'Get Powershell command's output when invoked through code
I have written a piece of code (in C#) to execute a Powershell script (specifically Azure PowerShell) using System.Management.Automation. The powershell script basically uploads a vhd in a container on Azure, which shows the upload progress and time elapsed etc when command is manually entered through azure Powershell. Through code everything works fine but i want to get the result/output of a command (i.e. upload progress, time elapsed), during command execution (i.e. pipeline.invoke();) here is the code:
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();
RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
Pipeline pipeline = runspace.CreatePipeline();
Command myCommand = new Command(scriptPath);
foreach (var argument in arguments)
{
myCommand.Parameters.Add(new CommandParameter(argument.Key, argument.Value));
}
pipeline.Commands.Add(myCommand);
var results = pipeline.Invoke(); // i want to get results here (i.e. during command execution)
foreach (var psObject in results)
{
System.Diagnostics.Debug.Write(psObject.BaseObject.ToString());
}
Please guide if it is possible to retrieve live output from Powershell.
Solution 1:[1]
Unless you're targeting PowerShell 1.0, there's no need to set up your runspace and pipeline manually, create an instance of the PowerShell class instead:
PowerShell psinstance = PowerShell.Create();
psinstance.AddScript(scriptPath);
var results = psinstance.Invoke();
Way simpler.
Now, the PowerShell class exposes the various non-standard output streams (Verbose, Debug, Error etc.) - including the Progress Stream - via the Streams property so you can subscribe to it, like so:
psinstance.Streams.Progress.DataAdded += myProgressEventHandler;
And then in your event handler:
static void myProgressEventHandler(object sender, DataAddedEventArgs e)
{
ProgressRecord newRecord = ((PSDataCollection<ProgressRecord>)sender)[e.Index];
if (newRecord.PercentComplete != -1)
{
Console.Clear();
Console.WriteLine("Progress updated: {0}", newRecord.PercentComplete);
}
}
As an example, here is that event handler shown above in action, while running a sample script that writes progress information (sample script posted below) in a simple console application:
Test-Progress.ps1
function Test-Progress
{
param()
Write-Progress -Activity 'Testing progress' -Status 'Starting' -PercentComplete 0
Start-Sleep -Milliseconds 600
1..10 |ForEach-Object{
Write-Progress -Activity "Testing progress" -Status 'Progressing' -PercentComplete $(5 + 6.87 * $_)
Start-Sleep -Milliseconds 400
}
Write-Progress -Activity 'Testing progress' -Status 'Ending' -PercentComplete 99
Start-Sleep -Seconds 2
Write-Progress -Activity 'Testing progress' -Status 'Done' -Completed
}
Test-Progress
Solution 2:[2]
It may be a little late, but still.
@Mathias R. Jessen answer works great, but for cases with the output of ordinary strings (without Write-Progress and so on):
Initialize the collection first
PSDataCollection<PSObject> output = new PSDataCollection<PSObject>();
output.DataAdded += Output_DataAdded;
Perform
var res = psinstance.BeginInvoke<PSObject, PSObject>(null, output);
res.AsyncWaitHandle.WaitOne();
Get the result real-time
private static void Output_DataAdded(object sender, DataAddedEventArgs e)
{
PSObject newRecord = ((PSDataCollection<PSObject>)sender)[e.Index];
Console.WriteLine(newRecord);
}
Tested on Get-Process PS command.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Mathias R. Jessen |
| Solution 2 | mysp4ce |

