Magic Quadrant™ pour la gestion des accès privilégiés 2025 : Netwrix reconnue pour la quatrième année consécutive. Téléchargez le rapport.

Plateforme
Centre de ressourcesBlog
Guide de gestion des erreurs avec PowerShell Try-Catch

Guide de gestion des erreurs avec PowerShell Try-Catch

Mar 9, 2025

La gestion des erreurs PowerShell utilise des blocs Try-Catch-Finally pour gérer les erreurs terminantes et non terminantes, assurant la fiabilité des scripts en exécution non surveillée. Try encadre le code à risque, Catch répond aux exceptions et Finally nettoie les ressources. Avec des options comme -ErrorAction, $ErrorActionPreference, et $Error, les administrateurs peuvent imposer une gestion stricte, capturer des messages d'erreur détaillés et automatiser la récupération. Cette approche réduit le temps d'arrêt, prévient la perte de données et permet un scriptage résilient à grande échelle.

Introduction à la gestion des erreurs dans PowerShell

De nombreux scripts PowerShell sont conçus pour s'exécuter de manière autonome, il est donc essentiel de s'assurer qu'ils peuvent gérer les erreurs de manière fluide. Une gestion appropriée des erreurs aide à prévenir une grande variété de problèmes, allant des opérations incomplètes et des temps d'arrêt du système à la perte de données. La gestion des erreurs doit prendre en compte à la fois les erreurs terminales, qui arrêtent l'exécution du script, et les erreurs non terminales, qui permettent au script de continuer à s'exécuter mais peuvent affecter le résultat.

L'un des mécanismes les plus utiles pour la gestion des erreurs dans PowerShell est le bloc Try-Catch-Finally. Le bloc Try contient du code qui pourrait générer une exception. Si cela se produit, le contrôle est transféré au bloc Catch, qui gère l'erreur en prenant des mesures telles que l'ignorance d'un fichier problématique ou d'une entrée invalide, ainsi que la consignation de l'événement. Le bloc Finally s'exécute toujours, effectuant des tâches de nettoyage telles que la fermeture de fichiers, la libération de ressources ou la consignation d'informations. Par exemple, créer des messages d'erreur détaillés pour Try Catch dans PowerShell peut vous permettre de prendre les mesures appropriées pour résoudre les problèmes.

Ce document offre une analyse approfondie des blocs Try-Catch-Finally. En cours de route, nous aborderons également d'autres méthodes de gestion des erreurs dans PowerShell, y compris l'utilisation du paramètre ErrorAction pour contrôler la manière dont les cmdlets réagissent aux erreurs et l'utilisation de la variable $Error pour stocker l'historique des erreurs.

Quelles sont les erreurs dans PowerShell ?

Les erreurs sont des événements qui peuvent affecter le déroulement normal de l'exécution d'un script ou peuvent l'arrêter complètement. Les causes courantes d'erreurs incluent une syntaxe incorrecte, des fichiers manquants, des permissions insuffisantes ou des ressources indisponibles. Il existe deux types principaux d'erreurs, les erreurs terminales et les erreurs non terminales.

Erreurs fatales : Erreurs critiques qui arrêtent le script

Les erreurs fatales arrêtent immédiatement l'exécution du script à moins qu'elles ne soient correctement gérées. Ces erreurs se produisent lorsque PowerShell rencontre un problème dont il ne peut se remettre, tel qu'une erreur de syntaxe, l'appel d'une variable ou d'un fichier qui n'existe pas, ou l'absence de permissions suffisantes pour réaliser l'opération demandée.

Par exemple, le script ci-dessous tente d'obtenir le fichier users.txt :

      Get-Content C:\users.txt | Get-ADUser -Properties name | Select-Object -Property SamAccountName,name
      

Si ce fichier n'existe pas à l'emplacement spécifié ou si le compte exécutant le script n'a pas les autorisations pour y accéder, le script générera une erreur fatale, interrompant l'opération du script comme indiqué ici :

Image

Erreurs non terminales : erreurs qui permettent au script de continuer

Les erreurs non terminales dans PowerShell sont des erreurs qui n'arrêtent pas l'exécution du script. Ces erreurs sont généralement générées par des cmdlets qui tentent de traiter plusieurs objets, où un échec ne stoppe pas nécessairement tout le script.

Par exemple, supposons que nous exécutons le script utilisé dans l'exemple précédent mais maintenant le fichier existe et nous avons les permissions pour y accéder. Cependant, nous n'avons pas de connectivité à un contrôleur de domaine. Dans ce cas, la première commande s'exécutera et obtiendra le contenu du fichier. Cependant, la commande suivante échouera, générant des erreurs non-terminales pour chacun des trois objets dans le fichier.

