Gestion des erreurs en PowerShell
Erreurs terminantes et non terminantes
PowerShell distingue deux catégories d'erreurs. Les erreurs terminantes
(terminating errors) interrompent immédiatement l'exécution du bloc courant — ce sont
celles que try/catch peut attraper nativement. Les erreurs non
terminantes (non-terminating errors) affichent un message en rouge mais laissent
le script continuer ; elles sont écrites dans le flux $Error et
peuvent être promues en erreurs terminantes via -ErrorAction Stop.
| Type | Comportement par défaut | Capturable par try/catch ? |
|---|---|---|
| Terminante | Arrête le bloc courant | ✅ Oui |
| Non terminante | Continue l'exécution | ❌ Non (sauf avec -ErrorAction Stop) |
$ErrorActionPreference
Cette variable globale contrôle le comportement par défaut de toutes les erreurs non terminantes dans votre session ou script :
# Valeurs possibles :
$ErrorActionPreference = 'Continue' # Défaut : affiche l'erreur et continue
$ErrorActionPreference = 'Stop' # Transforme toutes les erreurs en terminantes
$ErrorActionPreference = 'SilentlyContinue' # Masque l'erreur, continue silencieusement
$ErrorActionPreference = 'Inquire' # Demande confirmation à l'utilisateur
# Bonne pratique en début de script robuste :
$ErrorActionPreference = 'Stop'
Vous pouvez aussi surcharger ce comportement pour une seule cmdlet via le paramètre
commun -ErrorAction :
# N'affiche pas l'erreur si le fichier est absent
Get-Item 'C:\inexistant.txt' -ErrorAction SilentlyContinue
# Force la capture par try/catch pour cette cmdlet uniquement
Get-Item 'C:\inexistant.txt' -ErrorAction Stop
try / catch / finally
Le bloc try contient le code susceptible de lever une erreur terminante.
Le bloc catch est exécuté si une erreur est interceptée.
Le bloc finally s'exécute toujours, qu'il y ait eu erreur ou non.
try {
$contenu = Get-Content 'C:\data\config.json' -ErrorAction Stop
$json = $contenu | ConvertFrom-Json
Write-Host "Fichier chargé : $($json.nom)"
}
catch [System.IO.FileNotFoundException] {
Write-Warning "Fichier introuvable : $_"
}
catch [System.Exception] {
Write-Error "Erreur inattendue : $($_.Exception.Message)"
}
finally {
Write-Host 'Nettoyage terminé.' -ForegroundColor DarkGray
}
Le paramètre $_ dans le bloc catch contient l'objet
ErrorRecord courant. Ses propriétés les plus utiles :
catch {
$_.Exception.Message # Message d'erreur lisible
$_.Exception.GetType().FullName # Type .NET de l'exception
$_.ScriptStackTrace # Pile d'appels PowerShell
$_.InvocationInfo.Line # Numéro de ligne
$_.FullyQualifiedErrorId # Identifiant unique de l'erreur
}
Attraper plusieurs types d'exceptions
try {
$result = Invoke-WebRequest 'https://api.exemple.com/data' -ErrorAction Stop
}
catch [System.Net.WebException] {
Write-Warning "Problème réseau : $($_.Exception.Message)"
}
catch [System.UnauthorizedAccessException] {
Write-Error 'Accès refusé. Vérifiez vos permissions.'
}
catch {
# Filet de sécurité : attrape tout le reste
Write-Error "Erreur non gérée : $_"
}
La variable $Error
PowerShell maintient automatiquement un historique des erreurs dans la variable
automatique $Error, qui est une liste circulaire de 256 entrées par défaut.
$Error[0] # Dernière erreur survenue
$Error[0].Exception.Message
$Error.Count # Nombre d'erreurs dans l'historique
$Error.Clear() # Vider l'historique
# Changer la taille de l'historique
$MaximumErrorCount = 50
Write-Error vs Throw
Deux manières de générer manuellement une erreur, avec des comportements différents :
# Write-Error : génère une erreur NON terminante (le script continue)
Write-Error "Paramètre invalide : $Valeur"
# Throw : génère une erreur TERMINANTE (capturable par try/catch)
throw "Le fichier de configuration est manquant."
# Throw avec un objet exception typé
throw [System.IO.FileNotFoundException] "config.json introuvable"
-ErrorVariable
Le paramètre commun -ErrorVariable capture les erreurs d'une cmdlet
dans une variable de votre choix, sans interrompre l'exécution :
Get-Item 'C:\inexistant.txt' -ErrorAction SilentlyContinue -ErrorVariable monErreur
if ($monErreur) {
Write-Warning "Erreur capturée : $($monErreur[0].Exception.Message)"
}
Exemple pratique : script robuste de sauvegarde
Un script réel qui illustre toutes ces techniques ensemble :
#Requires -Version 5.1
[CmdletBinding()]
param(
[Parameter(Mandatory)][string] $Source,
[Parameter(Mandatory)][string] $Destination,
[string] $LogFile = 'C:\Logs\backup.log'
)
$ErrorActionPreference = 'Stop'
function Write-Log {
param([string]$Message, [string]$Niveau = 'INFO')
$ligne = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] [$Niveau] $Message"
Add-Content -Path $LogFile -Value $ligne
Write-Host $ligne -ForegroundColor $(if ($Niveau -eq 'ERROR') {'Red'} else {'Gray'})
}
try {
Write-Log "Début de la sauvegarde : $Source → $Destination"
if (-not (Test-Path $Source)) {
throw "Dossier source introuvable : $Source"
}
if (-not (Test-Path $Destination)) {
New-Item -Path $Destination -ItemType Directory | Out-Null
Write-Log "Dossier de destination créé : $Destination"
}
$fichiers = Get-ChildItem -Path $Source -Recurse -File
$compteur = 0
foreach ($fichier in $fichiers) {
try {
$cible = $fichier.FullName.Replace($Source, $Destination)
$dossierCible = Split-Path $cible
if (-not (Test-Path $dossierCible)) {
New-Item -Path $dossierCible -ItemType Directory | Out-Null
}
Copy-Item -Path $fichier.FullName -Destination $cible -Force
$compteur++
}
catch {
Write-Log "Impossible de copier $($fichier.Name) : $_" -Niveau 'ERROR'
# On continue malgré l'erreur sur ce fichier
}
}
Write-Log "Sauvegarde terminée : $compteur fichier(s) copié(s)."
}
catch {
Write-Log "ERREUR CRITIQUE : $_" -Niveau 'ERROR'
exit 1
}
finally {
Write-Log "Script terminé."
}