Padroneggia i blocchi Try Catch di PowerShell con esempi

Hai mai eseguito uno script o un cmdlet di PowerShell e ti sei trovato di fronte a un muro di testo urlante – in rosso – come quello mostrato di seguito?

Example of errors in PowerShell

Gli errori possono diventare travolgenti e confusi. E, soprattutto, gli errori sono spesso difficili da leggere, rendendo praticamente impossibile capire cosa e dove lo script ha commesso un errore.

Fortunatamente, hai alcune opzioni in PowerShell per migliorare questa situazione attraverso la gestione degli errori. Utilizzando la gestione degli errori, gli errori possono essere filtrati e visualizzati in modo tale da renderli più comprensibili. E capire l’errore facilita l’aggiunta di ulteriore logica alla gestione degli errori.

In questo articolo, imparerai tutto sugli errori in PowerShell e su come possono essere intercettati per eseguire la gestione degli errori utilizzando i blocchi Try Catch di PowerShell (e i blocchi finally).

Comprensione del Funzionamento degli Errori in PowerShell

Prima di approfondire la gestione degli errori, copriamo alcuni concetti sugli errori in PowerShell. Comprendere gli errori può portare a migliori strategie di gestione degli errori.

La Variabile Automatica $Error

In PowerShell, ci sono molte variabili automatiche, e una di esse è la variabile automatica $Error. PowerShell utilizza la variabile $Error per memorizzare tutti gli errori riscontrati nella sessione. La variabile $Error è un array di errori ordinati per i più recenti.

Quando si apre per la prima volta una sessione di PowerShell, la variabile $Error è vuota. È possibile verificare ciò chiamando la variabile $Error.

The $Error variable is empty

Come si può vedere, la variabile $Error è inizialmente vuota. Ma, una volta generato un errore, l’errore verrà aggiunto e memorizzato nella variabile $Error.

Nell’esempio sottostante, l’errore viene generato intenzionalmente ottenendo un nome di servizio che non esiste.

PS> Get-Service xyz
PS> $Error
PS> $Error.Count
The error is added to the $Error variable

Come si può vedere dall’output sopra riportato, l’errore generato è stato aggiunto alla variabile $Error.

La variabile $Error contiene una raccolta di errori generati nella sessione di PowerShell. Ogni errore può essere accessibile chiamando la sua posizione nell’array. L’ultimo errore sarà sempre all’indice 0.

Ad esempio, l’ultimo errore può essere recuperato utilizzando $Error[0].

Le proprietà dell’oggetto $Error

Dato che tutto in PowerShell è un oggetto, la variabile $Error è un oggetto e gli oggetti hanno proprietà. Utilizzando la pipeline per passare la variabile $Error al cmdlet Get-Member, dovresti vedere l’elenco delle proprietà disponibili.

$Error | Get-Member
The $Error object properties

Per determinare il motivo dell’errore, è possibile visualizzare il contenuto della proprietà InvocationInfo utilizzando il comando seguente.

$Error[0].InvocationInfo
The InvocationInfo property

Ora, potresti fare lo stesso con le altre proprietà e scoprire quali altre informazioni puoi trovare!

Errori di terminazione

Errori di terminazione interrompono il flusso di esecuzione quando vengono incontrati da PowerShell rispetto agli errori non di terminazione. Ci sono diversi modi in cui può verificarsi un errore di terminazione. Un esempio è quando si chiama un cmdlet con un parametro che non esiste.

Come si può vedere dalla schermata sottostante, quando viene eseguito il comando Get-Process notepad, il comando è valido e vengono visualizzati i dettagli del processo notepad.

The notepad process details

Tuttavia, quando viene utilizzato un parametro che non esiste come Get-Process notepad -handle 251, il cmdlet visualizza un errore che il parametro handle non è valido. Quindi, il cmdlet esce senza mostrare i dettagli del processo notepad.

Error is thrown because the parameter is invalid

Errori non di terminazione

Gli errori non di terminazione sono errori che non interrompono l’esecuzione dello script o del comando. Ad esempio, si può dare un’occhiata al codice qui sotto. Questo codice ottiene l’elenco dei nomi dei file dal file fileslist.txt. Successivamente, lo script passa attraverso ogni nome di file, legge il contenuto di ogni file e lo visualizza sullo schermo.

$file_list =  Get-Content .\filelist.txt
foreach ($file in $file_list) {
    Write-Output "Reading file $file"
    Get-Content $file
}

Il contenuto del file filelist.txt sono i nomi dei file mostrati nell’elenco sottostante.

File_1.log
File_2.log
File_3.log
File_4.log
File_5.log
File_6.log
File_7.log
File_8.log
File_9.log
File_10.log

Ma cosa succede se File_6.log non esistesse effettivamente? Quando si esegue il codice, ci si aspetta che si verifichi un errore perché lo script non riesce a trovare il file File_6.log. Si otterrà un output simile a quello mostrato di seguito.

