PowerShell est le principal langage de ligne de commande et de script utilisé par les systèmes d’exploitation Windows. Il permet d’exécuter des programmes et d’effectuer des tâches d’administration système depuis le terminal, et il est largement utilisé par les administrateurs système et les développeurs pour automatiser leurs flux de travail.
La gestion des erreurs est un élément essentiel de tout script et de toute automatisation. En cas de problème, vos scripts PowerShell ne doivent pas simplement planter. Ils doivent identifier qu’une erreur s’est produite, puis agir : relancer la tâche ou vous avertir qu’un incident est survenu afin que vous puissiez en trouver et en corriger la cause.
Ce guide vous apportera une compréhension détaillée de la gestion des erreurs PowerShell : types d’erreurs, techniques de traitement, exemples d’implémentation dans vos scripts et bonnes pratiques pour lever, intercepter, journaliser et traiter les erreurs.
Pour un aperçu rapide, regardez ce guide vidéo : Guide complet de la gestion des erreurs PowerShell.
De réactif, passez à proactif ! Découvrez comment passer à une gestion proactive de l’informatique grâce à notre guide étape par étape. Le consulter.
Les différents types d’erreurs dans PowerShell
Il existe deux types d’erreurs, qui doivent être traitées différemment pour garantir la fiabilité de vos scripts PowerShell.
Les erreurs avec fin d’exécution interrompent l’exécution de votre commande ou de votre script. Il s’agit généralement d’exceptions, que l’on peut traiter à l’aide de blocs try/catch (expliqués plus loin dans cet article). Ces erreurs proviennent notamment d’erreurs de syntaxe (commande mal saisie ou paramètres non valides) et d’erreurs internes à l’application ou à la commande exécutée.
Les erreurs sans fin d’exécution n’interrompent pas l’exécution de votre commande ou de votre script : celui-ci continue de s’exécuter après l’erreur. En général, une erreur sans fin d’exécution affiche un message d’erreur avant que l’exécution ne reprenne. Elle doit être traitée autrement qu’une erreur avec fin d’exécution, afin de ne pas provoquer de dysfonctionnement si le résultat attendu est nécessaire plus tard. Ces erreurs peuvent être dues à des délais d’attente réseau, à des fichiers manquants ou à des problèmes d’autorisations : sans être des exceptions critiques ni des erreurs d’exécution à proprement parler, elles entraînent un comportement inattendu si elles ne sont pas traitées.
Notions de base de la gestion des erreurs PowerShell (try, catch, finally et $ErrorActionPreference)
Les erreurs avec fin d’exécution et les exceptions sont levées (l’erreur se produit) puis interceptées (du code est exécuté pour traiter l’erreur). Une erreur non interceptée interrompt l’exécution de votre script PowerShell. En encapsulant votre code dans des blocs try , catch et finally, vous pouvez gérer ce type d’erreurs.
Si le code exécuté dans un bloc try lève une erreur, le code du bloc catch correspondant s’exécute pour la traiter (et permettre, le cas échéant, la poursuite de l’exécution). Toutes les tâches de nettoyage que vous souhaitez exécuter, qu’une erreur soit survenue ou non, peuvent être placées dans un bloc finally. Un exemple de code complet est fourni plus bas sur cette page.
La gestion des erreurs sans fin d’exécution fonctionne différemment : aucune erreur n’est levée pour interrompre l’exécution, elle ne peut donc pas être interceptée. L’erreur est en revanche stockée dans la variable $Error, un tableau d’erreurs accessible à tout moment dans vos scripts PowerShell pour vérifier si une instruction précédente a généré une erreur sans fin d’exécution, comme dans cet exemple :
Get-ChildItem -Path "C:fake_path"
if ($Error) {
Write-Host "Error occurred: $($Error[0])" # Display the most recent error as a string
$Error.Clear() # Clear the error
}Ci-dessus, la commande PowerShell Get-ChildItem génère une erreur sans fin d’exécution si le chemin de système de fichiers fourni n’existe pas (ici C :fake_path). L’erreur est enregistrée dans la variable $Error, qui est ensuite vérifiée et traitée.
Si vous souhaitez affecter la sortie d’erreur d’une commande donnée à une variable personnalisée, utilisez le paramètre -ErrorVariable (notez que, dans ce cas, la variable d’erreur n’est pas un tableau) :
Get-ChildItem -Path "C:fake_path" -ErrorVariable customError
if ($customError) {
Write-Host "Error occurred: $customError" # Display the error as a string
}Vous pouvez également convertir les erreurs sans fin d’exécution en erreurs avec fin d’exécution et les traiter avec des blocs try/catch. Pour appliquer ce comportement à toutes les erreurs sans fin d’exécution rencontrées dans votre script, définissez la variable globale $ErrorActionPreference sur Stop :
$ErrorActionPreference = "Stop"
Si vous ne souhaitez le faire que pour une seule commande, utilisez le paramètre -ErrorAction :
Get-ChildItem -Path "C:fake_path" -ErrorAction Stop
Implémenter des blocs try/catch/finally dans PowerShell
Voici un exemple de script PowerShell qui illustre la syntaxe et la structure des blocs try/catch/finally, montrant comment utiliser plusieurs blocs catch pour différents types d’exceptions et comment recourir à un bloc finally pour nettoyer et traiter les erreurs restantes. Commençons par une seule erreur traitée à l’aide d’un bloc try/catch :
try {
# Attempt a file operation that fails
Get-Content -Path "C:fake_pathfake_file.txt" -ErrorAction Stop
} catch {
Write-Host "Exception caught: $($_.Exception.Message)"
}Vous pouvez aussi traiter plusieurs types d’erreurs potentielles dans un même bloc try, chacune avec son propre bloc catch :
try {
# Each of the below commands will throw a terminating error of a different type
Get-Content -Path "C:fake_pathfake_file.txt" -ErrorAction Stop # Attempt a file operation that fails to throw a ItemNotFoundException
$null.fakeFunction() # Attempt to run a non-existent method on a null object to throw a RuntimeException
$divideZero = 1/0 # Divide by zero to throw an exception that won't be specifically caught
} catch [System.Management.Automation.ItemNotFoundException] { # Catch the specific error thrown by Get-Content
Write-Host "Item not found exception caught: $($_.Exception.Message)"
} catch [System.Management.Automation.RuntimeException] { # Catch the specific error thrown by $null.fakeFunction
Write-Host "Runtime exception caught: $($_.Exception.Message)"
} catch { # Catch all other errors
# General catch block for any other exceptions
Write-Host "General exception caught: $($_.Exception.Message)"
} finally { # The finally block is always executed whether an exception was thrown or not.
Write-Host "Executing the finally block."
$Error.Clear() # This could, for example, be used to clean up non-terminating errors.
}Le rôle de chaque instruction est expliqué dans le code, afin que vous puissiez voir dans son contexte complet la façon dont les instructions try, catch et finally fonctionnent ensemble. Notez que, lorsque plusieurs erreurs avec fin d’exécution surviennent dans le même bloc try, seule la première est interceptée et traitée, avant que le bloc finally ne s’exécute. Une fois cette erreur corrigée, les erreurs suivantes seront interceptées lors de l’exécution du script.
Techniques avancées de gestion des erreurs et exemples
Il est également possible d’imbriquer des blocs try/catch, de sorte que les erreurs « remontent » à travers eux. Vous pouvez ainsi traiter des erreurs précises dans les blocs try/catch internes, et traiter dans les blocs externes toutes les erreurs non interceptées ou relevées, y compris celles provenant de vos blocs catch internes. Par exemple, vous pourriez utiliser des blocs imbriqués pour traiter des erreurs spécifiques, puis un seul bloc externe pour intercepter et journaliser toutes les erreurs, plutôt que de répéter le code de journalisation dans chaque bloc catch interne.
try { # Beginning of the outer catch block
try { # Beginning of the inner catch block
# Include potentially error-causing code here
Get-Content -Path "C:fake_pathfake_file.txt" -ErrorAction Stop
} catch [System.Management.Automation.ItemNotFoundException] { # Catch statement for the inner catch block that specifically handles ItemNotFoundException
Write-Host "Inner try block file not found exception caught: $($_.Exception.Message)"
} catch { # Catch statement for the inner catch block that handles all other exceptions
Write-Host "Inner try block exception caught: $($_.Exception.Message)"
throw # Re-throw the exception so that it will bubble up to the outer try/catch block
}
} catch { # Catch statement for the outer catch block
Write-Host "Outer try block exception caught: $($_.Exception.Message)" # Handle all errors re-thrown in the inner catch blocks here for clean up, logging, and alerting tasks
}Notez que, dans l’exemple ci-dessus, l’exception ItemNotFoundException n’est pas relevée : elle ne remontera donc pas jusqu’au bloc catch externe.
À mesure que vous étofferez vos scripts PowerShell pour couvrir vos propres cas d’usage, vous voudrez sans doute pouvoir introduire vos propres exceptions personnalisées et vos propres enregistrements d’erreur PowerShell :
try {
$customException = New-Object Exception "This is a custom error!" # Create and throw a custom error
# Create a custom Error Record
$customErrorRecord = New-Object System.Management.Automation.ErrorRecord (
$customException,
"CustomErrorID",
[System.Management.Automation.ErrorCategory]::NotSpecified, # Sets the ErrorRecord category to NotSpecified
$null # Specify no specific target object for this error
)
throw $customErrorRecord
} catch {
# Catch and handle the custom error record
Write-Host "Error Message: $($_.Exception.Message)"
Write-Host "Error ID: $($_.FullyQualifiedErrorId)"
}Ci-dessus, vous pouvez constater qu’aucun objet cible n’est spécifié (puisqu’il est défini sur $null). Vous pourriez le remplacer par un chemin de fichier ou une autre référence, et enrichir le texte de l’exception afin de rendre l’erreur personnalisée plus informative.
Bonnes pratiques de gestion des erreurs PowerShell
Plusieurs bonnes pratiques sont à respecter lors de l’écriture de vos scripts PowerShell pour garantir une gestion des erreurs efficace :
- Rédigez des messages d’erreur clairs et prévisibles : vos messages d’erreur doivent être explicites et comporter suffisamment d’informations issues de l’exception ou de l’objet ErrorRecord pour identifier la cause précise de l’erreur.
- Faites en sorte que vos scripts puissent poursuivre leur exécution (ou se terminer proprement) en cas d’erreur : si vos scripts exécutent d’autres tâches, vous voudrez peut-être traiter l’erreur tout en les laissant se poursuivre. Les erreurs qui empêchent votre script de continuer doivent le faire sortir avec un code de sortie, et le résultat de toute erreur doit être journalisé et signalé.
- Testez régulièrement votre infrastructure de gestion des erreurs et de reporting : vos automatisations PowerShell ne servent à rien si elles échouent sans que vous vous en rendiez compte. Testez régulièrement vos scripts en y introduisant des erreurs pour vérifier que leur traitement fonctionne, que les détails sont journalisés et que vous recevez bien une alerte.
La gestion des erreurs est une fonction importante de l’écriture de scripts PowerShell et vous sera utile pendant que vous développerez vos compétences en script et en automatisation. Une implémentation correcte de la gestion des erreurs, qui passe notamment par une levée correcte des erreurs, l’utilisation des blocs try/catch/finally et le recours à $ErrorActionPreference, vous aidera à apprendre la syntaxe PowerShell, vous donnera une meilleure visibilité sur les problèmes rencontrés par vos scripts et vous permettra de mieux les gérer.
