Start-Process gibt tlw. keinen ReturnCode aus (PowerShell)
mayho33 (Level 2) - Jetzt verbinden
26.01.2014, aktualisiert 28.03.2014, 5987 Aufrufe, 4 Kommentare, 1 Danke
Hallo @ All!
Irgendwie stehe ich wieder mal am Schlauch und hoffe wieder auf tatkräftige Starthilfe!
Hier mein Problem:
Ich rufe eine Exe auf via: $RC = (Start-Process -FilePath <Irgend eine exe> /s -PassTru)
-Wait gebe ich absichtlich nicht an ich will nämlich, dass in der PS-Console sowas wie ein Fortschrittsbalken läuft. das mache ich so:
do {
write-host "*" -NoNewLine
if ($RC.ExitCode -gt -1) { Break}
Start-Sleep 1
} until ($RC.ExitCode -gt -1)
write-host ("ExitCode: + $RC.ExitCode)
Jetzt kommt es vor, dass entweder die Schleife nicht beendet wird obwohl der ExitCode sicher 0 oder höher ist, oder der ExitCode ist $null.
mit -Wait bekomme ich natürlich immer eine ExitCode, da habe ich aber auch keine Fortschrittsbalken. Den will ich aber unbedingt haben, weil einige EXEn und MSIs ziemlich groß sind und entsprechend lange brauchen.
Hat jemand ne Idee wie ich da eine saubere und vor allem sichere Lösung zustande bekomme??
Danke!
Mayho
Irgendwie stehe ich wieder mal am Schlauch und hoffe wieder auf tatkräftige Starthilfe!
Hier mein Problem:
Ich rufe eine Exe auf via: $RC = (Start-Process -FilePath <Irgend eine exe> /s -PassTru)
-Wait gebe ich absichtlich nicht an ich will nämlich, dass in der PS-Console sowas wie ein Fortschrittsbalken läuft. das mache ich so:
do {
write-host "*" -NoNewLine
if ($RC.ExitCode -gt -1) { Break}
Start-Sleep 1
} until ($RC.ExitCode -gt -1)
write-host ("ExitCode: + $RC.ExitCode)
Jetzt kommt es vor, dass entweder die Schleife nicht beendet wird obwohl der ExitCode sicher 0 oder höher ist, oder der ExitCode ist $null.
mit -Wait bekomme ich natürlich immer eine ExitCode, da habe ich aber auch keine Fortschrittsbalken. Den will ich aber unbedingt haben, weil einige EXEn und MSIs ziemlich groß sind und entsprechend lange brauchen.
Hat jemand ne Idee wie ich da eine saubere und vor allem sichere Lösung zustande bekomme??
Danke!
Mayho
4 Antworten
- LÖSUNG colinardo schreibt am 27.01.2014 um 00:17:59 Uhr
- LÖSUNG colinardo schreibt am 27.01.2014 um 10:21:10 Uhr
- LÖSUNG mayho33 schreibt am 29.01.2014 um 19:40:16 Uhr
- LÖSUNG MPascalau schreibt am 15.08.2015 um 18:46:06 Uhr
LÖSUNG 27.01.2014, aktualisiert um 01:01 Uhr
Hallo Mayho,
Schau dir mal dieses Mulithreading-Beispiel an:
https://www.administrator.de/forum/powershell-gui-bleibt-w%C3%A4hrend-ei ...
Würde den Prozess in einen parallelen Thread verlagern worin du dann mit -wait auf den Prozess wartest und dann den Exit-Code an den Hauptthread übergibst. Gerade bei MSI-Dateien ist es so das die Shell auf das Ende von msiexec warten sollte, denn sonst kommt es zu dem Phänomen das ein falscher Exit-Code ausgegeben wird (das liegt daran das msiexec ursprünglich nicht als Konsolenanwendung ausgelegt worden ist)
Was auch eine Möglichkeit wäre ist das CMDlet Start-Job mit dem sich so was realisieren ließe. Melde mich dazu nochmal...
Bis dahin ...
Grüße Uwe
Schau dir mal dieses Mulithreading-Beispiel an:
https://www.administrator.de/forum/powershell-gui-bleibt-w%C3%A4hrend-ei ...
Würde den Prozess in einen parallelen Thread verlagern worin du dann mit -wait auf den Prozess wartest und dann den Exit-Code an den Hauptthread übergibst. Gerade bei MSI-Dateien ist es so das die Shell auf das Ende von msiexec warten sollte, denn sonst kommt es zu dem Phänomen das ein falscher Exit-Code ausgegeben wird (das liegt daran das msiexec ursprünglich nicht als Konsolenanwendung ausgelegt worden ist)
Was auch eine Möglichkeit wäre ist das CMDlet Start-Job mit dem sich so was realisieren ließe. Melde mich dazu nochmal...
Bis dahin ...
Grüße Uwe
LÖSUNG 27.01.2014, aktualisiert 10.02.2014
Noch ein Beispiel wie du es machen kannst:
Grüße Uwe
# Hashtable beinhaltet später die Informationen aus dem parallelen Thread
$rc = @{}
# Neuen Thread erstellen
$myjob = [Powershell]::Create().AddScript({
param($result)
# hier dein Aufruf deiner MSI-Datei
$r = start-process "msiexec /i install.msi /qn" -wait -PassThru
$result.ExitCode = $r.ExitCode
}).AddArgument($rc)
# Thread starten
$myjob.BeginInvoke()| out-null
# Warte auf das Ende des Threads
while($myjob.InvocationStateInfo.State -eq "Running"){
write-host "*" -NoNewLine
sleep(1)
}
# Gebe ExitCode aus
echo "`r`nExit-Code: $($rc.ExitCode)"
LÖSUNG 29.01.2014, aktualisiert 10.02.2014
Hi Uwe!
Danke für die beiden Beispiele! Werde das mal in ner ruhigen Minute durchgehen. Multithreading habe ich noch nicht bedacht. Finde das ist eine tolle Idee.
Danke!
Mayho
EDIT
Hi Uwe!
nun hatte ich endlich Zeit das in meinen Code einzubauen.
Das zweite Beispiel von dir hat wunderbar geklappt ohne groß was anpassen zu müssen. Das Resultat ist wie gewünscht eine Progressanzeige in der Console. Auch die Returncodes kommen wie sie sollen.
Perfekt!! Vielen Dank!
Was habe ich daraus gelernt? Bei Problemen Uwe fragen :P
lg
Mayho!
Danke für die beiden Beispiele! Werde das mal in ner ruhigen Minute durchgehen. Multithreading habe ich noch nicht bedacht. Finde das ist eine tolle Idee.
Danke!
Mayho
EDIT
Hi Uwe!
nun hatte ich endlich Zeit das in meinen Code einzubauen.
Das zweite Beispiel von dir hat wunderbar geklappt ohne groß was anpassen zu müssen. Das Resultat ist wie gewünscht eine Progressanzeige in der Console. Auch die Returncodes kommen wie sie sollen.
Perfekt!! Vielen Dank!
Was habe ich daraus gelernt? Bei Problemen Uwe fragen :P
lg
Mayho!
LÖSUNG 15.08.2015 um 18:46 Uhr
Ich habe vor lange Zeit gelesen, dass PowerShell mit ExitCode Eigenschaft von Process ein Problem hat.
Die Erklärung war viel zu Kompliziert, und ich habe vergessen.
Ich habe das Problem so korrigiert:
function Get-ProcessExitCode {
[CmdletBinding()]
param(
[parameter(Mandatory=$true, ValueFromPipeline=$true)]
[System.Diagnostics.Process]$Process)
Begin {
$private:type = [System.Diagnostics.Process]
$private:prop = $private:type.GetProperty("ExitCode")
}
Process {
return $private:prop.GetValue($Process)
}
}
$RC.WaitForExit() # Wait for process to finish!
$exitcode = Get-ProcessExitCode $RC # Get the ExitCode
Die Erklärung war viel zu Kompliziert, und ich habe vergessen.
Ich habe das Problem so korrigiert:
function Get-ProcessExitCode {
[CmdletBinding()]
param(
[parameter(Mandatory=$true, ValueFromPipeline=$true)]
[System.Diagnostics.Process]$Process)
Begin {
$private:type = [System.Diagnostics.Process]
$private:prop = $private:type.GetProperty("ExitCode")
}
Process {
return $private:prop.GetValue($Process)
}
}
$RC.WaitForExit() # Wait for process to finish!
$exitcode = Get-ProcessExitCode $RC # Get the ExitCode