Image

Supposons maintenant que la connectivité du contrôleur de domaine soit rétablie, mais qu'un objet dans le fichier ait un nom d'utilisateur invalide. L'exécution du script générera l'erreur non terminale affichée ci-dessous pour l'objet, mais les autres objets seront traités par le script.

Image

Où les erreurs sont stockées : la variable $Error

$Error est un tableau automatique qui stocke les erreurs récentes rencontrées lors de l'exécution d'un script, ce qui le rend très utile pour le débogage et la résolution des problèmes. L'erreur la plus récente est stockée à l'indice [0].

Par exemple, lorsque le script suivant tente de récupérer un fichier inexistant, il récupère l'erreur résultante de $Error et l'affiche avec un message convivial :

      # trying to get a file which doesn't exist, and an error is generated.

Get-Item "C:\file44.txt"

# Display a message along with the last error.

Write-Host "Oops! Something went wrong Here's the error: $($Error[0])"
      
Image

Comprendre les blocs Try, Catch et Finally

Une bonne manière de gérer les erreurs en douceur est de mettre en œuvre des blocs Try-Catch-Finally.


Bloc Try : Où réside le code potentiellement sujet aux erreurs

Le bloc Try encadre le code qui pourrait générer une erreur. Par exemple, le script suivant est conçu pour arrêter le processus Notepad. Le bloc Try arrêtera ce processus s'il est en cours d'exécution, mais s'il ne l'est pas, l'exécution passera au bloc Catch, empêchant ainsi le script de planter.

      try {

    # Attempt to stop a process that may not be running

    Stop-Process -Name "Notepad" -ErrorAction Stop

    # If no error occurs, this line will execute

    Write-Host "Notepad process stopped successfully."

}

catch {

    # Handle the error gracefully

    Write-Host "Oops! Could not stop the process. Error: $($_.Exception.Message)"

}
      
Image

Bloc de capture : Gestion des erreurs lorsqu'elles surviennent

Le bloc Catch est utilisé pour gérer les exceptions qui surviennent dans le bloc Try. Dans l'exemple suivant de PowerShell Try Catch, le script invite l'utilisateur à entrer un nombre, divise 10 par ce nombre et imprime le résultat. Cependant, si le nombre entré est 0, la tentative de division entraînera une erreur, car il n’est pas possible de diviser par zéro. Dans ce cas, le bloc Catch s'exécutera et imprimera un message d'erreur au lieu d'un nombre.

      try {

    $number = [int](Read-Host "Enter a number")

    Write-Output "Result: $(10 / $number)"

}

catch {

    Write-Output "Error: Invalid input or division by zero!"

}

finally {

    Write-Output "Program execution completed."

}
      
Image

Bloc finally : Code qui s'exécute toujours, qu'une erreur se produise ou non

Le bloc Finally sera toujours exécuté, que une exception ait été levée ou non.

For instance, the following script defines an array with just three elements but attempts to print the fifth element; this exception is handled in the Catch block, which prints an error. However, the Finally block is also executed, so an additional message is printed.

      try {

    # Define an array

    $numbers = @(1, 2, 3)

    # Access an invalid index using a .NET method that throws an exception

    $value = $numbers.GetValue(5) 

    Write-Host "Value: $value"

}

catch [System.IndexOutOfRangeException] {

    # Handle the specific exception

    Write-Host "Error: Index out of range exception caught."

}

finally {

    # This block always executes

    Write-Host "Execution completed."

}
      
Image

Exemple avancé : Utilisation de plusieurs blocs catch pour différents types d'exceptions

Un script peut inclure plusieurs blocs Catch pour gérer différents types d'exceptions, permettant ainsi une gestion des erreurs plus granulaire. En effet, le framework .Net fournit un ensemble riche de types de messages d'exception PowerShell Try Catch , y compris les suivants :

  • System.DivideByZeroException — Se produit lorsqu'une tentative est faite de diviser un nombre par zéro
  • System.FormatException — Se produit lors de la tentative de conversion d'une entrée non numérique en nombre
  • System.ArgumentNullException — Se produit lorsqu'un argument passé est null mais ne devrait jamais être null 
  • System.IO.IOException — Levée lorsqu'une erreur d'E/S se produit

