Powershell: Capturing standard out and error with Process object Powershell: Capturing standard out and error with Process object powershell powershell

Powershell: Capturing standard out and error with Process object


The docs on the RedirectStandardError property suggests that it is better to put the WaitForExit() call after the ReadToEnd() call. The following works correctly for me:

$psi = New-object System.Diagnostics.ProcessStartInfo $psi.CreateNoWindow = $true $psi.UseShellExecute = $false $psi.RedirectStandardOutput = $true $psi.RedirectStandardError = $true $psi.FileName = 'ipconfig.exe' $psi.Arguments = @("/a") $process = New-Object System.Diagnostics.Process $process.StartInfo = $psi [void]$process.Start()$output = $process.StandardOutput.ReadToEnd() $process.WaitForExit() $output


Small variation so that you can selectively print the output if needed. As in if your looking just for error or warning messages and by the way Keith you saved my bacon with your response...

$psi = New-object System.Diagnostics.ProcessStartInfo $psi.CreateNoWindow = $true $psi.UseShellExecute = $false $psi.RedirectStandardOutput = $true $psi.RedirectStandardError = $true $psi.FileName = 'robocopy' $psi.Arguments = @("$HomeDirectory $NewHomeDirectory /MIR /XF desktop.ini /XD VDI /R:0 /W:0 /s /v /np") $process = New-Object System.Diagnostics.Process $process.StartInfo = $psi [void]$process.Start()do{   $process.StandardOutput.ReadLine()}while (!$process.HasExited)


Here is a modification to paul's answer, hopefully it addresses the truncated output. i did a test using a failure and did not see truncation.

function Start-ProcessWithOutput{    param ([string]$Path,[string[]]$ArgumentList)    $Output = New-Object -TypeName System.Text.StringBuilder    $Error = New-Object -TypeName System.Text.StringBuilder    $psi = New-object System.Diagnostics.ProcessStartInfo     $psi.CreateNoWindow = $true     $psi.UseShellExecute = $false     $psi.RedirectStandardOutput = $true     $psi.RedirectStandardError = $true     $psi.FileName = $Path    if ($ArgumentList.Count -gt 0)    {        $psi.Arguments = $ArgumentList    }    $process = New-Object System.Diagnostics.Process     $process.StartInfo = $psi     [void]$process.Start()    do    {       if (!$process.StandardOutput.EndOfStream)       {           [void]$Output.AppendLine($process.StandardOutput.ReadLine())       }       if (!$process.StandardError.EndOfStream)       {           [void]$Error.AppendLine($process.StandardError.ReadLine())       }       Start-Sleep -Milliseconds 10    } while (!$process.HasExited)    #read remainder    while (!$process.StandardOutput.EndOfStream)    {        #write-verbose 'read remaining output'        [void]$Output.AppendLine($process.StandardOutput.ReadLine())    }    while (!$process.StandardError.EndOfStream)    {        #write-verbose 'read remaining error'        [void]$Error.AppendLine($process.StandardError.ReadLine())    }    return @{ExitCode = $process.ExitCode; Output = $Output.ToString(); Error = $Error.ToString(); ExitTime=$process.ExitTime}}$p = Start-ProcessWithOutput "C:\Program Files\7-Zip\7z.exe" -ArgumentList "x","-y","-oE:\PowershellModules",$NewModules.FullName -verbose$p.ExitCode$p.Output$p.Error

the 10ms sleep is to avoid spinning cpu when nothing to read.