使用Start-Process和WaitForExit而不是-Wait获取ExitCode

我试图从PowerShell运行一个程序,等待退出,然后访问ExitCode,但没有太多的运气。 我不想用-Wait和Start-Process,因为我需要在后台进行一些处理。

这是一个简化的testing脚本:

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 

运行这个脚本会导致记事本启动。 手动closures后,退出代码将被打印,并且将会重新开始,而不使用-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属性?

你可以做的两件事情我认为…

  1. 手动创buildSystem.Diagnostics.Process对象并绕过Start-Process
  2. 在后台作业中运行可执行文件(仅适用于非交互式进程!)

你可以这样做:

 $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 

这里有两件事要记住。 一个是添加-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运行它,它将不会打印任何东西。

同样的答案在这里: https : //stackoverflow.com/a/7109778/17822

在尝试上面的最后一个build议的时候,我发现了一个更简单的解决scheme。 我只需要caching进程句柄。 只要我这样做,$ process.ExitCode工作正常。 如果我没有caching进程句柄,$ process.ExitCode为null。

例:

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

或尝试添加此…

 $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负责pipe理redirect的输出/错误stream,而不能直接使用System.Diagnostics.Process.Start()。

即使我的stream程已经完成,“等待”选项似乎阻止了我。

我试过阿德里安的解决scheme,它的工作原理。 但是我使用了Wait-Process而不是依靠检索进程句柄的副作用。

所以:

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