Par exemple, le script suivant demande à l'utilisateur d'entrer deux nombres, les convertit en format entier, divise le premier nombre par le second et affiche le résultat. Le premier bloc Catch gère la possibilité que l'entrée de l'utilisateur ne puisse pas être convertie en format entier, et le second bloc Catch gère la possibilité de tenter de diviser par zéro.

      try {

    # Prompt user for first input

    $num1 = Read-Host "Enter the first number"

    $num1 = [int]$num1  # Convert to integer (may cause FormatException)

    # Prompt user for second input

    $num2 = Read-Host "Enter the second number"

    $num2 = [int]$num2  # Convert to integer (may cause FormatException)

    # Perform division (may cause DivideByZeroException)

    $result = $num1 / $num2

    # Print result

    Write-Host "Result: $result"

}

catch [System.FormatException] {

    # Handling invalid input error

    Write-Host "Error: Please enter only numeric values!"

}

catch [System.DivideByZeroException] {

    # Handling division by zero error

    Write-Host "Error: Cannot divide by zero!"

}

catch {

    # Handling unexpected errors

    Write-Host "An unexpected error occurred: $_"

}

finally {

    # Code that always runs

    Write-Host "Execution completed."

}
      
Image

Techniques avancées de gestion des erreurs


Pour créer des scripts plus robustes et maintenables, envisagez d'utiliser les techniques de gestion des erreurs suivantes en combinaison avec les blocs PowerShell Try and Catch :

  • Utilisez $ErrorActionPreference = “Stop” pour garantir que toutes les erreurs sont traitées comme terminales, ce qui les rend plus faciles à attraper.
  • Utilisez -ErrorAction Stop sur des commandes individuelles pour permettre un contrôle plus granulaire sans affecter le script entier.
  • Utilisez $_.Exception.Message et $PSItem pour accéder aux détails des erreurs.

Interception d'exceptions spécifiques


Le script suivant est destiné à convertir une entrée d'utilisateur en un entier puis à exécuter une commande. Le premier bloc Catch gère la possibilité d'une entrée utilisateur invalide, et le second gère les tentatives d'exécution d'une commande invalide. Si l'une ou l'autre exception se produit, le script affiche un message personnalisé.

      try {

    # Attempt to convert user input to an integer (may throw FormatException)

    $number = Read-Host "Enter a number"

    $number = [int]$number 

    # Try running a non-existent command (may throw CommandNotFoundException)

    NonExistent-Command 

}

catch [System.FormatException] {

    Write-Host "Error: Invalid input. Please enter a valid number."

}

catch [System.Management.Automation.CommandNotFoundException] {

    Write-Host "Error: Command not found. Please check the command name."

}

catch {

    Write-Host "An unexpected error occurred: $_"

}

finally {

    Write-Host "Execution completed."

}
      
Image

Utilisation de $_.Exception.Message et $PSItem pour accéder aux détails des erreurs

Pour accéder aux détails des erreurs dans un bloc Catch, vous pouvez utiliser les variables suivantes :

  • $_.Exception.Message fournit un message d'erreur Try Catch PowerShell clair et convivial, ne présentant que la partie pertinente de l'erreur.
  • $PSItem contient l'objet d'erreur complet, y compris le type d'erreur, la source et la trace de la pile.

Le script suivant illustre la différence dans le résultat fourni par ces variables :

      try {

    # Attempt to open a non-existent file

    Get-Content "C:\File1.txt" -ErrorAction Stop

}

catch {

    # Using $_.Exception.Message to get detailed error information

    Write-Host "Error occurred: $($_.Exception.Message)"

    # Using $PSItem (same as $_) to display full error details

    Write-Host "Full Error Details: $PSItem"

}

finally {

    Write-Host "Execution completed."

}
      
Image

Utilisation des instructions Trap

Une instruction Trap définit le code qui est exécuté lorsqu'une erreur spécifique se produit, indépendamment de l'endroit dans le script où l'erreur survient. En conséquence, elle fournit un mécanisme pour gérer les erreurs à un niveau supérieur (global) que les blocs individuels de PowerShell Try-Catch.

Le script suivant utilise Try-Catch dans PowerShell pour gérer la possibilité d'une tentative de division par zéro. L'instruction Trap interceptera toute autre erreur qui pourrait survenir, ce qui dans ce cas est l'utilisation de la cmdlet Get-Item avec un fichier qui n'existe pas.

      # Global error handler using trap

trap {

    Write-Host "Global Error Handler (trap): $_"

    continue  # Allows the script to continue execution

}

function Test-TryCatch {

    try {

        Write-Host "Inside Try Block"

        1 / 0  # This will cause a division by zero error

        Write-Host "This line will not execute due to the error above."

    } catch {

        Write-Host "Caught in Try-Catch: $_"

    }

}

Write-Host "Before function call"

