Start-Process in PowerShell: Avvio Intuitivo del Processo

Per capire perché Start-Process e tutti questi altri comandi sono limitati, devi prima capire come funziona un tipico file EXE. Quando viene eseguito un file EXE, esegue l’azione per cui è stato progettato; fa il ping a qualcosa (ping), avvia un installer di software (setup), cerca un record DNS (nslookup), eccetera. Per questa parte e Start-Process ae altri comandi per avviare un processo funzionano alla grande. È semplice. Il limite si presenta quando quel file EXE restituisce un output.

Possiamo avviare un processo in PowerShell in molti modi diversi. Abbiamo i cmdlet PowerShell Start-Process e Invoke-Expression, possiamo chiamare direttamente l’eseguibile o usare l’ampersand (&) per invocare espressioni. Il modo più comune è utilizzare Start-Process perché è probabilmente il più intuitivo. PowerShell è noto per il suo approccio intuitivo alla denominazione dei comandi e Start-Process è una scelta eccellente. Tuttavia, quel comando è limitato.

Flussi

Un file EXE, come molti altri file eseguibili non limitati a Windows, ha il concetto di flussi standard. I flussi standard sono il modo in cui i file eseguibili restituiscono output. Questi flussi si presentano in tre varianti; stdin, stdout e stderr. Stdin è il flusso che può essere passato all’interno di l’eseguibile su cui non ci concentreremo qui. Stdout è il flusso che l’eseguibile utilizza per inviare output normale non di errore.

In termini di PowerShell, pensa a stdout come a ciò che restituisce Write-Output. Quando si verifica un errore (a seconda se lo sviluppatore dell’eseguibile l’ha scritto correttamente), l’eseguibile dovrebbe restituire l’output tramite stderr. Questo è uno stream che viene riservato per restituire eventuali informazioni sugli errori.

Questi stream permettono agli utenti di questi file eseguibili di differenziare tra l’output tipico e ciò che è un errore. Gli stream esistono da decenni e Windows, quindi PowerShell, ne sa tutto e ha adottato il proprio.

Codici di Uscita

Un codice di uscita, codice di ritorno o codice di risultato è un altro concetto vecchio come il mondo che i file eseguibili seguono. Un codice di uscita è un numero intero che consente all’eseguibile di segnalare uno stato all’utente quando esce.

Ci sono alcuni codici di uscita standard che i programmi dovrebbero seguire, come ad esempio se il codice di uscita è 0, tutto va bene, il codice di uscita 3010 significa che è necessario riavviare e così via. PowerShell può catturare questo codice di uscita in diversi modi, ad esempio utilizzando la variabile automatica $LastExitCode. I codici di uscita sono un altro metodo con cui il file eseguibile comunica all’utente.

Cattura di Stream e Codici di Uscita

Ora che hai capito con cosa stiamo lavorando, usiamo un esempio. Per mantenerlo semplice, userò il vecchio ping.exe. Prima, farò un ping a google.com che restituirà un risultato di successo. Non stiamo utilizzando qui il processo di avvio di PowerShell.

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

Hai visto che il codice di uscita differisce perché il risultato di ping era diverso, ma non hai visto i flussi perché nativamente PowerShell non comprende la differenza quando si tratta di file eseguibili. Il testo che vedi nella console è bianco; non il testo di errore rosso che conosci e ami.

Possiamo catturare i flussi e ridirigerli su file in diversi modi, come utilizzando > e 2> come mostrato di seguito. Questo è il modo vecchio stile.

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.

Notate però che, in questo caso, anche se ping.exe restituisce un codice di uscita pari a 1 (come mostrato sopra), quell’output va comunque a stdout. Questo è comune. A quale flusso e codice di uscita viene restituito è completamente a discrezione dello sviluppatore e viene in molti stili diversi, sfortunatamente.

Se vuoi procedere nel modo “nuova scuola” potresti utilizzare Start-Process e utilizzare i parametri -RedirectStandardError e -RedirectStandardOutput, ma andrebbero comunque solo su file.

Limitazioni di Start-Process

Puoi vedere che avviare un processo e restituire qualche output comune non è troppo comune. Inoltre, PowerShell non gestisce molto bene i flussi e i codici di uscita. Se dovessi utilizzare Start-process per eseguire ping.exe e volessi tracciare cosa è successo nel risultato, dovrei fare qualcosa del genere ogni volta che volessi eseguire un file eseguibile.

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!

Correggiamo tutto questo. Scarica una piccola funzione che ho creato chiamata Invoke-Process dalla PowerShell Gallery.

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

Ora esegui ping utilizzando un host valido e vedi cosa succede.

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

Osserva come otteniamo lo stesso output. Questo è buono!

Ora esegui il ping utilizzando un host non valido.

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

Ora notiamo che otteniamo il tipico testo di errore rosso come ci si aspetterebbe se qualcosa fosse andato storto. Invoke-Process utilizza Start-Process sotto il cofano per catturare stdout, stderr e il codice di uscita e quindi invia l’output allo stream a cui dovrebbe andare. È così che dovrebbe essere!

Peccato che PowerShell non abbia reso più facile lavorare con gli stream e i codici di uscita dai file eseguibili, ma suppongo che oggi, ora che è open source, possiamo aggiungerlo lì dentro!

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