Maîtrisez les blocs Try Catch de PowerShell avec des exemples

Avez-vous déjà exécuté un script ou une commande PowerShell et été confronté à un mur de texte criard – en rouge – comme celui ci-dessous?

Example of errors in PowerShell

Les erreurs peuvent devenir écrasantes et déroutantes. Et surtout, les erreurs sont souvent difficiles à lire, ce qui rend presque impossible de déterminer ce qui n’a pas fonctionné dans le script et où.

Heureusement, vous avez quelques options dans PowerShell pour améliorer cela grâce à la gestion des erreurs. En utilisant la gestion des erreurs, les erreurs peuvent être filtrées et affichées de manière à ce qu’il soit plus facile de les comprendre. Et comprendre l’erreur facilite l’ajout de plus de logique à la gestion des erreurs.

Dans cet article, vous découvrirez les erreurs dans PowerShell et comment les intercepter pour effectuer une gestion des erreurs à l’aide des blocs Try Catch de PowerShell (et des blocs finally).

Comprendre le fonctionnement des erreurs dans PowerShell

Avant d’aborder la gestion des erreurs, couvrons d’abord quelques concepts autour des erreurs dans PowerShell. Comprendre les erreurs peut conduire à de meilleures stratégies de gestion des erreurs.

La variable automatique $Error

En PowerShell, il existe de nombreuses variables automatiques, et l’une d’elles est la variable automatique $Error. PowerShell utilise la variable $Error pour stocker toutes les erreurs rencontrées dans la session. La variable $Error est un tableau d’erreurs triées par les plus récentes.

Lorsque vous ouvrez une session PowerShell pour la première fois, la variable $Error est vide. Vous pouvez le vérifier en appelant la variable $Error.

The $Error variable is empty

Comme vous pouvez le voir, la variable $Error commence vide. Cependant, une fois qu’une erreur est générée, l’erreur sera ajoutée et stockée dans la variable $Error.

Dans l’exemple ci-dessous, l’erreur est générée en obtenant délibérément un nom de service qui n’existe pas.

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

Comme vous pouvez le voir dans la sortie ci-dessus, l’erreur générée a été ajoutée à la variable $Error.

La variable $Error contient une collection d’erreurs générées dans la session PowerShell. Chaque erreur peut être accédée en appelant sa position dans le tableau. La dernière erreur sera toujours à l’index 0.

Par exemple, la dernière erreur peut être récupérée en utilisant $Error[0].

Les propriétés de l’objet $Error

Étant donné que tout dans PowerShell est un objet, la variable $Error est un objet, et les objets ont des propriétés. En passant la variable $Error à la cmdlet Get-Member, vous devriez voir la liste des propriétés disponibles.

$Error | Get-Member
The $Error object properties

Pour déterminer la raison de l’erreur, vous pouvez afficher le contenu de la propriété InvocationInfo en utilisant la commande ci-dessous.

$Error[0].InvocationInfo
The InvocationInfo property

Maintenant, vous pourriez faire la même chose avec les autres propriétés et découvrir quelles autres informations vous pouvez trouver!

Erreurs de terminaison

Les erreurs terminales arrêtent le flux d’exécution lorsqu’elles sont rencontrées par PowerShell par rapport aux erreurs non-terminales. Il existe plusieurs façons qu’une erreur terminale peut se produire. Un exemple est lorsque vous appelez une cmdlet avec un paramètre qui n’existe pas.

Comme vous pouvez le voir sur la capture d’écran ci-dessous, lorsque la commande Get-Process notepad est exécutée, la commande est valide et les détails du processus notepad sont affichés.

The notepad process details

Mais, lorsque vous utilisez un paramètre qui n’existe pas comme Get-Process notepad -handle 251, la cmdlet affiche une erreur indiquant que le paramètre handle n’est pas valide. Ensuite, la cmdlet se termine sans afficher les détails du processus notepad.

Error is thrown because the parameter is invalid

Erreurs non-terminales

Les erreurs non-terminales sont des erreurs qui n’arrêtent pas l’exécution du script ou de la commande. Par exemple, regardez le code ci-dessous. Ce code obtient la liste des noms de fichiers à partir du fichier fileslist.txt. Ensuite, le script parcourt chaque nom de fichier, lit le contenu de chaque fichier et l’affiche à l’écran.

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

Le contenu du fichier filelist.txt sont les noms de fichiers indiqués dans la liste ci-dessous.

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

