Start-Process in PowerShell: Intuïtieve lancering van processen

Om te begrijpen waarom Start-Process en al deze andere opdrachten beperkt zijn, moet je eerst begrijpen hoe een typisch EXE-bestand werkt. Wanneer een EXE-bestand wordt uitgevoerd, voert het de actie uit waarvoor het is ontworpen; het pingt iets (ping), start een software-installatieprogramma (setup), zoekt naar een DNS-record (nslookup), wat dan ook. Voor dit deel en Start-Process en andere opdrachten om een proces te starten werkt geweldig. Het is eenvoudig. De beperking komt wanneer dat EXE-bestand enige uitvoer retourneert.

We kunnen een proces starten in PowerShell op veel verschillende manieren. We hebben de PowerShell Start-Process en Invoke-Expression cmdlets, we kunnen het uitvoerbare bestand rechtstreeks aanroepen of de ampersand (&) gebruiken om expressies aan te roepen. De meest gebruikelijke manier is om Start-Process te gebruiken omdat het waarschijnlijk het meest intuïtief is. PowerShell staat bekend om zijn intuïtieve benadering van het benoemen van commando’s en Start-Process is een uitstekende keuze. Echter, die opdracht heeft beperkingen.

Streams

Een EXE-bestand, net als veel andere uitvoerbare bestanden, niet beperkt tot Windows, heeft een concept van standaardstreams. Standaardstreams zijn hoe uitvoerbare bestanden uitvoer retourneren. Deze streams komen in drie smaken; stdin, stdout en stderr. Stdin is de stream die naar het uitvoerbare bestand kan worden doorgegeven, waar we hier niet op zullen focussen. Stdout is de stream die het uitvoerbare bestand gebruikt om normale niet-foutuitvoer te verzenden.

In PowerShell-termen kun je stdout beschouwen als wat Write-Output retourneert. Wanneer er een fout optreedt (afhankelijk van of de ontwikkelaar van het uitvoerbare bestand het correct heeft geschreven), zou het uitvoerbare bestand output moeten retourneren via stderr. Dit is een stream die apart is gezet voor het retourneren van foutinformatie.

Deze streams stellen gebruikers van deze uitvoerbare bestanden in staat om onderscheid te maken tussen wat gebruikelijke output is en wat een fout is. Streams bestaan al tientallen jaren, en Windows en dus PowerShell weten er alles van en hebben er zelfs hun eigen versie van aangenomen.

Exit-codes

Een exit-code, retourcode of resultaatcode is nog een oud concept dat uitvoerbare bestanden ook volgen. Een exit-code is een geheel getal dat het het uitvoerbare bestand mogelijk maakt om bij het afsluiten een status aan de gebruiker door te geven.

Er zijn enkele standaard exit-codes die programma’s zouden moeten volgen, zoals als de exit-code 0 is, is alles in orde, exit-code 3010 betekent dat er een herstart nodig is, enzovoort. PowerShell kan deze exit-code op verschillende manieren vastleggen, zoals het gebruik van de automatische variabele $LastExitCode. Exit-codes zijn nog een manier waarop het uitvoerbare bestand communiceert met de gebruiker.

Streams en Exit-codes Vastleggen

Nu je begrijpt waarmee we werken, laten we een voorbeeld gebruiken. Om het eenvoudig te houden, zal ik de goede oude ping.exe gebruiken. Eerst zal ik pingen naar google.com, wat een succesvol resultaat zou moeten opleveren. We gebruiken hier niet PowerShell Start-Process.

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

Je zag dat de exit-code verschilt omdat het resultaat van ping anders was, maar je zag geen streams omdat PowerShell van nature het verschil niet begrijpt als het gaat om uitvoerbare bestanden. De tekst die je ziet in de console is wit; niet de rode fouttekst waar je van houdt.

We kunnen de streams vastleggen en omleiden naar bestanden op verschillende manieren, zoals het gebruik van > en 2> zoals hieronder. Dit is de ouderwetse manier.

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.

Merk echter op dat, in dit geval, zelfs als ping.exe een exit-code van 1 retourneert (zoals hierboven getoond), die uitvoer nog steeds naar stdout gaat. Dit is gebruikelijk. Welke stream en exitcode worden geretourneerd, is volledig aan de ontwikkelaar en komt in veel verschillende stijlen voor, helaas.

Als je de “nieuwe school” wilt volgen, kun je Start-Process gebruiken en de parameters -RedirectStandardError en -RedirectStandardOutput gebruiken, maar ze worden nog steeds alleen naar bestanden geleid.

Beperkingen van Start-Process

Je kunt zien dat het starten van een proces en het retourneren van enkele algemene uitvoer niet al te gebruikelijk is. Bovendien behandelt PowerShell de streams en exitcodes niet al te goed. Als ik Start-Process zou gebruiken om ping.exe uit te voeren en wilde bijhouden wat er in het resultaat gebeurde, zou ik iets als dit moeten doen elke keer dat ik een uitvoerbaar bestand wilde uitvoeren.

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!

Laten we dit allemaal oplossen. Download een kleine functie die ik heb gemaakt genaamd Invoke-Process van de PowerShell Gallery.

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

Voer nu ping uit met behulp van een geldige host en kijk wat er gebeurt.

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

Merk op hoe we dezelfde uitvoer krijgen. Dat is goed!

Voer nu ping uit met gebruik van een ongeldige host.

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

Let nu op dat we de typische rode fouttekst krijgen zoals we zouden verwachten als er iets mis ging. Invoke-Process gebruikt Start-Process onderliggend om stdout, stderr en de exitcode vast te leggen, en stuurt vervolgens de uitvoer naar de juiste stream. Zo hoort het te zijn!

Het is jammer dat PowerShell het niet eenvoudiger heeft gemaakt om met streams en exitcodes van uitvoerbare bestanden te werken, maar ik veronderstel dat we dat tegenwoordig kunnen toevoegen nu het open source is!

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