16


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!

2 Answers 2

25

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.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks! But the method Add() returns void. I guess that you need to use a Command object and add a the parameter to it and pass it to the method Add. You are talking about two ways to do it programmatically, what is the second way?
I also found out that if you get "AuthorizationManager check failed" exception when trying to import your module, make sure sure your .psm1 file is saved in UTF8 and not in ASCII.
@x0n Oops.. The link is dead (?)
blog upgrade broke links - sigh.
|
0

The simplest way that you can do this is by using AddScript() method. You can do:

pipeline.AddScript("Import-Module moduleName").Invoke();

If you want to add another import in the same line

pipeline.AddScript("Import-Module moduleName \n Import-Module moduleName2").Invoke();

Its not mandatory to .Invoke() right ofter you add the script to the pipeline, you can add more scripts and invoke later.

pipeline.AddScript("Import-Module moduleName");
pipeline.AddCommand("pwd");
pipeline.Invoke();

For more information visit Microsoft Official website

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.