0

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();
        }
0

1 Answer 1

6

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);
    }
}
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.