0

I'm writing a C# GUI program that uses System.Management.Automation to execute powershell commands on an instance created at runtime, I need it to be a persistent powershell instance so I can send multiple commands and collect the output at runtime. This works as intended but i'm having some issues subscribing to the progress event. It only fires when I input faulty commands and writes that the progress is -1 percent complete.

When I input correct commands it doesn't fire at all. The error and output events work properly so i'm not sure what's going wrong.

I found two others having similar problems but their solutions didn't work for me, I linked them down below. Here's the code i'm using unsucessfully so far.

 public class CodeHandler {
   public static PowerShell psInstance;

   public void init() {
     //Create powershell instance
     psInstance = PowerShell.Create();
   }

   public async Task < string > ExecutePowershellCommand(string script) {
     psInstance.AddScript(script);
     psInstance.AddCommand("Out-String");

     PSDataCollection < PSObject > outputCollection = new PSDataCollection < PSObject > ();
     outputCollection.DataAdded += outputCollection_DataAdded;

     //The Part I Can't Get To Work
     psInstance.Streams.Progress.DataAdded += (sender, eventargs) => {
       PSDataCollection < ProgressRecord > progressRecords = (PSDataCollection < ProgressRecord > ) sender;
       Console.WriteLine("!Progress is {0} percent complete", progressRecords[eventargs.Index].PercentComplete);
     };

     psInstance.Streams.Error.DataAdded += Error_DataAdded;

     IAsyncResult result = psInstance.BeginInvoke < PSObject, PSObject > (null, outputCollection);

     while (!result.IsCompleted) {
       Console.WriteLine("Waiting for pipeline to finish...");
       await Task.Delay(100);
     }

     PSInvocationState state = psInstance.InvocationStateInfo.State;
     Console.WriteLine("Execution has stopped. The pipeline state: " + state);
     if (state != PSInvocationState.Completed)
       return string.Empty;

     StringBuilder stringBuilder = new StringBuilder();
     foreach(PSObject outputItem in outputCollection) {
       stringBuilder.AppendLine(outputItem.BaseObject.ToString());
       Console.WriteLine(outputItem.BaseObject.ToString());
     }

     return stringBuilder.ToString();
   }

 }

References:

Getting Write-Progress -PercentComplete status from within C#

Reading Powershell Progress Bar Output in C#

3
  • Where is the script? Commented Feb 14, 2021 at 15:41
  • What? It's posted in the question where there's a comment saying this is what I can't get to work Commented Feb 14, 2021 at 21:43
  • "It only fires when I input faulty commands and writes that the progress is -1 percent complete." - do you have an example of a "faulty command" and a "correct command"? If you try to invoke a command that doesn't emit to the Progress stream, then the behavior you describe is expected Commented Feb 14, 2021 at 22:41

1 Answer 1

1

Add psInstance.EndInvoke(result); as shown below:

                       ...
 IAsyncResult result = psInstance.BeginInvoke < PSObject, PSObject > (null, outputCollection);

 while (!result.IsCompleted) {
   Console.WriteLine("Waiting for pipeline to finish...");
   await Task.Delay(100);
 }

 psInstance.EndInvoke(result);

                       ...

Your script needs to use Write-Progress

Example script

# Use Get-Command to get list of commands and store them in the $cmds variable.
$cmds = Get-Command

# Pipe the events to the ForEach-Object cmdlet.
$cmds  | ForEach-Object -Begin {
    # In the Begin block, use Clear-Host to clear the screen.
    Clear-Host

    # Set the $i counter variable to zero.
    $i = 0

    # Set the $out variable to a empty string.
    $out = ""
} -Process {
    # get name
     # Append to the out variable.
     # $out=$out + $_

     write-output ($_.Name + " " + $_.Version) 

    # Increment the $i counter variable which is used to create the progress bar.
    $i = $i+1

    # Use Write-Progress to output a progress bar.
    # The Activity and Status parameters create the first and second lines of the progress bar heading, respectively.
    Write-Progress -Activity "Searching Commands" -Status "Progress:" -PercentComplete ($i/$cmds.count*100)
} -End {
    # Display using the out variable.
    # $out
}
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.