Test-TryCatch

Write-Host "After function call"

# Triggering another error outside try-catch to see if trap works

Write-Host "Triggering an error outside Try-Catch"

Get-Item "C:\NonExistentFile.txt" -ErrorAction Stop  # Force a terminating error

Write-Host "Script completed"
      

Gestion des erreurs non terminales dans PowerShell

Catch blocks are designed to handle terminating errors; since non-terminating errors don’t stop script execution, they don’t trigger Catch block. However, we can convert non-terminating errors into terminating errors using the -ErrorAction Stop parameter. This parameter forces the script to treat non-terminating error as terminating errors, which will allow Catch blocks to handle them appropriately.

Supposons que nous exécutions le script suivant mais que le dossier auquel il tente d'accéder n'existe pas. Le bloc Try utilise -ErrorAction Stop pour convertir cette erreur non terminale en erreur terminale afin qu'elle soit gérée par le bloc Catch.

      $directoryPath = "C:\NonExistentFolder"

try {

    Write-Host "Checking if directory exists..."

    Get-ChildItem -Path $directoryPath -ErrorAction Stop  # Force a terminating error if the directory doesn't exist

    Write-Host "Directory found."

} catch {

    Write-Host "Error: The directory '$directoryPath' was not found."

}
      
Image

Meilleures pratiques pour utiliser Try-Catch dans PowerShell

Pour maximiser la clarté, l'efficacité et la maintenabilité de votre code, concevez soigneusement votre bloc de gestion des erreurs. En particulier, Try-Catch doit être utilisé uniquement pour de véritables exceptions. Limiter le code dans le bloc Try aux opérations susceptibles de générer une exception facilite l'identification de la source des exceptions et le débogage du script. Dans les autres cas, envisagez d'utiliser des instructions if-else ou switch.

Parmi les autres meilleures pratiques clés, on trouve les suivantes :

  • Assurez-vous que le code à l'intérieur du bloc Try respecte le principe de responsabilité unique, ce qui signifie que chaque partie du code effectue une tâche spécifique.
  • Utilisez des blocs Catch séparés pour gérer différents types d'exceptions.
  • Incluez toujours un bloc Finally pour nettoyer le code et libérer les ressources.

Le script suivant illustre certaines de ces meilleures pratiques. Il utilise une instruction if avec test-path pour vérifier si un fichier existe avant de tenter d'y accéder. Si le fichier n'existe pas, l'erreur est affichée à l'aide de l'instruction else. Le bloc Try-Catch est utilisé uniquement pour lire le contenu du fichier ; si le script rencontre une erreur comme un manque de permissions, le bloc Catch gérera l'exception et affichera un message d'erreur.

      # Define the path to the file

$filePath = "D:\NonExistentFile.txt"

# Check if the file exists

if (Test-Path -Path $filePath) {

    try {

        # Try to read the file contents

        $fileContents = Get-Content -Path $filePath -ErrorAction Stop

        Write-Host "File contents: $fileContents"

    }

    catch {

        # Handle any exceptions that occur while reading the file

        Write-Host "Error: Unable to read the file. Exception Message: $_"

    }

} else {

    # If the file does not exist, display an error message

    Write-Host "Error: The file does not exist."

}
      
Image

PowerShell Try-Catch et Continuation de Script

Utilisation des instructions Continue

Lorsqu'un script rencontre une erreur dans un bloc Try-Catch, le comportement par défaut est de gérer l'exception dans le bloc Catch et d'arrêter l'exécution. Cependant, il existe des scénarios où nous souhaitons continuer l'exécution après avoir géré l'erreur, comme lors du traitement d'un lot de fichiers ou du test de connexions à plusieurs serveurs.

Pour garantir qu'une seule défaillance n'arrête pas toute l'itération, utilisez une instruction Continue. Par exemple, le script suivant teste la connexion de plusieurs serveurs ; l'instruction Continue assure que l'exécution se poursuivra même si une erreur se produit sur un serveur.

      # List of server names (replace with actual server names or IPs)

$servers = @("lhehost9", "lhehost11", "lhehost10")

foreach ($server in $servers) {

    try {

        Write-Host "Attempting to connect to $server..."

        # Simulating a remote connection (Replace with actual connection command)

        Test-Connection -ComputerName $server -Count 2 -ErrorAction Stop

        Write-Host "Successfully connected to $server.`n"

    } catch {

        Write-Host "Error: Failed to connect to $server. Skipping to next server...`n"

        continue  # Continue to the next server in the loop

    }

}

Write-Host "Script execution completed."
      
Image

