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

Intento ejecutar un progtwig desde PowerShell, esperar la salida y acceder al código de salida, pero sin mucha suerte. No quiero usar -Espere con Start-Process, ya que necesito un 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 cerrar esto manualmente, se imprimirá el código de salida y se reiniciará sin usar -wait. No se proporciona ningún código de salida cuando esto se abandona:

 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 progtwig y esperar a que se cierre, por lo que no puedo usar -Espera. ¿Alguna idea de cómo puedo hacer esto y aún tener acceso a la propiedad .ExitCode de este proceso?

Dos cosas que podrías hacer, creo …

  1. Crear el objeto System.Diagnostics.Process manualmente y eludir el proceso de inicio
  2. Ejecute el ejecutable en un trabajo en segundo plano (¡solo para procesos no interactivos!)

Así es como podría hacer:

 $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 

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

 -PassThru [] 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 pasa un objeto de proceso y se puede ver la propiedad ExitCode de ese objeto. Aquí hay 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 -Wait, no imprimirá nada.

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

Al probar la sugerencia final anterior, descubrí una solución aún más simple. Todo lo que tuve que hacer fue almacenar en caché el identificador del proceso. Tan pronto como lo hice, $ process.ExitCode funcionó correctamente. Si no almacenaba en caché el identificador del proceso, $ process.ExitCode era nulo.

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)" } 

La opción ‘-Esperar’ pareció bloquearme a pesar de que mi proceso había terminado.

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

Asi que:

 $proc = Start-Process $msbuild -PassThru Wait-Process -InputObject $proc if ($proc.ExitCode -ne 0) { Write-Warning "$_ exited with status code $($proc.ExitCode)" } 

O intenta 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, aún puede dejar que PowerShell se encargue de administrar flujos de salida / error redirigidos, lo que no puede hacer usando System.Diagnostics.Process.Start () directamente.