Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell - How to Import-Module in a Runspace


I am trying to create a cmdlet in C#. The code looks something like this:

[Cmdlet(VerbsCommon.Get, "HeapSummary")]
public class Get_HeapSummary : Cmdlet
{
    protected override void ProcessRecord()
    {
        RunspaceConfiguration config = RunspaceConfiguration.Create();
        Runspace myRs = RunspaceFactory.CreateRunspace(config);
        myRs.Open();

        RunspaceInvoke scriptInvoker = new RunspaceInvoke(myRs);
        scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");

        Pipeline pipeline = myRs.CreatePipeline();
        pipeline.Commands.Add(@"Import-Module G:\PowerShell\PowerDbg.psm1");
        //...
        pipeline.Invoke();

        Collection<PSObject> psObjects = pipeline.Invoke();
        foreach (var psObject in psObjects)
        {
            WriteObject(psObject);
        }
    }
}

But trying to execute this CmdLet in PowerShell gives me this error: The term Import-Module is not recognized as the name of a cmdlet. The same command in PowerShell doesn't give me this error. If I execute 'Get-Command' instead, I can see that 'Invoke-Module' is listed as a CmdLet.

Is there a way to do an 'Import-Module' in a Runspace?

Thanks!

like image 843
Absolom Avatar asked Jun 07 '11 13:06

Absolom


1 Answers

There are two ways to import modules programmatically, but I'll address your method first. Your line pipeline.Commands.Add("...") should only be adding the command, not the command AND the parameter. The parameter is added separately:

# argument is a positional parameter
pipeline.Commands.Add("Import-Module");
var command = pipeline.Commands[0];
command.Parameters.Add("Name", @"G:\PowerShell\PowerDbg.psm1")

The above pipeline API is a bit clumsy to use and is informally deprecated for many uses although it's at the base of many of the higher level APIs. The best way to do this in powershell v2 or higher is by using the System.Management.Automation.PowerShell Type and its fluent API:

# if Create() is invoked, a runspace is created for you
var ps = PowerShell.Create(myRS);
ps.Commands.AddCommand("Import-Module").AddArgument(@"g:\...\PowerDbg.psm1")
ps.Invoke()

Another way when using the latter method is to preload modules using InitialSessionState, which avoids the need to seed the runspace explictly with Import-Module.

InitialSessionState initial = InitialSessionState.CreateDefault();
    initialSession.ImportPSModule(new[] { modulePathOrModuleName1, ... });
    Runspace runspace = RunspaceFactory.CreateRunspace(initial);
    runspace.Open();
    RunspaceInvoke invoker = new RunspaceInvoke(runspace);
    Collection<PSObject> results = invoker.Invoke("...");

Hope this helps.

like image 123
x0n Avatar answered Oct 25 '22 06:10

x0n