Example of non-terminating error

Come puoi vedere dalla schermata dei risultati sopra, lo script è stato in grado di leggere i primi cinque file nell’elenco, ma quando ha provato a leggere il file File_6.txt, è stato restituito un errore. Lo script ha poi continuato a leggere il resto dei file prima di uscire. Non si è terminato.

La variabile $ErrorActionPreference

Fino ad ora, hai imparato sugli errori terminanti e non terminanti e su come differiscono l’uno dall’altro. Ma sapevi che un errore non terminante può essere forzato a essere trattato come un errore terminante?

PowerShell ha un concetto chiamato pvariabili di riferimento. Queste variabili vengono utilizzate per modificare il comportamento di PowerShell in molti modi diversi. Una di queste variabili si chiama $ErrorActionPreference.

La variabile $ErrorActionPreference viene utilizzata per modificare il modo in cui PowerShell gestisce gli errori non terminanti. Per impostazione predefinita, il valore di $ErrorActionPreference è impostato su Continua. Cambiando il valore della variabile $ErrorActionPreference in STOP forza PowerShell a trattare tutti gli errori come errori terminanti.

Utilizza il codice qui sotto per cambiare il valore di $ErrorActionPreference.

$ErrorActionPreference = "STOP"

Per apprendere ulteriori informazioni su altri valori validi della variabile $ErrorActionPreference, visita PowerShell ErrorActionPreference.

Ora, torna all’esempio utilizzato nella sezione Errori non terminanti di questo articolo. Lo script può essere modificato per includere il cambiamento in $ErrorActionPreference come mostrato nel codice sottostante:

# Imposta il valore di $ErrorActionPreference su STOP
$ErrorActionPreference = "STOP"
$file_list =  Get-Content .\filelist.txt
foreach ($file in $file_list) {
    Write-Output "Reading file $file"
    Get-Content $file
}

Eseguire il codice modificato sopra comporterà un comportamento diverso rispetto a prima quando il valore di $ErrorActionPreference è impostato sul valore predefinito di Continue.

Forcing a terminating error using the $ErrorActionPreference variable

Come puoi vedere dalla schermata dei risultati sopra, lo script è stato in grado di leggere i primi cinque file nell’elenco, ma quando ha provato a leggere il file File_6.txt, viene restituito un errore perché il file non è stato trovato. Quindi, lo script si è interrotto e il resto dei file non viene letto.

Il valore di $ErrorActionPreference è valido solo nella sessione PowerShell corrente. Si reimposta al valore predefinito una volta avviata una nuova sessione PowerShell.

Il parametro comune ErrorAction

Se il valore $ErrorActionPreference viene applicato alla sessione di PowerShell, il parametro ErrorAction si applica a qualsiasi cmdlet che supporta parametri comuni. Il parametro ErrorAction accetta gli stessi valori della variabile $ErrorActionPreference.

Il valore del parametro ErrorAction ha la precedenza sul valore di $ErrorActionPreference.

Torniamo indietro e utilizziamo lo stesso codice dell’esempio precedente. Ma, questa volta, il parametro ErrorAction viene aggiunto alla riga Get-Content.

# Imposta il valore di $ErrorActionPreference su default (CONTINUE)
$ErrorActionPreference = "CONTINUE"
$file_list =  Get-Content .\filelist.txt
foreach ($file in $file_list) {
    Write-Output "Reading file $file"
		# Utilizza il parametro comune -ErrorAction
		Get-Content $file -ErrorAction STOP
}

Dopo aver eseguito il codice modificato, vedrai che anche se $ErrorActionPreference è impostato su Continue, lo script viene comunque interrotto una volta che si verifica un errore. Lo script viene interrotto perché il valore del parametro ErrorAction di PowerShell in Get-Content è impostato su STOP.

Forcing a terminating error using the PowerShell ErrorAction parameter

Utilizzo dei blocchi Try Catch di PowerShell

A questo punto, hai imparato sugli errori di PowerShell e su come funzionano la variabile $ErrorActionPreference e i parametri ErrorAction di PowerShell. Ora è il momento di imparare le cose interessanti: i blocchi Try Catch Finally di PowerShell.

I blocchi try catch di PowerShell (e il blocco finally opzionale) sono un modo per gettare una rete intorno a un pezzo di codice e catturare eventuali errori che si verificano.

Il codice seguente mostra la sintassi dello statement Try.

try {
    <statement list>
}
catch [[<error type>][',' <error type>]*]{
    <statement list>
}
finally {
    <statement list>
}

Il blocco Try contiene il codice che si desidera che PowerShell “provi” e monitori per gli errori. Se il codice nel blocco Try incontra un errore, l’errore viene aggiunto alla variabile $Error e quindi passato al blocco Catch.

Il blocco Catch contiene le azioni da eseguire quando riceve un errore dal blocco Try. Possono esserci più blocchi Catch in uno statement Try.

