Start-Process in PowerShell: Intuitives Prozess-Starten

Um zu verstehen, warum Start-Process und all diese anderen Befehle eingeschränkt sind, muss man zunächst verstehen, wie eine typische EXE-Datei funktioniert. Wenn eine EXE-Datei ausgeführt wird, führt sie die Aktion aus, für die sie entwickelt wurde; sie pingt etwas (ping), startet einen Software-Installer (setup), sucht einen DNS-Eintrag nach (nslookup), was auch immer. Für diesen Teil und Start-Process and andere Befehle, um einen Prozess zu starten, funktioniert es großartig. Es ist einfach. Die Einschränkung tritt auf, wenn diese EXE-Datei eine Ausgabe zurückgibt.

Wir können einen Prozess auf verschiedene Arten in PowerShell starten. Wir haben die PowerShell Start-Process und Invoke-Expression Cmdlets, wir können die ausführbare Datei direkt aufrufen oder das kaufmännische Und-Zeichen (&) verwenden, um Ausdrücke aufzurufen. Der häufigste Weg ist jedoch die Verwendung von Start-Process, weil es wahrscheinlich am intuitivsten ist. PowerShell steht für seinen intuitiven Ansatz bei der Benennung von Befehlen, und Start-Process ist eine ausgezeichnete Wahl. Allerdings ist dieser Befehl begrenzt.

Streams

Eine EXE-Datei, wie viele andere ausführbare Dateien, nicht nur unter Windows, hat ein Konzept von Standard-Streams. Standard-Streams sind die Art und Weise, wie ausführbare Dateien Ausgaben zurückgeben. Diese Streams kommen in drei Varianten vor: stdin, stdout und stderr. Stdin ist der Stream, der an die ausführbare Datei übergeben werden kann, auf den wir uns hier nicht konzentrieren werden. Stdout ist der Stream, den die ausführbare Datei verwendet, um normale, nicht-fehlerhafte Ausgaben zu senden.

Im PowerShell-Jargon betrachte stdout als das, was Write-Output zurückgibt. Wenn ein Fehler auftritt (abhängig davon, ob der Entwickler der ausführbaren Datei es richtig geschrieben hat), sollte die ausführbare Datei die Ausgabe über stderr zurückgeben. Dies ist ein Stream, der für die Rückgabe von Fehlerinformationen reserviert ist.

Diese Streams ermöglichen es Benutzern dieser ausführbaren Dateien, zwischen dem üblichen Output und einem Fehler zu unterscheiden. Streams gibt es seit Jahrzehnten, und Windows sowie PowerShell wissen alles darüber und haben ihre eigenen übernommen.

Exit-Codes

Ein Exit-Code, Rückgabecode oder Ergebniscode ist ein weiteres altbewährtes Konzept, dem ausführbare Dateien folgen. Ein Exit-Code ist eine Ganzzahl, die es der ausführbaren Datei ermöglicht, beim Beenden einen Status an den Benutzer zu signalisieren.

Es gibt einige Standard-Exit-Codes, denen Programme folgen sollen, wie z. B. wenn der Exit-Code 0 ist, ist alles in Ordnung, Exit-Code 3010 bedeutet, dass ein Neustart erforderlich ist, und so weiter. PowerShell kann diesen Exit-Code auf verschiedene Arten erfassen, z. B. durch Verwendung der automatischen Variable $LastExitCode. Exit-Codes sind eine weitere Methode, mit der die ausführbare Datei mit dem Benutzer kommuniziert.

Erfassen von Streams und Exit-Codes

Jetzt, da Sie verstehen, woran wir arbeiten, verwenden wir ein Beispiel. Um es einfach zu halten, werde ich das gute alte ping.exe verwenden. Zuerst werde ich google.com pingen, was ein erfolgreiches Ergebnis zurückgeben wird. Hier verwenden wir nicht den PowerShell-Startprozess.

PS C:\> ping google.com
Pinging google.com [2607:f8b0:4004:80b::200e] with 32 bytes of data:

