Explication de la boucle Foreach en PowerShell : Syntaxe, Exemples et Meilleures Pratiques | Netwrix Blog | Aperçus pour les professionnels de la cybersécurité et de l'IT
Feb 20, 2025
The PowerShell ForEach loop simplifies iterating over collections like arrays, lists, or pipeline output, making it essential for automation and data processing. It executes a block of code for each item, supporting use cases such as renaming files, updating Active Directory users, or parsing logs. Best practices include using clear variable names, combining with error handling, and leveraging ForEach-Object for memory-efficient, pipeline-driven tasks.
La boucle foreach dans PowerShell vous permet de parcourir tous les éléments d'une collection et d'exécuter un bloc de code pour chaque élément. Par exemple, vous pouvez utiliser une boucle foreach pour créer une liste de tous les fichiers dans un répertoire pour un audit, afficher tous les processus en cours sur le système ou déplacer les anciens fichiers vers une archive.
Cet article détaille la syntaxe de la boucle PowerShell foreach et explore des cas d'utilisation courants, avec des scripts d'exemple. Ensuite, il explique comment éviter les erreurs communes et offre les meilleures pratiques pour utiliser les boucles foreach efficacement.
Commencer avec les boucles Foreach de PowerShell
Syntaxe de base et traitement
Voici la syntaxe de base de l'instruction foreach :
foreach ($item in $collection) {
# Code to execute for each item
}
Le traitement de cette boucle foreach se déroule comme suit :
- PowerShell charge la collection $collection en mémoire et détermine le nombre d'objets qu'elle contient.
- Le premier objet de $collection est attribué à la variable $item, et le bloc de code est exécuté pour cet objet.
- La valeur de $item est mise à jour à l'objet suivant dans $collection et le bloc de code est exécuté pour cet objet. Cette étape est répétée jusqu'à ce que tous les objets dans $collection aient été traités.
Syntaxe avancée
La méthode foreach offre un moyen plus concis de parcourir les collections et peut potentiellement offrir de meilleures performances. La syntaxe est la suivante :
$collection.ForEach({ <expression> })
Comparaison du mot-clé Foreach, de Foreach-Object et de la méthode Foreach
Le mot-clé Foreach, l'objet Foreach-object et la méthode Foreach ont un but similaire, mais ils présentent des cas d'utilisation et des comportements distincts.
ForEach Keyword
Le mot-clé foreach est utilisé pour itérer sur une collection d'éléments, charge tous les éléments de la collection en mémoire et traite tous les éléments en une seule fois. Ce qui en fait un choix idéal lorsqu'il s'agit de traiter rapidement des collections en mémoire.
Cmdlet ForEach-Object
Le cmdlet Foreach-object, en revanche, est un cmdlet orienté pipeline conçu pour traiter chaque objet transitant dans le pipeline un à un. Il réduit la consommation de ressources telles que la mémoire et convient aux scénarios où le chargement de la collection entière en mémoire n'est pas pratique. Bien qu'il soit légèrement plus lent que foreach en raison de la surcharge du pipeline, il est avantageux dans l'utilisation efficace de la mémoire pendant l'exécution du script.
ForEach Method
La méthode Foreach a été introduite dans PowerShell 5, la méthode Foreach est utile sur certains types de collections tels que les tableaux et les listes, elle offre une syntaxe concise pour effectuer des actions sur chaque élément. La méthode Foreach est orientée objet et utilisée lorsque nous voulons enchaîner des méthodes et pour une collection en mémoire, elle est plus efficace que le cmdlet foreach-object.
Dans l'exemple suivant, nous obtenons les processus consommant plus de 400 Mo de mémoire avec foreach, foreach-object et la méthode foreach.
# Get all processes consuming more than 400MB of memory
$processes = Get-Process | Where-Object { $_.WorkingSet64 -gt 400MB }
# Using foreach keyword (Table Format)
Write-Host "`n=== Using foreach Keyword (Table Format) ===" -ForegroundColor Cyan
$output = foreach ($proc in $processes) {
[PSCustomObject]@{
"Process Name" = $proc.ProcessName
"PID" = $proc.Id
"Memory (MB)" = [math]::Round($proc.WorkingSet64 / 1MB, 2)
}
}
$output | Format-Table -AutoSize
# Using Foreach-Object (List Format)
Write-Host "`n=== Using Foreach-Object Cmdlet (List Format) ===" -ForegroundColor Green
$processes | ForEach-Object {
Write-Output "Process Name : $($_.ProcessName)"
Write-Output "PID : $($_.Id)"
Write-Output "Memory Usage : $([math]::Round($_.WorkingSet64 / 1MB, 2)) MB"
Write-Output "-----------------------------------"
}
# Using .ForEach() Method (CSV-like Output)
Write-Host "`n=== Using .ForEach() Method (CSV-like Output) ===" -ForegroundColor Yellow
$processes.ForEach({
"$($_.ProcessName),$($_.Id),$([math]::Round($_.WorkingSet64 / 1MB, 2)) MB"
}) | ForEach-Object { Write-Output $_ }
Cas d'utilisation courants
Afficher tous les numéros dans un tableau
Le script suivant va parcourir un tableau de nombres et écrire chacun d'eux dans la console :
# Define an array of numbers
$numbers = 1..5
# Loop through the array
foreach ($number in $numbers) {
Write-Host "Number (foreach keyword): $number"
}
Afficher les noms de tous les fichiers dans un répertoire
L'exemple suivant de boucle foreach en PowerShell utilise le cmdlet Get-ChildItem pour récupérer le fichier d'un répertoire spécifié et affiche le nom de chaque fichier :
foreach ($file in Get-ChildItem -Path " D:\Office") {
Write-Output $file.Name
}
Manipulez chaque objet dans une collection
Le script suivant obtient tous les processus dont le nom commence par C ou F, vérifie si chaque processus est en cours d'exécution et ajoute la propriété personnalisée isActive à chaque processus pour documenter son statut :
# Get all processes whose names start with 'C' or 'F'
$processes = Get-Process | Where-Object { $_.Name -like "C*" -or $_.Name -like "F*" }
foreach ($process in $processes) {
$isActive = $process.Responding
$process | Add-Member -NotePropertyName "IsActive" -NotePropertyValue $isActive
}
$processes | Format-Table -Property Name, Id, IsActive
Techniques avancées
Traitement des éléments différemment selon vos critères
Vous pouvez utiliser des instructions If dans des boucles foreach pour effectuer différentes actions en fonction des caractéristiques de chaque objet traité. Le script suivant récupère tous les fichiers dans un répertoire spécifié mais affiche les noms de ceux uniquement plus grands que 10 ko :
foreach ($file in Get-ChildItem -Path "D:\Office") {
if ($file.Length -gt 10KB) {
Write-Output $file.Name
}
}
Ce script pourrait facilement être modifié pour effectuer d'autres actions sur les gros fichiers d'un répertoire au lieu de simplement les lister. Par exemple, vous pourriez les copier dans un autre emplacement, les compresser ou les supprimer en fonction de leur dernière date d'accès.
Utilisation de l'imbrication
Mettre une boucle foreach à l'intérieur d'une autre s'appelle l'imbrication. Les boucles foreach imbriquées peuvent être utilisées pour parcourir deux collections ou plus et effectuer des opérations impliquant des éléments des deux collections. Par exemple, l'imbrication peut être utilisée pour générer des combinaisons de paramètres pour les tests, créer des produits cartésiens d'ensembles ou parcourir des données multidimensionnelles.
Le script ci-dessous utilise des boucles foreach imbriquées pour générer toutes les combinaisons possibles d'éléments de deux tableaux différents, l'un avec trois nombres et l'autre avec trois lettres :
$outerArray = 1..3
$innerArray = 'A', 'B', 'C'
foreach ($outer in $outerArray) {
foreach ($inner in $innerArray) {
Write-Output "$outer $inner"
}
}
Gestion des erreurs
Si une boucle foreach rencontre une erreur, le script se terminera. Un exemple courant est lorsque le code essaie de diviser par zéro, ce qui n'est pas mathématiquement possible. Le message d'erreur résultant peut vous aider à identifier la cause des problèmes.
Vous pouvez utiliser un bloc Try-Catch pour gérer les problèmes potentiels avec élégance et garantir que le script continue de traiter les éléments supplémentaires de la collection. Dans le script suivant, le bloc try tente de résoudre un problème de division en utilisant chaque nombre de la collection. Si l'opération réussit, le résultat est écrit sur l'hôte ; sinon, le bloc catch affiche un message d'erreur en rouge. Dans les deux cas, la boucle passe à l'élément suivant de la collection.
# Sample collection of items.
$numbers = @(1, 2, 0, 4, 5)
foreach ($number in $numbers) {
try {
$result = 10 / $number
Write-Host "10 divided by $number is: $result"
} catch {
Write-Host "Error: Cannot divide by zero. Skipping $number." -ForegroundColor Red
}
}
Éviter les erreurs courantes
Voici quelques erreurs souvent commises avec les boucles foreach et comment les éviter.
Utilisation du même nom de variable dans des boucles imbriquées
L'utilisation du même nom de variable dans des boucles imbriquées peut entraîner des comportements inattendus et des conflits. Par exemple, le script suivant utilise la même variable $item dans les boucles externe et interne :\
foreach ($item in $collection) {
foreach ($item in $nestedCollection) { # Overwrites outer $item
Write-Host $item
}
}
Pour éviter des problèmes, utilisez des noms de variables uniques pour chaque boucle :
foreach ($outerItem in $collection) {
foreach ($innerItem in $nestedCollection) {
Write-Host $innerItem
}
}
Sortir prématurément des boucles
Une instruction break peut être utilisée pour sortir d'une boucle foreach une fois qu'une condition souhaitée est remplie. Cependant, l'utilisation incorrecte des instructions break peut terminer prématurément la boucle, conduisant à un traitement incomplet de la collection.
En conséquence, utilisez break avec précaution. Envisagez des alternatives telles que continue pour sauter des itérations spécifiques sans sortir de la boucle :
Boucles infinies
Si la condition de la boucle n'est jamais évaluée à faux ou si la collection est modifiée de manière inappropriée, la boucle peut continuer indéfiniment. Par exemple, alors que le script suivant itère sur une collection, il continue d'ajouter de nouveaux éléments à cette collection :
$collection = @("Item1", "Item2", "Item3")
foreach ($item in $collection) {
$collection.Add("NewItem") # Changes collection size dynamically
}
Une manière d'éviter cette boucle infinie est de faire une copie de la collection originale puis d'itérer à travers la copie, en apportant des modifications à l'originale :
# Original collection
$collection = @("Item1", "Item2", "Item3")
# Iterate over a copy of the collection
foreach ($item in $collection.Clone()) {
Write-Host "Processing $item"
$collection.Add("NewItem") # Modify the original collection safely
}
Write-Host "Final Collection: $collection"
Meilleures pratiques
Les meilleures pratiques suivantes peuvent vous aider à utiliser les boucles foreach plus efficacement.
Pour les données en pipeline, utilisez le cmdlet foreach-object.
Comme nous l'avons vu, foreach dans PowerShell charge une collection en mémoire puis traite chaque élément séquentiellement. Cependant, parfois, vous devez traiter des objets transmis via un pipeline. Dans ces cas, utilisez le cmdlet foreach-object, qui utilise également moins de mémoire. Pour des exemples, consultez ce guide Essential PowerShell Commands.
Maximisez la lisibilité et la maintenabilité des scripts.
Pour rendre vos scripts plus faciles à lire et à maintenir, utilisez une indentation et un espacement cohérents pour vos boucles foreach, ajoutez des commentaires pertinents et gardez le corps de la boucle concis en définissant des fonctions ou des méthodes, comme illustré ici :
# Define a collection of file paths
$filePaths = Get-ChildItem -Path "D:\Office" -File
# Process each file in the collection
foreach ($file in $filePaths) {
# Check if the file is larger than 1KB
if ($file.Length -gt 1KB) {
# Log the file name and size
Write-Host "Large file found: $($file.Name) - Size: $($file.Length / 1KB) KB"
} else {
# Skip smaller files
Write-Host "Skipping small file: $($file.Name)"
}
}
Conclusion
La boucle foreach dans PowerShell est un outil précieux pour automatiser des tâches nécessitant de parcourir une collection et d'exécuter du code sur chaque élément, telles que la gestion de fichiers et le contrôle des processus. Commencez par expérimenter avec les exemples simples fournis dans cet article, puis passez à des techniques plus avancées comme les boucles imbriquées et la gestion des erreurs.
FAQ
Quelle est la différence entre une boucle foreach et le cmdlet foreach-object ?
Une boucle foreach est utilisée pour parcourir un tableau ou une autre collection, qu'elle charge en mémoire avant de traiter les données. La cmdlet foreach-object est utilisée pour traiter les objets transmis via un pipeline par une autre cmdlet.
Comment gérez-vous les erreurs dans une boucle foreach ?
Utilisez un bloc try-catch pour gérer les exceptions avec élégance.
Peut-on sortir d'une boucle foreach dans PowerShell ?
Oui, vous pouvez utiliser une instruction break pour sortir d'une boucle foreach une fois qu'une condition souhaitée est atteinte. Ici, la boucle est interrompue lorsque le nombre 5 est atteint dans la collection, donc seulement les nombres de 1 à 4 sont écrits sur l'hôte :
foreach ($number in 1..10) {
if ($number -eq 5) { break }
Write-Host $number
}
Comment imbriquer des boucles foreach ?
Pour imbriquer des boucles foreach, placez une boucle à l'intérieur d'une autre. Pour éviter les erreurs, assurez-vous d'utiliser des noms de variables uniques pour les différentes boucles. Le script suivant utilise des boucles foreach imbriquées pour itérer sur deux collections et afficher toutes les combinaisons possibles des éléments de ces collections :
$outerCollection = @(1, 2)
$innerCollection = @(3, 4)
foreach ($outerItem in $outerCollection) {
foreach ($innerItem in $innerCollection) {
Write-Host "Outer: $outerItem, Inner: $innerItem"
}
}
Partager sur
En savoir plus
À propos de l'auteur
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.
En savoir plus sur ce sujet
Supprimer le fichier avec Powershell s'il existe
PowerShell Write to File : "Out-File" et techniques de sortie de fichier
Comment créer de nouveaux utilisateurs Active Directory avec PowerShell
Comment exécuter un script PowerShell
Qu'est-ce que PowerShell ? Un guide complet de ses fonctionnalités et utilisations