Il blocco Finally contiene il codice che verrà eseguito alla fine dello statement Try. Questo blocco viene eseguito che ci sia stato un errore o meno.

Cattura errori non specifici (Catch-All) con l’ErrorAction di PowerShell

A simple Try statement contains a Try and a Catch block. The Finally block is optional.

Ad esempio, per catturare un’eccezione non specifica, il parametro Catch dovrebbe essere vuoto. Il codice di esempio di seguito utilizza lo stesso script utilizzato nella sezione La variabile $ErrorActionPreference ma modificato per utilizzare i blocchi Try Catch.

Come puoi vedere dal codice seguente, questa volta, il foreach statement è racchiuso nel blocco Try. Quindi, un blocco Catch contiene il codice per visualizzare la stringa Si è verificato un errore se si verifica un errore. Il codice nel blocco Finally cancella semplicemente la variabile $Error.

$file_list = Get-Content .\filelist.txt
try {
    foreach ($file in $file_list) {
        Write-Output "Reading file $file"
        Get-Content $file -ErrorAction STOP
    }
}
catch {
    Write-Host "An Error Occured" -ForegroundColor RED
}
finally {
    $Error.Clear()
}

Il codice sopra, dopo essere stato eseguito in PowerShell, ti darà questo output mostrato di seguito.

Script terminated when an error occurred

L’output sopra indica che lo script ha incontrato un errore, ha eseguito il codice all’interno del blocco Catch, e poi si è interrotto.

L’errore è stato gestito, che era lo scopo della gestione degli errori. Tuttavia, l’errore visualizzato era troppo generico. Per mostrare un errore più descrittivo, potresti accedere alla proprietà Exception dell’errore che è stato passato dal blocco Try.

Il codice qui sotto è modificato, in particolare il codice all’interno del blocco Catch, per visualizzare il messaggio di eccezione dell’errore corrente che è stato passato lungo il pipeline – $PSItem.Exception.Message

$file_list = Get-Content .\filelist.txt
try {
    foreach ($file in $file_list) {
        Write-Output "Reading file $file"
        Get-Content $file -ErrorAction STOP
    }
}
catch {
    Write-Host $PSItem.Exception.Message -ForegroundColor RED
}
finally {
    $Error.Clear()
}

Questa volta, quando viene eseguito il codice modificato sopra, il messaggio visualizzato è molto più descrittivo.

Script terminated with a descriptive error message

Gestione di Errori Specifici

Ci sono momenti in cui una gestione degli errori generale non è l’approccio più appropriato. Forse, vuoi che il tuo script esegua un’azione che dipende dal tipo di errore riscontrato.

Come si determina il tipo di errore? Controllando il valore TypeName della proprietà Exception dell’ultimo errore. Ad esempio, per trovare il tipo di errore dall’esempio precedente, usa questo comando:

$Error[0].Exception | Get-Member

Il risultato del codice sopra assomiglierebbe allo screenshot qui sotto. Come puoi vedere, viene visualizzato il valore TypeNameSystem.Management.Automation.ItemNotFoundException.

Getting the error TypeName value

Ora che conosci il tipo di errore che devi intercettare, modifica il codice per catturarlo in modo specifico. Come puoi vedere dal codice modificato qui sotto, ci sono ora due blocchi Catch. Il primo blocco Catch intercetta un tipo specifico di errore (System.Management.Automation.ItemNotFoundException). Al contrario, il secondo blocco Catch contiene il messaggio di errore generico, che intercetta tutti gli errori.

$file_list = Get-Content .\filelist.txt
try {
    foreach ($file in $file_list) {
        Write-Output "Reading file $file"
        Get-Content $file -ErrorAction STOP
    }
}
catch [System.Management.Automation.ItemNotFoundException]{
    Write-Host "The file $file is not found." -ForegroundColor RED
}
catch {
    Write-Host $PSItem.Exception.Message -ForegroundColor RED
}
finally {
    $Error.Clear()
}

La schermata qui sotto mostra l’output del codice modificato sopra.

Script terminated with a specific error message

Conclusione

In questo articolo, hai appreso gli errori in PowerShell, le loro proprietà e come puoi determinare il tipo specifico di errore. Hai anche appreso la differenza tra il modo in cui la variabile $ErrorActionPreference e il parametro ErrorAction di PowerShell influenzano il modo in cui PowerShell tratta gli errori non terminanti.

Hai anche imparato come utilizzare i blocchi PowerShell Try Catch Finally per gestire gli errori, sia per errori specifici che per un approccio generale.

Gli esempi mostrati in questo articolo illustrano solo i concetti di base di come funzionano i blocchi Try Catch Finally. La conoscenza che spero tu abbia acquisito in questo articolo dovrebbe darti le basi per iniziare ad applicare la gestione degli errori nei tuoi script.

Ulteriori Letture

Source:
https://adamtheautomator.com/powershell-try-catch/