Powershell: Capture el progtwig stdout y stderr para separar las variables

¿Es posible redirigir stdout de un progtwig externo a una variable y stderr de progtwigs externos a otra variable en una ejecución?

por ejemplo:

$global:ERRORS = @(); $global:PROGERR = @(); function test(){ # Can we redirect errors to $PROGERR here, leaving stdout for $OUTPUT? $OUTPUT = (& myprogram.exe 'argv[0]', 'argv[1]'); if ( $OUTPUT | select-string -Pattern "foo" ) { # do stuff } else { $global:ERRORS += "test(): oh noes! 'foo' missing!"; } } test; if ( @($global:ERRORS).length -gt 0 ) { Write-Host "Script specific error occurred"; foreach ( $err in $global:ERRORS ) { $host.ui.WriteErrorLine("err: $err"); } } else { Write-Host "Script ran fine!"; } if ( @($global:PROGERR).length -gt 0 ) { # do stuff } else { Write-Host "External program ran fine!"; } 

Un ejemplo aburrido, sin embargo, me pregunto si eso es posible.

La forma más sencilla de hacerlo es usar un archivo para la salida de stderr, por ejemplo:

 $output = & myprogram.exe 'argv[0]', 'argv[1]' 2>stderr.txt $err = get-content stderr.txt if ($LastExitCode -ne 0) { ... handle error ... } 

También usaría $ LastExitCode para verificar si hay errores de las extensiones nativas de la consola.

Una opción es combinar la salida de stdout y stderr en una sola transmisión, luego filtrar.

Los datos de stdout serán cadenas, mientras que stderr produce objetos System.Management.Automation.ErrorRecord.

 $allOutput = & myprogram.exe 2>&1 $stderr = $allOutput | ?{ $_ -is [System.Management.Automation.ErrorRecord] } $stdout = $allOutput | ?{ $_ -isnot [System.Management.Automation.ErrorRecord] } 

Debería utilizar las opciones Start-Process con -RedirectStandardError -RedirectStandardOutput. Esta otra publicación tiene un gran ejemplo de cómo hacer esto (tomada de la siguiente publicación):

 $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "ping.exe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = "localhost" $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() $stdout = $p.StandardOutput.ReadToEnd() $stderr = $p.StandardError.ReadToEnd() Write-Host "stdout: $stdout" Write-Host "stderr: $stderr" Write-Host "exit code: " + $p.ExitCode 

Esta es también una alternativa que he usado para redirigir stdout y stderr de una línea de comando mientras todavía muestra el resultado durante la ejecución de powershell:

 $command = "myexecutable.exe my command line params" Invoke-Expression $command -OutVariable output -ErrorVariable errors Write-Host "STDOUT" Write-Host $output Write-Host "STDERR" Write-Host $errors 

Otra posibilidad más para complementar lo que ya se dio.

Tenga en cuenta que esto no siempre funciona dependiendo de cómo se invoca el script, he tenido problemas con -OutVariable y -ErrorVariable cuando se invoca desde una línea de comandos estándar en lugar de una línea de comandos de PowerShell como esta:

 PowerShell -File ".\FileName.ps1" 

Una alternativa que parece funcionar en la mayoría de las circunstancias es esta:

 $stdOutAndError = Invoke-Expression "$command 2>&1" 

Desafortunadamente, perderá salida a la línea de comando durante la ejecución del script y tendrá que Write-Host $stdOutAndError después de que el comando regrese para hacerlo “parte del registro” (como una parte de un archivo por lotes de Jenkins). Y lamentablemente no separa stdout y stderr.