0

I am trying to work out an efficient way of calling a Powershell cmdlet for 20-30 files asynchronously. Although the below code is working, the Import-Module step is run for every file which is processed. Unfortunately this Module takes between 3 or 4 seconds to import.

Searching on the web I can find references to RunspacePools & InitialSessionState, but have had issues trying to create a PSHost object which is required in the CreateRunspacePool overload.

Any help would be appreciated.

Thanks

Gavin

.

.

Code sample from my application:

I am using a Parallel ForEach to distribute the files between threads.

Parallel.ForEach(files, (currentFile) => 
{
    ProcessFile(currentfile);
});



private void ProcessFile(string filepath)
{
    // 
    // Some non powershell related code removed for simplicity
    //


    // Start PS Session, Import-Module and Process file
    using (PowerShell PowerShellInstance = PowerShell.Create())
    {
        PowerShellInstance.AddScript("param($path) Import-Module MyModule; Process-File -Path $path");
        PowerShellInstance.AddParameter("path", filepath);
        PowerShellInstance.Invoke();
    }
}
6
  • Possible duplicate of PowerShell - How to Import-Module in a Runspace Commented Jun 11, 2016 at 22:48
  • Try using the code from here to load a Module using the InitialSessionState for the RunSpacePools. Commented Jun 12, 2016 at 0:39
  • Thanks, the answer on the post still imports the module once per item in the foreach loop. Although there is a link to a blog which describes the information i needed. So thanks for pointing me in the right direction. Commented Jun 12, 2016 at 11:49
  • @user4317867 - Thanks for the link, but this shows PowerShell code which also uses CreateRunspacePool($minRunspaces, $maxRunspaces, $iss, $Host) and i still dont know how to create a $Host variable to apply. Commented Jun 12, 2016 at 11:53
  • It seems $Host is TypeName: System.Management.Automation.Internal.Host.InternalHost that's created when the Powershell console is opened. Are you looking to create a pool of RunSpaces that all have the desired module loaded? Commented Jun 12, 2016 at 19:48

1 Answer 1

0

As it has already been explained in the comments, this won't work with PSJobs because objects are serialized and the jobs themselves run in a separate process.

What you can do is create a RunspacePool with an InitialSessionState that has the module imported:

private RunspacePool rsPool;

public void ProcessFiles(string[] files)
{
    // Set up InitialSessionState 
    InitialSessionState initState = InitialSessionState.Create();
    initState.ImportPSModule(new string[] { "MyModule" });
    initState.LanguageMode = PSLanguageMode.FullLanguage;

    // Set up the RunspacePool
    rsPool = RunspaceFactory.CreateRunspacePool(initialSessionState: initState);
    rsPool.SetMinRunspaces(1);
    rsPool.SetMaxRunspaces(8);
    rsPool.Open();

    // Run ForEach()
    Parallel.ForEach(files, ProcessFile);
}

private void ProcessFile(string filepath)
{
    // Start PS Session and Process file
    using (PowerShell PowerShellInstance = PowerShell.Create())
    {
        // Assign the instance to the RunspacePool
        PowerShellInstance.RunspacePool = rsPool;

        // Run your script, MyModule has already been imported
        PowerShellInstance.AddScript("param($path) Process-File @PSBoundParameters").AddParameter("path", filepath);
        PowerShellInstance.Invoke();
    }
}
Sign up to request clarification or add additional context in comments.

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.