Подтвердить что ты не робот

Получение ExitCode с использованием Start-Process и WaitForExit вместо -Wait

Я пытаюсь запустить программу из PowerShell, дождаться выхода, а затем получить доступ к ExitCode, но не имея большой удачи. Я не хочу использовать -Wait с Start-Process, так как мне нужна некоторая обработка для продолжения в фоновом режиме.

Здесь упрощенный тест script:

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

Запуск этого script приведет к запуску блокнота. После того, как это будет закрыто вручную, код выхода будет напечатан, и он начнется снова, не используя -wait. При выходе из него не появляется ExitCode:

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: 

Мне нужно иметь возможность выполнять дополнительную обработку между запуском программы и ожиданием ее выхода, поэтому я не могу использовать -Wait. Любая идея, как я могу это сделать и все еще иметь доступ к свойству .ExitCode из этого процесса?

4b9b3361

Ответ 1

Две вещи, которые вы могли бы сделать, я думаю...

  • Создайте объект System.Diagnostics.Process вручную и обходите Start-Process
  • Запустите исполняемый файл в фоновом задании (только для неинтерактивных процессов!)

Здесь вы также можете:

$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

ИЛИ

Start-Job -Name DoSomething -ScriptBlock {
    & ping.exe somehost
    Write-Output $LASTEXITCODE
}
#Do other stuff here
Get-Job -Name DoSomething | Wait-Job | Receive-Job

Ответ 2

Здесь есть две вещи. Один из них - добавить аргумент -PassThru, а два - добавить аргумент -Wait. Вам нужно добавить аргумент wait из-за этого дефекта 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.

После этого объект процесса передается обратно, и вы можете посмотреть свойство ExitCode этого объекта. Вот пример:

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

# this will print 1

Если вы запустите его без -PassThru или -Wait, он ничего не распечатает.

Тот же ответ здесь: fooobar.com/questions/143171/...

Ответ 3

Пробовав последнее предложение выше, я обнаружил еще более простое решение. Все, что мне нужно было сделать, - кэшировать дескриптор процесса. Как только я это сделал, процесс process.ExitCode работал правильно. Если я не кэшировал дескриптор процесса, $process.ExitCode был пустым.

Пример:

$proc = Start-Process $msbuild -PassThru
$handle = $proc.Handle # cache proc.Handle http://stackoverflow.com/a/23797762/1479211
$proc.WaitForExit();

if ($proc.ExitCode -ne 0) {
    Write-Warning "$_ exited with status code $($proc.ExitCode)"
}

Ответ 4

Или попробуйте добавить это...

$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)

Используя этот код, вы все же можете позволить PowerShell заботиться об управлении перенаправленными потоками вывода/ошибок, которые вы не можете сделать напрямую с помощью System.Diagnostics.Process.Start().

Ответ 5

Опция '-Wait', казалось, блокировала меня, хотя мой процесс завершился.

Я попробовал решение Adrian, и он работает. Но я использовал Wait-Process вместо того, чтобы полагаться на побочный эффект извлечения дескриптора процесса.

Итак:

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

if ($proc.ExitCode -ne 0) {
    Write-Warning "$_ exited with status code $($proc.ExitCode)"
}