Reply from 2607:f8b0:4004:80b::200e: time=61ms
Reply from 2607:f8b0:4004:80b::200e: time=65ms
Reply from 2607:f8b0:4004:80b::200e: time=80ms
Reply from 2607:f8b0:4004:80b::200e: time=78ms

Ping statistics for 2607:f8b0:4004:80b::200e:

Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 61ms, Maximum = 80ms, Average = 71ms

PS> $LastExitCode
0
PS> $?
True

I’ll now purposefully ping a host that doesn’t resolve a DNS name and will fail. Notice the value of $LastExitCode.

PS> ping googlllll.com

Ping request could not find host googlllll.com. Please check the name and try again.
PS> $LASTEXITCODE
1

Du hast bemerkt, dass der Exit-Code sich unterscheidet, weil das Ergebnis von Ping anders war, aber du hast die Streams nicht gesehen, weil PowerShell nativ den Unterschied bei ausführbaren Dateien nicht versteht. Der Text, den du in der Konsole siehst, ist weiß; nicht der rote Fehlertext, den du kennst und liebst.

Wir können die Streams erfassen und auf verschiedene Arten umleiten, z.B. mit > und 2> wie unten gezeigt. Das ist die alte Schule.

PS> ping googllll.com > output.msg 2> output.err
PS> Get-Content .\output.err
PS> Get-Content .\output.msg

Ping request could not find host googllll.com. Please check the name and try again.

Beachte jedoch, dass in diesem Fall, obwohl ping.exe einen Exit-Code von 1 zurückgibt (wie oben gezeigt), diese Ausgabe immer noch an stdout geht. Das ist üblich. Welcher Stream und Exit-Code zurückgegeben werden, liegt ganz beim Entwickler und erfolgt in vielen verschiedenen Stilen, leider.

Wenn du den „neuen Weg“ gehen möchtest, könntest du Start-Process verwenden und die Parameter -RedirectStandardError und -RedirectStandardOutput verwenden, aber sie würden immer noch nur in Dateien gehen.

Einschränkungen von Start-Process

Du kannst sehen, dass das Starten eines Prozesses und das Zurückgeben einiger allgemeiner Ausgaben nicht allzu verbreitet ist. Darüber hinaus behandelt PowerShell die Streams und Exit-Codes nicht besonders gut. Wenn ich Start-Process verwenden würde, um ping.exe auszuführen und das Ergebnis verfolgen möchte, müsste ich jedes Mal etwas wie dies tun, wenn ich eine ausführbare Datei ausführen wollte.

PS> Start-Process -FilePath -NoNewWindow ping -ArgumentList 'google.com' -RedirectStandardOutput output.txt -RedirectStandardError err.txt
PS> $LastExitCode
PS> Get-Content -Path output.txt
PS> Get-Content -Path err.txt

I still wouldn’t get my error text either!

Lass uns das alles reparieren. Lade eine kleine Funktion herunter, die ich erstellt habe, namens Invoke-Process aus der PowerShell Gallery.

PS> Install-Script 'Invoke-Process'
PS> . Invoke-Process.ps1

Führe nun Ping mit einem gültigen Host aus und sieh, was passiert.

Invoke-Process -FilePath ping -ArgumentList ‘google.com’

Beachte, wie wir die gleiche Ausgabe erhalten. Das ist gut!

Führen Sie jetzt einen Ping mit einem ungültigen Host aus.

Invoke-Process -FilePath ping -ArgumentList ‘googlddde.com’

Beachten Sie nun, dass wir den typischen roten Fehlertext erhalten, wie wir es erwarten würden, wenn etwas schiefgeht. Invoke-Process verwendet Start-Process unter der Oberfläche, um stdout, stderr und den Exit-Code zu erfassen und sendet dann die Ausgabe an den entsprechenden Stream. So sollte es sein!

Schade, dass PowerShell es nicht einfacher gemacht hat, mit Streams und Exit-Codes von ausführbaren Dateien zu arbeiten, aber ich nehme an, heutzutage können wir das jetzt hinzufügen, da es Open Source ist!

Source:
https://adamtheautomator.com/start-process/