Foreach Statement PowerShell : syntaxe, exemples et bonnes pratiques ⚙️

L’instruction foreach en PowerShell permet de parcourir chaque élément d’une collection déjà chargée en mémoire, comme un tableau ou une liste d’objets, pour exécuter un même bloc d’instructions sur chacun d’eux. Sa syntaxe minimale est simple : foreach ($item in $collection) { }. Exemple concret :
$fruits = "pomme", "banane", "cerise"
foreach ($fruit in $fruits) {
Write-Output $fruit
}
Ce code affiche successivement chaque valeur du tableau $fruits. Voyons maintenant comment exploiter cette instruction sur des tableaux, des objets, des fichiers, et comment elle se distingue de la cmdlet ForEach-Object et de la méthode .ForEach().
Syntaxe de base de la boucle foreach PowerShell
La structure générale d’une boucle foreach PowerShell repose sur trois éléments : une variable de boucle, une collection PowerShell existante, et un bloc de script exécuté pour chaque itération.
foreach ($variable in $collection) {
# instructions exécutées pour chaque élément
}
La variable de boucle, ici $variable, prend successivement la valeur de chaque élément de la collection tant que celle-ci n’est pas épuisée. Cette variable reste accessible après la fin de la boucle et conserve la dernière valeur traitée, ce qui distingue cette instruction de certains langages où la portée est strictement limitée au bloc.
Cette instruction fonctionne aussi bien sur un tableau littéral, une variable contenant déjà une collection, ou encore le résultat direct d’une cmdlet placé entre parenthèses. PowerShell charge alors l’ensemble de la collection en mémoire avant de commencer l’itération, contrairement à un pipeline qui traite les objets un par un au fur et à mesure de leur production.
Parcourir un tableau PowerShell
Un tableau PowerShell est l’exemple le plus courant d’utilisation de foreach. Il peut contenir des chaînes, des nombres ou tout autre type d’objet :
$nombres = 1, 2, 3, 4, 5
foreach ($nombre in $nombres) {
Write-Output ($nombre * 2)
}
Chaque élément du tableau est multiplié par deux et affiché individuellement. Cette approche fonctionne de la même façon quel que soit le type de données stocké dans le tableau.
Parcourir une collection d’objets
PowerShell manipule très souvent des objets plutôt que de simples valeurs, notamment lorsqu’une cmdlet retourne des résultats. La boucle foreach permet d’accéder directement aux propriétés de chaque objet parcouru :
$services = Get-Service
foreach ($service in $services) {
if ($service.Status -eq "Running") {
Write-Output "$($service.Name) est actif"
}
}
Cet exemple parcourt une collection PowerShell de services système et affiche uniquement ceux dont le statut est actif, en combinant la boucle avec une condition.
Utiliser foreach avec des fichiers et des processus
Le même principe s’applique aux fichiers d’un répertoire ou aux processus en cours d’exécution, deux cas fréquents en administration système :
$fichiers = Get-ChildItem -Path "C:\Logs" -Filter "*.log"
foreach ($fichier in $fichiers) {
Write-Output "$($fichier.Name) - $($fichier.Length) octets"
}
Ici, chaque fichier journal du dossier est listé avec sa taille, ce qui illustre bien l’intérêt de la boucle pour traiter automatiquement un ensemble d’éléments similaires sans dupliquer le code.
Utiliser des conditions et contrôler la boucle avec break et continue
Il est courant de combiner une instruction foreach avec des conditions pour filtrer ou interrompre le traitement. Deux instructions permettent de contrôler précisément le déroulement de la boucle :
breakinterrompt immédiatement la boucle entière, sans traiter les éléments restants.continueignore uniquement l’itération en cours et passe directement à l’élément suivant.
foreach ($nombre in 1..10) {
if ($nombre -eq 7) {
break
}
if ($nombre % 2 -eq 0) {
continue
}
Write-Output $nombre
}
Ce script affiche les nombres impairs de 1 à 6, ignore les nombres pairs grâce à continue, puis arrête totalement la boucle dès que la valeur 7 est atteinte grâce à break.
Foreach, ForEach-Object et la méthode .ForEach() : quelles différences
PowerShell propose trois façons distinctes de parcourir une collection, souvent confondues à cause de leur nom proche.
| Forme | Type | Fonctionnement | Cas d’usage typique |
|---|---|---|---|
foreach | Instruction de langage | Parcourt une collection déjà chargée en mémoire | Boucle classique sur un tableau ou une variable |
ForEach-Object | Cmdlet | Traite chaque objet reçu dans le pipeline | Chaînage de commandes avec l’opérateur pipe |
.ForEach() | Méthode de collection | Applique un script block directement sur la collection | Écriture concise sans variable intermédiaire |
L’instruction foreach est en général la plus lisible lorsque la collection est déjà stockée dans une variable. La cmdlet ForEach-Object, elle, s’intègre naturellement dans un pipeline, en recevant les objets à mesure qu’ils sont produits par la commande précédente, sans devoir attendre que toute la collection soit chargée.
Utiliser ForEach-Object et la variable $_
Avec ForEach-Object, chaque objet du pipeline est représenté par la variable automatique $_, aussi appelée $PSItem. Ces deux notations sont strictement équivalentes :
Get-Process | ForEach-Object {
Write-Output "$($_.Name) utilise $($_.CPU) secondes CPU"
}
Ce script block s’exécute pour chaque processus transmis dans le pipeline. $_ remplace ici la variable explicite qu’on aurait déclarée avec une instruction foreach classique, comme $item dans les exemples précédents.
La méthode .ForEach() sur une collection
Depuis PowerShell 4.0, une collection dispose directement d’une méthode .ForEach(), qui applique un script block sans passer par le pipeline ni par une instruction séparée :
$fruits = "pomme", "banane", "cerise"
$fruits.ForEach({ Write-Output $_.ToUpper() })
Cette syntaxe reste proche de ForEach-Object dans son usage de $_, mais s’exécute directement sur la collection déjà en mémoire, sans transiter par le pipeline, ce qui la rapproche davantage du fonctionnement de l’instruction foreach.
Choisir entre boucle classique et pipeline
Le choix entre foreach et ForEach-Object dépend surtout du contexte du script. foreach convient bien lorsque la collection est déjà disponible dans une variable et que la lisibilité prime. ForEach-Object devient pertinent dès que la boucle s’insère dans une chaîne de commandes avec l’opérateur pipe, en traitant les objets au fil de l’eau plutôt qu’après un chargement complet en mémoire.
Get-ChildItem -Path "C:\Data" | Where-Object { $_.Length -gt 1MB } | ForEach-Object {
Write-Output $_.Name
}
Dans cet exemple, l’usage de ForEach-Object s’intègre naturellement après un filtre Where-Object, ce qu’une instruction foreach classique rendrait plus lourd à écrire.
Erreurs fréquentes avec l’instruction foreach
Certaines erreurs reviennent régulièrement chez les débutants comme chez les utilisateurs plus expérimentés :
- Confondre
foreachetForEach-Object: écrire$collection | foreach ($item in $collection)produit une erreur de syntaxe, car l’instructionforeachne s’utilise pas avec le pipeline de cette manière. - Utiliser
$_dans une instruction foreach classique :$_n’existe que dans un script block de pipeline, pas dans le bloc d’une instructionforeach, où seule la variable déclarée aprèsforeach (est disponible. - Modifier la collection pendant son parcours : ajouter ou supprimer un élément d’un tableau en cours de boucle peut provoquer des comportements imprévisibles.
- Oublier que la variable de boucle persiste après la boucle : réutiliser un nom de variable de boucle ailleurs dans le script sans le réinitialiser peut introduire des bugs silencieux.
- Confondre script block et bloc de l’instruction foreach : le contenu entre accolades d’une instruction
foreachn’est pas un script block indépendant comme celui utilisé avecForEach-Objectou.ForEach(); il ne peut pas être stocké dans une variable puis réutilisé de la même manière.
Bonnes pratiques pour écrire des boucles foreach lisibles
Nommer explicitement la variable de boucle selon son contenu, plutôt que d’utiliser systématiquement $item, améliore nettement la lisibilité d’un script long. Il est également conseillé de limiter la profondeur des blocs imbriqués et de préférer une condition claire à une suite de vérifications empilées dans une même itération. Pour les traitements plus complexes impliquant de nombreux objets et des besoins avancés comme l’exécution simultanée de plusieurs itérations, ForEach-Object -Parallel existe dans les versions récentes de PowerShell, mais reste une option à réserver à des cas spécifiques plutôt qu’un usage systématique.
