Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell, stream Process output and errors while running external process

I am using a PowerShell script to execute a console application and I am trying to redirect the standard output and the standard error from there. The code I am using is the following:

$ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo 
$ProcessInfo.FileName = "myExe.exe"
$ProcessInfo.Arguments = "bla bla bla"
$ProcessInfo.RedirectStandardError = $true 
$ProcessInfo.RedirectStandardOutput = $true 
$ProcessInfo.UseShellExecute = $false 
$Process = New-Object System.Diagnostics.Process 
$Process.StartInfo = $ProcessInfo 

$Process.Start() | Out-Null 
$output = $Process.StandardOutput.ReadToEnd() 
$errors = $Process.StandardError.ReadToEnd()
$Process.WaitForExit() 
$output 
$errors 

return $Process.ExitCode

So far so good, if I have an error I can see it redirected into my PowerShell console and if I have output it is also redirected. The issue is that this process takes 10 minutes and in the meantime we have no clue of what is going on.

Is there any way in PowerShell I can stream the content of the Output and the Error while the process is running? In pure .NET we can subscribe to events of the Process class, can I do the same in PowerShell?

like image 345
Raffaeu Avatar asked Apr 23 '14 08:04

Raffaeu


1 Answers

Is there any way in PowerShell I can stream the content of the Output and the Error while the process is running? In pure .NET we can subscribe to events of the Process class, can I do the same in PowerShell?

Sure you can! What you need is an Object Events:

An object event is a .Net object that not only has the usual Properties and Methods in the object, but also has another member called Event, which you can register a subscription on using Register-ObjectEvent

Here is slightly modified example from the the PowerShell forums. It will output data from the ping command asynchronously (at least from the script point of view):

# Setup stdin\stdout redirection
$StartInfo = New-Object System.Diagnostics.ProcessStartInfo -Property @{
                FileName = 'ping.exe'
                Arguments = '-t 127.0.0.1'
                UseShellExecute = $false
                RedirectStandardOutput = $true
                RedirectStandardError = $true
            }

# Create new process
$Process = New-Object System.Diagnostics.Process

# Assign previously created StartInfo properties
$Process.StartInfo = $StartInfo

# Register Object Events for stdin\stdout reading
$OutEvent = Register-ObjectEvent -Action {
    Write-Host $Event.SourceEventArgs.Data
} -InputObject $Process -EventName OutputDataReceived

$ErrEvent = Register-ObjectEvent -Action {
    Write-Host $Event.SourceEventArgs.Data
} -InputObject $Process -EventName ErrorDataReceived

# Start process
[void]$Process.Start()

# Begin reading stdin\stdout
$Process.BeginOutputReadLine()
$Process.BeginErrorReadLine()

# Do something else while events are firing
do
{
    Write-Host 'Still alive!' -ForegroundColor Green
    Start-Sleep -Seconds 1
}
while (!$Process.HasExited)

# Unregister events
$OutEvent.Name, $ErrEvent.Name |
    ForEach-Object {Unregister-Event -SourceIdentifier $_}
like image 135
beatcracker Avatar answered Oct 09 '22 03:10

beatcracker