Mais que se passe-t-il si File_6.log n’existe pas réellement ? Lorsque vous exécutez le code, vous vous attendez à ce qu’une erreur se produise car le script ne peut pas trouver le fichier File_6.log. Vous verrez une sortie similaire indiquée ci-dessous.

Example of non-terminating error

Comme vous pouvez le voir sur la capture d’écran du résultat ci-dessus, le script a pu lire les cinq premiers fichiers de la liste, mais lorsqu’il a essayé de lire le fichier File_6.txt, une erreur est retournée. Le script a ensuite continué à lire le reste des fichiers avant de quitter. Il n’a pas terminé.

La variable $ErrorActionPreference

Jusqu’à présent, vous avez appris la différence entre les erreurs terminales et non terminales. Mais saviez-vous qu’une erreur non terminale peut être forcée à être traitée comme une erreur terminale?

PowerShell a un concept appelé les variables de référence. Ces variables sont utilisées pour modifier le comportement de PowerShell de nombreuses manières différentes. L’une de ces variables s’appelle $ErrorActionPreference.

La variable $ErrorActionPreference est utilisée pour modifier la façon dont PowerShell traite les erreurs non terminales. Par défaut, la valeur de $ErrorActionPreference est définie sur Continuer. Changer la valeur de la variable $ErrorActionPreference en STOP force PowerShell à traiter toutes les erreurs comme des erreurs terminales.

Utilisez le code ci-dessous pour changer la valeur de $ErrorActionPreference.

$ErrorActionPreference = "STOP"

Pour en savoir plus sur les autres valeurs valides de la variable $ErrorActionPreference, visitez la page PowerShell ErrorActionPreference.

À présent, reportez-vous à l’exemple utilisé dans la section Erreurs non terminales de cet article. Le script peut être modifié pour inclure le changement dans $ErrorActionPreference comme le code indiqué ci-dessous :

# Définir la valeur de $ErrorActionPreference sur STOP
$ErrorActionPreference = "STOP"
$file_list =  Get-Content .\filelist.txt
foreach ($file in $file_list) {
    Write-Output "Reading file $file"
    Get-Content $file
}

Exécuter le code modifié ci-dessus se comportera différemment qu’auparavant lorsque la valeur de $ErrorActionPreference est définie sur la valeur par défaut de Continuer.

Forcing a terminating error using the $ErrorActionPreference variable

Comme vous pouvez le voir sur la capture d’écran du résultat ci-dessus, le script a pu lire les cinq premiers fichiers de la liste, mais lorsqu’il a tenté de lire le fichier File_6.txt, une erreur est retournée car le fichier n’a pas été trouvé. Ensuite, le script s’est terminé et le reste des fichiers n’a pas été lu.

La valeur de $ErrorActionPreference n’est valide que dans la session PowerShell actuelle. Elle se réinitialise à la valeur par défaut dès qu’une nouvelle session PowerShell est démarrée.

Le paramètre commun ErrorAction

Si la valeur $ErrorActionPreference est appliquée à la session PowerShell, le paramètre ErrorAction s’applique à toute commande qui prend en charge les paramètres courants. Le paramètre ErrorAction accepte les mêmes valeurs que la variable $ErrorActionPreference.

La valeur du paramètre ErrorAction prévaut sur la valeur de $ErrorActionPreference.

Revenons en arrière et utilisons le même code que dans l’exemple précédent. Mais, cette fois, le paramètre ErrorAction est ajouté à la ligne Get-Content.

# Définir la valeur $ErrorActionPreference sur la valeur par défaut (CONTINUE)
$ErrorActionPreference = "CONTINUE"
$file_list =  Get-Content .\filelist.txt
foreach ($file in $file_list) {
    Write-Output "Reading file $file"
		# Utiliser le paramètre commun -ErrorAction
		Get-Content $file -ErrorAction STOP
}

Après avoir exécuté le code modifié, vous verrez que même si $ErrorActionPreference est défini sur Continue, le script s’est toujours arrêté une fois qu’il a rencontré une erreur. Le script s’est arrêté car la valeur du paramètre PowerShell ErrorAction dans Get-Content est définie sur STOP.

Forcing a terminating error using the PowerShell ErrorAction parameter

Utilisation des blocs Try Catch de PowerShell

À ce stade, vous avez appris à propos des erreurs PowerShell et comment fonctionnent la variable $ErrorActionPreference et les paramètres ErrorAction de PowerShell. Maintenant, il est temps que vous appreniez le bon truc – les blocs Try Catch Finally de PowerShell.