Utilisation de la variable $ErrorActionPreference

Une autre manière de forcer l'exécution d'un script à continuer après une erreur est d'utiliser la variable $ErrorActionPreference. Alors que les blocs Try-Catch permettent une gestion localisée des erreurs, $ErrorActionPreference est un paramètre global qui contrôle la réponse de PowerShell aux erreurs non terminales.

Nous avons déjà vu que vous pouvez définir $ErrorActionPreference à “Stop” afin de garantir que toutes les erreurs soient traitées comme terminales et ainsi les rendre plus faciles à attraper. Cependant, cette variable a des paramètres supplémentaires, y compris Continue (le paramètre par défaut), SilentlyContinue, Inquire et Ignore. En choisissant le paramètre pour cette variable, vous pouvez définir comment les erreurs sont gérées à travers le script.


Bloc Finally de PowerShell : Assurer le nettoyage des ressources

Comme mentionné précédemment, le bloc Finally s'exécute après les blocs Try et Catch, que une erreur se soit produite ou non pendant l'exécution du script. Il est souvent utilisé pour des processus de nettoyage tels que la fermeture de fichiers, la terminaison de connexions et la libération de ressources.

Par exemple, le script suivant ouvre un fichier et y écrit « hello world ». Si une erreur se produit, le bloc Catch affichera un message. Dans tous les cas, le bloc Finally s'assurera que le flux de fichier est fermé pour éviter toute fuite de ressources.

      try {

    $filePath = "D:\Office\Backup\eventviewer_logs.txt"

    $fileStream = [System.IO.StreamWriter]::new($filePath)

    $fileStream.WriteLine("Hello, World!")

}

catch {

    Write-Host "An error occurred: $_"

}

finally {

    if ($fileStream) {

        $fileStream.Close()

        Write-Host "File stream closed successfully."

    }

}
      

Handling Multiple Errors in PowerShell
Variables that Store and Count Errors

PowerShell fournit deux variables qui sont très utiles pour l'audit et le débogage de scripts qui rencontrent plusieurs exceptions :

  • $Error conserve une liste des erreurs rencontrées pendant une session.
  • $Error.count indique le nombre total d'erreurs enregistrées dans la session en cours.

Pour un suivi précis, il peut être nécessaire de vider la liste des erreurs de temps à autre pendant une session. Utiliser $Error.clear() supprimera toutes les erreurs stockées.


Utilisation de blocs Try-Catch imbriqués pour gérer plusieurs erreurs

Le script suivant inclut deux blocs Try-Catch imbriqués pour gérer deux erreurs potentielles différentes, en essayant de diviser par zéro et en essayant d'accéder à un fichier non-existant :

      try {

    Write-Host "Starting First try block..."

    try {

        Write-Host "Attempting to divide by zero..."

        $result = 1 / 0  # This will cause a divide-by-zero exception

    }

    catch [System.DivideByZeroException] {

        Write-Host "Inner catch: Division by zero error occurred"

        throw "Re-throwing error to outer try block"

    }

    try {

        Write-Host "Accessing a file that doesn't exist..."

        Get-Content -Path "C:\File1.txt" -ErrorAction Stop

    }

    catch [System.IO.FileNotFoundException] {

        Write-Host "Inner catch: File not found error occurred"

    }

}

catch {

    Write-Host "Outer catch: Handling an error from inner blocks - $($_.Exception.Message)"

}

finally {

    Write-Host "Executing final block for cleanup..."

}
      
Image

Messages d'erreur et débogage dans PowerShell

Accéder aux informations détaillées sur les erreurs

Lorsque des erreurs surviennent pendant l'exécution d'un script, il ne suffit pas de savoir qu'une erreur s'est produite ; nous avons besoin d'informations détaillées pour diagnostiquer et résoudre le problème. Comme mentionné précédemment, la variable $Error conserve un tableau d'enregistrements d'erreurs, avec l'erreur la plus récente à $Error[0]. Les propriétés spécifiques d'erreur incluent Exception, CategoryInfo, InvocationInfo et ScriptStackTrace.

La propriété ScriptStackTrace est inestimable car elle fournit la pile d'appels détaillée, montrant la séquence des appels de fonctions et les emplacements des scripts qui ont conduit à l'erreur. Pour accéder à ces informations détaillées pour l'erreur la plus récente, utilisez $Error[0].ScriptStackTrace.

Fournir des messages d'erreur personnalisés

Afficher des messages d'erreur significatifs et conviviaux améliore l'utilisabilité et le débogage des scripts. Des messages personnalisés peuvent fournir aux utilisateurs un aperçu de ce qui a mal tourné et parfois les aider à corriger l'erreur, comme en rectifiant un chemin de fichier incorrect, un nom de processus incorrect ou des permissions insuffisantes.

