87

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

このスクリプトを実行すると、メモ帳が起動します。これを手動で閉じた後、終了コードが出力され、を使用せずに再開され-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プロパティにアクセスできるようにするにはどうすればよいですか?

4

6 に答える 6

125

ここで覚えておくべきことが2つあります。1つは-PassThru引数を追加することで、2つは引数を追加する-Waitことです。この欠陥のため、待機引数を追加する必要があります。

-PassThru [<SwitchParameter>]
    Returns a process object for each process that the cmdlet started. By default,
    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出力されません。

同じ答えがここにあります:Windowsインストーラーを実行してPowerShellで成功/失敗の値を取得するにはどうすればよいですか?

上記の「欠陥レポート」リンクに記載されている回避策があることにも注意してください。これは次のとおりです。

# Start the process with the -PassThru command to be able to access it later
$process = Start-Process 'ping.exe' -WindowStyle Hidden -ArgumentList '-n 1 -w 127.0.0.1' -PassThru

# This will print out False/True depending on if the process has ended yet or not
# Needs to be called for the command below to work correctly
$process.HasExited

# This will print out the actual exit code of the process
$process.GetType().GetField('exitCode', 'NonPublic, Instance').GetValue($process)
于 2013-04-15T14:51:05.090 に答える
59

上記の最後の提案を試している間に、私はさらに簡単な解決策を発見しました。私がしなければならなかったのは、プロセスハンドルをキャッシュすることだけでした。それを行うとすぐに、$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)"
}
于 2014-05-22T04:20:34.500 に答える
51

あなたにできることは2つあると思います...

  1. System.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
于 2012-04-21T19:32:19.613 に答える
18

プロセスが終了したにもかかわらず、「-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)"
}
于 2017-05-02T01:56:30.910 に答える
5

または、これを追加してみてください...

$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()を直接使用して行うことはできません。

于 2012-06-14T01:12:49.893 に答える
0

これがこのテーマのバリエーションです。Cisco Ampをアンインストールし、待機して、終了コードを取得したいと思います。しかし、アンインストールプログラムは、「un_a」と呼ばれる2番目のプログラムを開始し、終了します。このコードを使用すると、un_aが終了するのを待って、終了コードを取得できます。これは、「再起動が必要」の場合は3010です。これは実際には.batファイル内にあります。

あなたがfolding@homeをアンインストールしたいと思ったことがあるなら、それは同じように機能します。

rem uninstall cisco amp, probably needs a reboot after

rem runs Un_A.exe and exits

rem start /wait isn't useful
"c:\program files\Cisco\AMP\6.2.19\uninstall.exe" /S

powershell while (! ($proc = get-process Un_A -ea 0)) { sleep 1 }; $handle = $proc.handle; 'waiting'; wait-process Un_A; exit $proc.exitcode
于 2020-05-21T21:38:29.257 に答える