Blocs try catch PowerShell (et bloc finally facultatif) sont une manière d’encercler un morceau de code et de capturer les erreurs qui surviennent.

Le code ci-dessous montre la syntaxe de l’instruction Try.

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

Le bloc Try contient le code que vous souhaitez que PowerShell « essaie » et surveille pour les erreurs. Si le code dans le bloc Try rencontre une erreur, l’erreur est ajoutée à la variable $Error puis transmise au bloc Catch.

Le bloc Catch contient les actions à exécuter lorsqu’il reçoit une erreur du bloc Try. Il peut y avoir plusieurs blocs Catch dans une instruction Try.

Le bloc Finally contient le code qui s’exécutera à la fin de l’instruction Try. Ce bloc s’exécute qu’une erreur ait été rencontrée ou non.

Capture d’erreurs non spécifiques (Catch-All) avec PowerShell ErrorAction

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

Par exemple, pour capturer une exception non spécifique, le paramètre Catch devrait être vide. Le code d’exemple ci-dessous utilise le même script que celui utilisé dans la section Variable $ErrorActionPreference, mais modifié pour utiliser les blocs Try Catch.

Comme vous pouvez le voir dans le code ci-dessous, cette fois, la instruction foreach est encapsulée dans le bloc Try. Ensuite, un bloc Catch contient le code pour afficher la chaîne Une erreur est survenue si une erreur s’est produite. Le code dans le bloc Finally efface simplement la variable $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()
}

Le code ci-dessus, après son exécution dans PowerShell, vous donnera la sortie suivante.

Script terminated when an error occurred

La sortie ci-dessus montre que le script a rencontré une erreur, exécuté le code à l’intérieur du bloc Catch, puis s’est terminé.

L’erreur a été gérée, ce qui était le but de la gestion des erreurs. Cependant, l’erreur affichée était trop générique. Pour afficher une erreur plus descriptive, vous pourriez accéder à la propriété Exception de l’erreur qui a été transmise par le bloc Try.

Le code ci-dessous est modifié, spécifiquement le code à l’intérieur du bloc Catch, pour afficher le message d’exception de l’erreur actuelle qui a été transmise dans le 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()
}

Cette fois, lorsque le code modifié ci-dessus est exécuté, le message affiché est beaucoup plus descriptif.

Script terminated with a descriptive error message

Capturer des erreurs spécifiques

Il y a des moments où une gestion d’erreur générale n’est pas l’approche la plus appropriée. Peut-être que vous voulez que votre script effectue une action qui dépend du type d’erreur rencontré.

Comment déterminez-vous le type d’erreur? En vérifiant la valeur TypeName de la propriété Exception de la dernière erreur. Par exemple, pour trouver le type d’erreur de l’exemple précédent, utilisez cette commande:

$Error[0].Exception | Get-Member

Le résultat du code ci-dessus ressemblerait à la capture d’écran ci-dessous. Comme vous pouvez le voir, la valeur TypeName est affichée – System.Management.Automation.ItemNotFoundException.

Getting the error TypeName value

Maintenant que vous connaissez le type d’erreur que vous devez intercepter, modifiez le code pour le capturer spécifiquement. Comme vous pouvez le voir dans le code modifié ci-dessous, il y a maintenant deux blocs Catch. Le premier bloc Catch intercepte un type d’erreur spécifique (System.Management.Automation.ItemNotFoundException). En revanche, le deuxième bloc Catch contient le message d’erreur générique, attrape-tout.

$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 capture d’écran ci-dessous montre la sortie du code modifié ci-dessus.

Script terminated with a specific error message

Conclusion

Dans cet article, vous avez appris les erreurs dans PowerShell, ses propriétés et comment déterminer le type spécifique d’une erreur. Vous avez également appris la différence entre la variable $ErrorActionPreference et le paramètre ErrorAction de PowerShell et comment ils affectent le traitement des erreurs non terminales par PowerShell.

Vous avez également appris comment utiliser les blocs Try Catch Finally de PowerShell pour gérer les erreurs, que ce soit pour des erreurs spécifiques ou une approche attrape-tout.

Les exemples présentés dans cet article ne font que démontrer les bases de fonctionnement des blocs Try Catch Finally. Les connaissances que j’espère que vous avez acquises dans cet article devraient vous donner les bases nécessaires pour commencer à appliquer la gestion des erreurs dans vos scripts.

Lecture complémentaire

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