Pour afficher des messages personnalisés, nous pouvons utiliser Write-host ou write-error dans un bloc Catch. Incluez $_.Exception.message pour fournir des détails supplémentaires.

Par exemple, lorsqu'une erreur (division par zéro) se produit pendant l'exécution du script suivant, une notification détaillée est à la fois imprimée dans la console et envoyée par courriel à l'administrateur :

      $SMTPServer = "lvkex.ca.lo"

$SMTPPort = 587

$From = "aadministrator@ca.lo"

$To = "administrator@ca.lo"

$Subject = "PowerShell Script Error Alert"

try {

    Write-Host "Executing script..."  

    # Simulate an error (divide by zero)

    $result = 1 / 0 

}

catch {

    # Capture actual error message details

    $ErrorMessage = @"

An error occurred in the PowerShell script.

Message: $($_.Exception.Message)

Script: $($MyInvocation.ScriptName)

Line: $($_.InvocationInfo.ScriptLineNumber)

Date: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")

"@

    # Log error to console and send email

    Write-Host "An error occurred. Sending email notification..."

    Send-MailMessage -SmtpServer $SMTPServer -Port $SMTPPort -From $From -To $To -Subject $Subject -Body $ErrorMessage

}

}
      
Image

Cas d'utilisation courants pour PowerShell Try-Catch

Mise à jour en masse des profils utilisateurs tout en gérant les erreurs de saisie des données

Les administrateurs utilisent souvent PowerShell pour mettre à jour automatiquement les informations des utilisateurs dans Active Directory à partir d'un fichier csv. Étant donné que le fichier d'entrée peut contenir des données invalides, il est important d'utiliser Try-Catch pour gérer et consigner les erreurs.

Le script suivant importe un fichier csv contenant une liste d'utilisateurs et itère dessus pour mettre à jour leurs descriptions dans AD. Il affiche les résultats dans la console et consigne toutes les erreurs dans un fichier journal.

      # Define file paths

$CsvFile = "C:\Members (7).csv"

$LogFile = "C:\logs.txt"

# Import CSV

$Users = Import-Csv -Path $CsvFile

foreach ($User in $Users) {

    try {

        # Attempt to find the user in AD using CN or SamAccountName

        $ADUser = Get-ADUser -LDAPFilter "(cn=$($User.cn))" -Properties SamAccountName, Description -ErrorAction SilentlyContinue

        if ($ADUser -eq $null) {

            # Log missing users

            $ErrorMessage = "$(Get-Date): User '$($User.cn)' not found in AD."

            Write-Host $ErrorMessage

            Add-Content -Path $LogFile -Value $ErrorMessage

            continue  # Skip to the next user

        }

        # Define new description

        $NewDescription = "Test update on $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"

        # Update AD user description

        Set-ADUser -Identity $ADUser.SamAccountName -Description $NewDescription -ErrorAction Stop

        # Log success

        Write-Host "Updated: $($ADUser.SamAccountName) - New Description: $NewDescription"

    }

    catch {

        # Capture and log errors

        $ErrorMessage = "$(Get-Date): Error updating $($User.cn) ($($ADUser.SamAccountName)) - $($_.Exception.Message)"

        Write-Host $ErrorMessage

        Add-Content -Path $LogFile -Value $ErrorMessage

    }

}
      
Image

Gestion des problèmes de serveur ou de connexions réseau

Try-Catch blocks are also useful for handling server and network connection issues. For example, the following script illustrates how to test the connection to a server, once with the correct name and once with incorrect name:

      # Define server details

$Server = "ada1.adatum.local"

$LogFile = "C:\log.txt"

try {

    # Check if the server responds to a ping

    $PingTest = Test-NetConnection -ComputerName $Server

    if (-not $PingTest.PingSucceeded) {

        throw "Server $Server is not responding to ping."

    }

    # Check RDP connectivity (port 3389)

    $RDPTest = Test-NetConnection -ComputerName $Server -Port 3389

    if (-not $RDPTest.TcpTestSucceeded) {

        throw "Server $Server is reachable but RDP port 3389 is not open."

    }

    # If both checks pass

    Write-Host "Server $Server is reachable, and RDP is accessible."

}

catch {

    # Capture and log the error

    $ErrorMessage = "$(Get-Date): Error connecting to server $Server - $($_.Exception.Message)"

    Write-Host $ErrorMessage

    Add-Content -Path $LogFile -Value $ErrorMessage

}
      
