Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capturing PowerShell output in C# after execution of each pipeline command

Tags:

c#

powershell

wpf

I am implementing a WPF application that executes a PowerShell script for each key/value pair given in a dictionary, using the pair as script arguments. I store each run of the script as a new command in the pipeline. However, this causes me to only get output back from the last command that was run, when I need the output after each run of the script. I have considered creating a new pipeline each time the script is executed, but I need to know when all executions of the script are done. Here's the relevant code to help explain my problem:

private void executePowerShellScript(String scriptText, Dictionary<String, String> args)
{
     // Create the PowerShell object.
     PowerShell powerShell = PowerShell.Create();

     // If arguments were given, add the script and its arguments.
     if (args != null)
     {
          foreach (KeyValuePair<String, String> arg in args)
          {
               powerShell.AddScript(scriptText);
               powerShell.AddArgument(arg.Key);
               powerShell.AddArgument(arg.Value);
          }
     }

     // Otherwise, just add the script.
     else
          powerShell.AddScript(scriptText);

     // Add the event handlers.
     PSDataCollection<PSObject> output = new PSDataCollection<PSObject>();
     output.DataAdded += new EventHandler<DataAddedEventArgs>(Output_DataAdded);
     powerShell.InvocationStateChanged +=
          new EventHandler<PSInvocationStateChangedEventArgs>(Powershell_InvocationStateChanged);

     // Invoke the pipeline asynchronously.
     IAsyncResult asyncResult = powerShell.BeginInvoke<PSObject, PSObject>(null, output);
}

private void Output_DataAdded(object sender, DataAddedEventArgs e)
{
     PSDataCollection<PSObject> myp = (PSDataCollection<PSObject>)sender;

     Collection<PSObject> results = myp.ReadAll();
     foreach (PSObject result in results)
     {
          Console.WriteLine(result.ToString());
     }
}

And then I use the following method to know when all executions of the script have been completed. Since I do this by checking that the invocation state of the pipeline is completed, I can't make a new pipeline for each execution of the script:

private void Powershell_InvocationStateChanged(object sender, PSInvocationStateChangedEventArgs e)
{
     switch (e.InvocationStateInfo.State)
     {
          case PSInvocationState.Completed:
               ActiveCommand.OnCommandSucceeded(new EventArgs());
               break;
          case PSInvocationState.Failed:
               OnErrorOccurred(new ErrorEventArgs((sender as PowerShell).Streams.Error.ReadAll()));
               break;
     }
     Console.WriteLine("PowerShell object state changed: state: {0}\n", e.InvocationStateInfo.State);
}

So, to get to my question:

1) Can I force the pipeline to produce output after each command that it executes? Or,
2) If I were to create a new pipeline each time I run the command, is there another way that I could check that all executions of the script have been completed?

There are few examples using the actual PowerShell class in C# and I know next to nothing about threading, so any help would be greatly appreciated.

like image 404
caseklim Avatar asked Oct 08 '22 09:10

caseklim


1 Answers

I feel silly for answering my own question, but all I did was move the loop functionality from my C# code into my script and that worked. So now I pass all the keys and values at once as array parameters and only have the one command in the pipeline.

I would still be interested to know if it is possible to produce output after each command in the pipeline is executed, though.

like image 159
caseklim Avatar answered Oct 10 '22 00:10

caseklim