PowerShellからプログラムを実行し、終了を待ってから、ExitCodeにアクセスしようとしていますが、あまり運がありません。バックグラウンドで実行するには処理が必要なので、-Wait
を Start-Process
と一緒に使用したくありません。
簡単なテストスクリプトを次に示します。
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
このスクリプトを実行すると、 Notepad が開始されます。これを手動で閉じた後、終了コードが出力され、-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プロパティにアクセスできますか?
あなたにできる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
ここで覚えておくべきことが2つあります。 1つは-PassThru
引数を追加することで、2つは-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
なしで実行すると、何も出力されません。
同じ答えがここにあります:PowerShellでWindowsインストーラーを実行して成功/失敗値を取得する方法
上記の最後の提案を試している間に、私はさらに簡単な解決策を発見しました。プロセスハンドルをキャッシュするだけでした。それをするとすぐに、$ process.ExitCodeは正しく機能しました。プロセスハンドルをキャッシュしなかった場合、$ process.ExitCodeはnullでした。
例:
$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)"
}
「-Wait」オプションは、プロセスが終了したにもかかわらず、ブロックされているように見えました。
私はエイドリアンのソリューションを試してみましたが、うまくいきました。しかし、プロセスハンドルを取得する副作用に依存する代わりに、 Wait-Process を使用しました。
そう:
$proc = Start-Process $msbuild -PassThru
Wait-Process -InputObject $proc
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にリダイレクトされた出力/エラーストリームの管理を任せることができますが、System.Diagnostics.Process.Start()を直接使用することはできません。