Image

Conclusion

Try-Catch-Finally blocks are an invaluable tool for handling errors in PowerShell scripts. By combining them with mechanisms such as the ErrorAction parameter and the $ErrorActionPreference and $Error variables, you can create robust scripts that run smoothly even when unexpected issues arise. As a result, you can automate tasks with confidence that you will not suffer problems like incomplete operation, system downtime or data loss.

FAQ

Pourquoi mon bloc try-catch PowerShell n'attrape-t-il pas les erreurs ?


La raison la plus courante pour laquelle les blocs try-catch ne fonctionnent pas est que vous êtes confronté à des erreurs non-terminales. PowerShell a deux types d'erreurs : terminales (qui arrêtent l'exécution) et non-terminales (qui affichent un message mais continuent de s'exécuter). Par défaut, try-catch ne capture que les erreurs terminales.

Pour intercepter les erreurs non terminales, ajoutez -ErrorAction Stop à la commande à l'intérieur de votre bloc try. Cela force PowerShell à traiter l'erreur comme terminale :

      try {
    Get-ChildItem "C:\NonExistent" -ErrorAction Stop
} catch {
    Write-Host "Caught the error!"
}
      

Sans -ErrorAction Stop, le message d'erreur s'affiche mais votre bloc catch ne s'exécute jamais.

Un autre problème est lié à la portée. Si vous appelez des fonctions ou des scripts externes depuis votre bloc try, il se peut que les erreurs de ceux-ci ne remontent pas correctement. Assurez-vous que la fonction ou le script que vous appelez utilise également une gestion d'erreurs adéquate, ou utilisez $ErrorActionPreference = "Stop" au début de votre script pour modifier le comportement par défaut de manière globale. N'oubliez pas que la modification de la préférence globale affecte toutes les commandes de votre script, alors utilisez-la avec prudence dans les environnements de production.


Comment réparer les messages d'erreur qui s'affichent toujours avec PowerShell try-catch ?

Même avec une implémentation correcte de try-catch, vous pourriez toujours voir des messages d'erreur car PowerShell les affiche avant que le bloc catch ne les traite. Cela se produit avec les erreurs non-terminales qui deviennent terminales via -ErrorAction Stop. L'erreur apparaît dans la console, puis est capturée par votre gestionnaire.

Pour supprimer complètement l'affichage des erreurs, utilisez -ErrorAction SilentlyContinue combiné à la vérification de $? (la variable automatique de succès) ou $Error[0] pour l'erreur la plus récente :

      Get-ChildItem "C:\NonExistent" -ErrorAction SilentlyContinue
if (!$?) {
    Write-Host "Command failed silently"
}
      

Cette approche vous donne le contrôle sur la détection des erreurs sans messages d'erreur visibles.

Pour une solution plus propre, capturez les informations d'erreur dans votre bloc catch et décidez de la manière de les gérer. Utilisez $_.Exception.Message pour obtenir les détails de l'erreur, puis consignez-les ou affichez-les selon vos besoins. De cette façon, vous contrôlez exactement ce que les utilisateurs voient :

      try {
    Get-ChildItem "C:\NonExistent" -ErrorAction Stop
} catch {
    Write-Warning "Directory access failed: $($_.Exception.Message)"
}

      

Cette approche est particulièrement importante dans les environnements d'entreprise où les messages d'erreur doivent être conviviaux et consignés de manière appropriée.

Comment gérez-vous les erreurs non terminales avec try-catch de PowerShell ?

Les erreurs non terminales nécessitent une gestion particulière car elles ne déclenchent pas les blocs catch par défaut. L'approche la plus fiable consiste à utiliser -ErrorAction Stop sur les commandes individuelles où vous souhaitez capturer des erreurs. Cela convertit les erreurs non terminales en erreurs terminales que votre try-catch peut gérer.

Pour les fonctions qui génèrent plusieurs erreurs non terminales, envisagez de définir $ErrorActionPreference = "Stop" au niveau de la fonction, puis réinitialisez-le par la suite :

      function Test-Function {
    $ErrorActionPreference = "Stop"
    try {
        # your commands here
    } catch {
        # error handling
    } finally {
        $ErrorActionPreference = "Continue"
    }
}
      

Une approche alternative utilise le paramètre -ErrorVariable pour capturer les erreurs sans arrêter l'exécution. Exécutez votre commande avec -ErrorVariable myErrors -ErrorAction SilentlyContinue, puis vérifiez si $myErrors contient quelque chose. Cette méthode vous permet de gérer les erreurs après l'achèvement de la commande sans interrompre le flux :

      Get-ChildItem "C:\*" -ErrorVariable problems -ErrorAction SilentlyContinue
if ($problems) {
    Write-Host "Found $($problems.Count) errors to review"
}
      

Ce modèle fonctionne bien pour les opérations en masse où vous souhaitez recueillir tous les problèmes avant de décider de la manière de répondre.

Quelle est la différence entre ErrorAction Stop et SilentlyContinue dans try-catch ?

ErrorAction Stop convertit les erreurs non-terminales en erreurs terminales qui arrêtent immédiatement l'exécution et déclenchent votre bloc catch. Utilisez ceci lorsque vous souhaitez que votre try-catch gère l'erreur et que vous ne pouvez pas continuer si la commande échoue. C'est le choix le plus courant pour les opérations critiques où l'échec doit arrêter le processus.

ErrorAction SilentlyContinue supprime les messages d'erreur et permet la poursuite de l'exécution, mais les erreurs ne déclenchent pas les blocs catch. L'erreur se produit toujours et est ajoutée à $Error, mais aucun message d'erreur visible n'apparaît et votre script continue de s'exécuter. Cette option est utile lorsque vous vous attendez à ce que certaines opérations échouent et souhaitez les gérer par une logique conditionnelle plutôt que par un traitement d'exception.

La principale différence dans les scénarios try-catch est le flux de contrôle. Avec Stop, votre bloc catch s'exécute et vous décidez de la suite des événements. Avec SilentlyContinue, vous devez vérifier le succès manuellement en utilisant $?, $Error, ou -ErrorVariable. Pour les opérations axées sur la sécurité, Stop offre une meilleure visibilité et gestion des erreurs, garantissant que les échecs d'accès ou les violations de sécurité ne passent pas inaperçus. Dans les environnements d'entreprise, la gestion explicite des erreurs via try-catch avec ErrorAction Stop crée de meilleures pistes d'audit et un comportement de script plus prévisible.


Comment utilisez-vous try-catch avec les boucles PowerShell et continuez l'exécution ?

Dans les boucles, le comportement de try-catch dépend de l'endroit où l'erreur se produit et de ce que vous souhaitez qu'il se passe ensuite. Pour continuer à traiter les éléments restants après une erreur, placez le try-catch à l'intérieur de la boucle et utilisez continue dans le bloc catch :

      foreach ($item in $items) {
    try {
        Process-Item $item -ErrorAction Stop
    } catch {
        Write-Warning "Failed to process $item"
        continue
    }
}
      

Cela ignore l'élément échoué et passe au suivant.

Si vous souhaitez réessayer les opérations échouées, combinez try-catch avec un compteur de réessai :

      foreach ($item in $items) {
    $retries = 0
    do {
        try {
            Process-Item $item -ErrorAction Stop
            break
        } catch {
            $retries++
            if ($retries -ge 3) {
                Write-Error "Failed after 3 attempts: $item"
                break
            }
            Start-Sleep 1
        }
    } while ($retries -lt 3)
}

      

Ce modèle est précieux pour les opérations réseau ou les tâches gourmandes en ressources qui pourraient échouer temporairement.

Pour collecter à la fois les succès et les échecs, utilisez des tableaux pour suivre les résultats :

      $successful = @()
$failed = @()
foreach ($item in $items) {
    try {
        Process-Item $item -ErrorAction Stop
        $successful += $item
    } catch {
        $failed += @{Item=$item; Error=$_.Exception.Message}
    }
}
      

Cette approche offre une visibilité complète sur les opérations en masse, ce qui est essentiel pour le traitement des données, la gestion des utilisateurs ou les tâches d'administration système où vous devez rendre compte des succès et des échecs aux parties prenantes.

Partager sur

En savoir plus

À propos de l'auteur

Asset Not Found

Tyler Reese

Vice-président de la gestion de produit, CISSP

Avec plus de deux décennies d'expérience dans l'industrie de la sécurité logicielle, Tyler Reese connaît intimement les défis d'identité et de sécurité en rapide évolution auxquels les entreprises sont confrontées aujourd'hui. Actuellement, il occupe le poste de directeur de produit pour le portefeuille Netwrix Identity and Access Management, où ses responsabilités incluent l'évaluation des tendances du marché, la définition de la direction de la gamme de produits IAM et, en fin de compte, la satisfaction des besoins des utilisateurs finaux. Son expérience professionnelle s'étend de la consultation en IAM pour des entreprises du Fortune 500 à l'architecture d'entreprise d'une grande société de vente directe aux consommateurs. Il détient actuellement la certification CISSP.