Obtener ExitCode usando Start-Process y WaitForExit en lugar de-Wait


Estoy tratando de ejecutar un programa desde PowerShell, esperar a la salida, a continuación, obtener acceso al código de salida, pero no tener mucha suerte. No quiero usar-Espera con Inicio-Proceso, ya que necesito algo de procesamiento para continuar en segundo plano.

Aquí hay un script de prueba simplificado:

cd "C:\Windows"

# ExitCode is available when using -Wait...
Write-Host "Starting Notepad with -Wait - return code will be available"
$process = (Start-Process -FilePath "notepad.exe" -PassThru -Wait)
Write-Host "Process finished with return code: " $process.ExitCode

# ExitCode is not available when waiting separately
Write-Host "Starting Notepad without -Wait - return code will NOT be available"
$process = (Start-Process -FilePath "notepad.exe" -PassThru)
$process.WaitForExit()
Write-Host "Process exit code should be here: " $process.ExitCode

Al ejecutar este script se iniciará el bloc de notas. Después de que esto se cierre manualmente, se imprimirá el código de salida y comenzará de nuevo, sin usar-wait. No se proporciona ningún código de salida cuando es salir:

Starting Notepad with -Wait - return code will be available
Process finished with return code:  0
Starting Notepad without -Wait - return code will NOT be available
Process exit code should be here: 

Necesito poder realizar un procesamiento adicional entre el inicio del programa y la espera de que salga, por lo que no puedo hacer uso de-Wait. Cualquier idea de cómo puedo hacer esto y todavía tener acceso a la .¿La propiedad ExitCode de este proceso?

Author: Richard, 2012-04-21

5 answers

Creo que hay dos cosas que podrías hacer...

  1. Crea el Sistema.Diagnostico.Process object manualmente y bypass Start-Process
  2. Ejecute el ejecutable en un trabajo en segundo plano (¡solo para procesos no interactivos!)

Aquí está cómo usted podría hacer cualquiera de los dos:

$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "notepad.exe"
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = ""
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
#Do Other Stuff Here....
$p.WaitForExit()
$p.ExitCode

O

Start-Job -Name DoSomething -ScriptBlock {
    & ping.exe somehost
    Write-Output $LASTEXITCODE
}
#Do other stuff here
Get-Job -Name DoSomething | Wait-Job | Receive-Job
 31
Author: Andy Arismendi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-21 19:32:19

Hay dos cosas para recordar aquí. Uno es agregar el argumento-PassThru y dos es agregar el argumento-Wait. Necesita agregar el argumento wait debido a este defecto http://connect.microsoft.com/PowerShell/feedback/details/520554/start-process-does-not-return-exitcode-property

-PassThru [<SwitchParameter>]
    Returns a process object for each process that the cmdlet started. By d
    efault, this cmdlet does not generate any output.

Una vez hecho esto, se devuelve un objeto process y puede ver la propiedad ExitCode de ese objeto. He aquí un ejemplo:

$process = start-process ping.exe -windowstyle Hidden -ArgumentList "-n 1 -w 127.0.0.1" -PassThru -Wait
$process.ExitCode

# this will print 1

Si lo ejecuta sin-PassThru o - Espera, no imprimirá nada.

La misma respuesta aquí: https://stackoverflow.com/a/7109778/17822

 69
Author: Daniel McQuiston,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:33

Mientras probaba la sugerencia final anterior, descubrí una solución aún más simple. Todo lo que tenía que hacer era almacenar en caché el controlador del proceso. Tan pronto como lo hice, process proceso.ExitCode funcionó correctamente. Si no guardaba en caché el controlador del proceso, process process.ExitCode era nula.

Ejemplo:

$proc = Start-Process $msbuild -PassThru
$handle = $proc.Handle # cache proc.Handle
$proc.WaitForExit();

if ($proc.ExitCode -ne 0) {
    Write-Warning "$_ exited with status code $($proc.ExitCode)"
}
 27
Author: Adrian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-27 17:33:14

La opción '-Wait' parecía bloquearse para mí a pesar de que mi proceso había terminado.

Probé la solución de Adrian y funciona. Pero usé Wait-Process en lugar de confiar en un efecto secundario de recuperar el controlador de proceso.

Así que:

$proc = Start-Process $msbuild -PassThru
Wait-Process -InputObject $proc

if ($proc.ExitCode -ne 0) {
    Write-Warning "$_ exited with status code $($proc.ExitCode)"
}
 6
Author: blt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-02 01:56:30

O intente agregar esto...

$code = @"
[DllImport("kernel32.dll")]
public static extern int GetExitCodeProcess(IntPtr hProcess, out Int32 exitcode);
"@
$type = Add-Type -MemberDefinition $code -Name "Win32" -Namespace Win32 -PassThru
[Int32]$exitCode = 0
$type::GetExitCodeProcess($process.Handle, [ref]$exitCode)

Al usar este código, PowerShell puede seguir encargándose de administrar flujos de salida/error redirigidos, lo que no puede hacer con el Sistema.Diagnostico.Proceso.Start() directamente.

 3
Author: Greg Vogel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-14 01:12:49