Author Posts

July 18, 2014 at 8:23 am

I know the C# element of this is OT here but I am at a loss and am hopeful someone with more powershell experience than I may know something.

I have tried several ways to loop through some code with powershell invoked from with C# but each invocation runs painfully slow and degrades very quickly to almost a halt.
If I create and dispose of the System.Management.Automation PowerShell instance for each iteration the speed maintains its pace for slightly longer but degrades as well.
Ultimately the speed of a single invocation is dreadful.

My use case is calling a function and sending in a some strings and dictionaries of lists as parameters. I need to do this a few million times.
The C# app queries a database for input and writes back processed data. If not invoking powershell that process alone is extremely fast.

A thought would be to never leave the ps execution environment and expose some C# classes to the ps environment that yield input and consume output.
The loop would run within a single ps invocation. If possible, that class that provides data utilizes a generator, so I certainly would not want to consume its dataset before iterating as that would consume far too much memory. I could create some code that accepts this properly via a pipeline.

What are any thoughts from people who have been down this road?

Thanks!

July 18, 2014 at 8:26 am

We probably need to see what you've already attempted, but in general, PowerShell is very slow compared to C#. If performance is a concern, since you're in a C# app anyway, you may find that it's better to leave PowerShell out of the picture entirely.

July 18, 2014 at 9:18 am

Hi Dave,
I have basically moved the following into and out of the loop that iterates of the data set:

Collection<PSObject> results;
using (PowerShell powerShell = PowerShell.Create())
{
    // Source functions.
    powerShell.AddScript(PsScript);
    powerShell.Invoke();

    // Call function contained in sourced script above.
    powerShell.AddCommand("My-Function");
    powerShell.AddParameter("ParamA", varA);
    powerShell.AddParameter("ParamB", varB);
    powerShell.AddParameter("ParamC", varC);
    powerShell.AddParameter("ParamD", varD);

    results = powerShell.Invoke();
}

I'd love to remove the powershell but this is the premise of the program, it provides an easy to modify scriptable environment.
Its fundamental that for each usage of the compiled code, you have access to user defined functions.

Aside from the above, I have tried all sorts of appraoches using RunSpaces etc to no avail.

Thanks!

July 18, 2014 at 10:50 am

Well, that's the basics of how to execute PowerShell from within C#. However, if you're doing this millions of times, you may find that it's much faster to run the script once, keep an open runspace, and then run the function multiple times. That way you're not forcing PowerShell to parse and compile the script every time through the loop. Something along these lines:

using (var runspace = RunspaceFactory.CreateRunspace())
{
    using (var powerShell = PowerShell.Create())
    {
        powerShell.Runspace = runspace;
        powerShell.AddScript(PsScript);
        powerShell.Invoke();
    }

    foreach (var thingy in thingies)
    {
        using (var powerShell = PowerShell.Create())
        {
            powerShell.Runspace = runspace;

            powerShell.AddCommand("My-Function");
            powerShell.AddParameter("ParamA", varA);
            powerShell.AddParameter("ParamB", varB);
            powerShell.AddParameter("ParamC", varC);
            powerShell.AddParameter("ParamD", varD);
 
            var results = powerShell.Invoke();

            // Do whatever with results
        }
    }
}

(Note: I wrote this in Notepad, and haven't tested it. It probably doesn't work as-is.)

July 18, 2014 at 2:47 pm

Dave,
That actually made such a significant difference that the original approach may just be feasible.

Very much appreciated!