Home > Net >  Execute a continuously running PowerShell command and get result into form
Execute a continuously running PowerShell command and get result into form

Time:12-19

I had a command (actually a DAPR command :-) ) that run in PowerShell and continuously return results. I know how to connect to the PowerShell terminal and get a result, but my problem is that my command continuously returns the result and I need to capture this result to a Form.

using (PowerShell powerShell = PowerShell.Create())
        {
            powerShell.AddScript("ping 172.21.1.25 -t");
            powerShell.AddCommand("Out-String");
            Collection<PSObject> PSOutput = powerShell.Invoke();
            StringBuilder stringBuilder = new StringBuilder();
            foreach (PSObject pSObject in PSOutput)
            {
                stringBuilder.AppendLine(pSObject.ToString());
                
            }
            return stringBuilder.ToString();
        }

CodePudding user response:

You don't need to wait for a pipeline to return - you can start consuming output while it's still running!

You just need to make a few changes:

  • Add the -Stream switch parameter to Out-String (or drop Out-String completely)
  • Create a PSDataCollection<string> instance through which we can collect output
  • Invoke the pipeline asynchronously, with PowerShell.BeginInvoke<TInput, TOutput>()
void PingForever()
{
    using (var powerShell = PowerShell.Create())
    {
        // prepare commands - notice we use `Out-String -Stream` to avoid "backing up" the pipeline
        powerShell.AddScript("ping 8.8.8.8 -t");
        powerShell.AddCommand("Out-String").AddParameter("Stream", true);

        // now prepare a collection for the output, register event handler
        var output = new PSDataCollection<string>();
        output.DataAdded  = new EventHandler<DataAddedEventArgs>(ProcessOutput);

        // invoke the command asynchronously - we'll be relying on the event handler to process the output instead of collecting it here
        var asyncToken = powerShell.BeginInvoke<object,string>(null, output);

        if(asyncToken.AsyncWaitHandle.WaitOne()){
            if(powerShell.HadErrors){
                foreach(var errorRecord in powerShell.Streams.Error){
                    // inspect errors here
                    // alternatively: register an event handler for `powerShell.Streams.Error.DataAdded` event
                }
            }

            // end invocation without collecting output (event handler has already taken care of that)
            powerShell.EndInvoke(asyncToken);
        }
    }
}

void ProcessOutput(object? sender, DataAddedEventArgs eventArgs)
{
    var collection = sender as PSDataCollection<string>;
    if(null != collection){
        var outputItem = collection[eventArgs.Index];

        // Here's where you'd update the form with the new output item
        Console.WriteLine("Got some output: '{0}'", outputItem);
    }
}
  • Related