wake-up-neo.com

Erhalten Sie ExitCode mit Start-Process und WaitForExit anstelle von -Wait

Ich versuche, ein Programm von PowerShell aus auszuführen, auf den Exit zu warten und dann auf den ExitCode zuzugreifen, aber ich habe nicht viel Glück. Ich möchte -Wait Nicht zusammen mit Start-Process verwenden, da ich im Hintergrund noch einige Verarbeitungsschritte ausführen muss.

Hier ist ein vereinfachtes Testskript:

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

Wenn Sie dieses Skript ausführen, wird Notepad gestartet. Nachdem dies manuell geschlossen wurde, wird der Beendigungscode gedruckt und ohne Verwendung von -wait Erneut gestartet. Es wird kein ExitCode bereitgestellt, wenn dieser beendet wird:

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:

Ich muss in der Lage sein, zwischen dem Starten des Programms und dem Warten auf das Beenden des Programms eine zusätzliche Verarbeitung durchzuführen, daher kann ich -Wait Nicht verwenden. Wie kann ich das tun und trotzdem von diesem Prozess aus auf die .ExitCode-Eigenschaft zugreifen?

57
Richard

Zwei Dinge, die Sie tun könnten, denke ich ...

  1. Erstellen Sie das System.Diagnostics.Process-Objekt manuell und umgehen Sie Start-Process
  2. Ausführen der ausführbaren Datei in einem Hintergrundjob (nur für nicht interaktive Prozesse!)

Hier ist, wie Sie entweder tun könnten:

$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

ODER

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

Hier sind zwei Dinge zu beachten. Zum einen das Argument -PassThru Und zum anderen das Argument -Wait. Sie müssen das wait-Argument wegen dieses Fehlers hinzufügen: 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.

Sobald Sie dies tun, wird ein Prozessobjekt zurückgegeben und Sie können die ExitCode-Eigenschaft dieses Objekts anzeigen. Hier ist ein Beispiel:

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

# This will print 1

Wenn Sie es ohne -PassThru Oder -Wait Ausführen, wird nichts gedruckt.

Dieselbe Antwort finden Sie hier: Wie führe ich ein Windows-Installationsprogramm aus und erhalte einen Erfolgs-/Fehlschlagswert in PowerShell?

81

Als ich den letzten Vorschlag oben ausprobierte, entdeckte ich eine noch einfachere Lösung. Alles, was ich tun musste, war das Prozesshandle zwischenzuspeichern. Sobald ich das getan habe, hat $ process.ExitCode richtig funktioniert. Wenn ich das Prozesshandle nicht zwischengespeichert habe, war $ process.ExitCode null.

beispiel:

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

Die Option "Warten" schien für mich zu blockieren, obwohl mein Prozess beendet war.

Ich habe versucht, Adrian Lösung und es funktioniert. Aber ich habe Wait-Process verwendet, anstatt mich auf einen Nebeneffekt beim Abrufen des Prozess-Handles zu verlassen.

So:

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

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

Oder füge dies hinzu ...

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

Mithilfe dieses Codes können Sie PowerShell weiterhin die Verwaltung umgeleiteter Ausgabe-/Fehlerströme überlassen, was mit System.Diagnostics.Process.Start () nicht direkt möglich ist.

4
Greg Vogel