trycatch try erroraction catch powershell start-process

erroraction - powershell use try catch



Captura de error estándar y error con Start-Process (5)

¿Hay algún error en el comando de Start-Process Powershell al acceder a las propiedades StandardError y StandardOutput ?

Si ejecuto lo siguiente, no obtengo salida

$process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait $process.StandardOutput $process.StandardError

Pero si redirijo el resultado a un archivo, obtengo el resultado esperado

$process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait -RedirectStandardOutput stdout.txt -RedirectStandardError stderr.txt


Así es como Start-Process fue diseñado por alguna razón. Aquí hay una forma de obtenerlo sin enviarlo a archivo:

$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


IMPORTANTE:

Hemos estado usando la función proporcionada anteriormente por LPG. Sin embargo, esto contiene un error que puede encontrar al iniciar un proceso que genera una gran cantidad de resultados. Debido a esto, puede terminar con un interbloqueo al utilizar esta función. En su lugar, use la versión adaptada a continuación:

Function Execute-Command ($commandTitle, $commandPath, $commandArguments) { Try { $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = $commandPath $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $commandArguments $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null [pscustomobject]@{ commandTitle = $commandTitle stdout = $p.StandardOutput.ReadToEnd() stderr = $p.StandardError.ReadToEnd() ExitCode = $p.ExitCode } $p.WaitForExit() } Catch { exit } }

Se puede encontrar más información sobre este tema en MSDN :

Se puede producir una condición de interbloqueo si el proceso principal llama a p.WaitForExit antes de p.StandardError.ReadToEnd y el proceso secundario escribe suficiente texto para completar la secuencia redirigida. El proceso principal esperaría indefinidamente para que el proceso secundario salga. El proceso secundario esperaría indefinidamente para que el padre lea de la secuencia StandardError completa.

EDITAR: Agregó un corsé faltante al final del bloque Try.


Realmente tuve problemas con los ejemplos anteriores de @Andy Arismendi y @LPG. Siempre deberías usar:

$stdout = $p.StandardOutput.ReadToEnd()

antes de llamar

$p.WaitForExit()

El ejemplo completo es:

$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 $stdout = $p.StandardOutput.ReadToEnd() $stderr = $p.StandardError.ReadToEnd() $p.WaitForExit() Write-Host "stdout: $stdout" Write-Host "stderr: $stderr" Write-Host "exit code: " + $p.ExitCode


También tuve este problema y terminé usando el código Andys para crear una función para limpiar cosas cuando se necesitan ejecutar varios comandos, devolverá stderr, stdout y los códigos de salida como objetos. Una cosa para tener en cuenta que la función no aceptará. / En la ruta, se deben usar rutas completas.

Function Execute-Command ($commandTitle, $commandPath, $commandArguments) { $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = $commandPath $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $commandArguments $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() [pscustomobject]@{ commandTitle = $commandTitle stdout = $p.StandardOutput.ReadToEnd() stderr = $p.StandardError.ReadToEnd() ExitCode = $p.ExitCode } }

he aquí cómo usarlo

$DisableACMonitorTimeOut = Execute-Command -commandTitle "Disable Monitor Timeout" -commandPath "C:/Windows/System32/powercfg.exe" -commandArguments " -x monitor-timeout-ac 0"


en el código proporcionado en la pregunta, creo que leer la propiedad ExitCode de la variable de inicio debería funcionar.

$process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait $process.ExitCode

Tenga en cuenta que (como en su ejemplo) necesita agregar los parámetros -PassThru y -Wait (esto me sorprendió por un tiempo)