Aller au contenu principal

Les boucles : foreach, for et while

Notions théoriques

foreach, le mot-clé

foreach ($service in $services) {
Write-Host $service.Name
}

$services est entièrement chargée en mémoire avant que la boucle ne commence.

ForEach-Object, la cmdlet de pipeline

Get-Service | ForEach-Object { $_.Name }

ForEach-Object (alias %) traite les objets au fil de l'eau, un par un, à mesure qu'ils arrivent dans le pipeline — sans attendre que toute la collection soit disponible.

foreachForEach-Object
NatureMot-clé du langageCmdlet de pipeline
SourceUne variable déjà chargée en mémoireLe flux du pipeline
Variable de boucleNommée par vous ($service)$_ (ou $PSItem)

C'est une distinction fréquemment demandée à l'examen : mot-clé contre cmdlet, mémoire contre flux.

for

for ($i = 1; $i -le 10; $i++) {
Write-Host $i
}

Notez la présence des points-virgules et l'absence de do/done.

while et do

while ($reponse -ne "O" -and $reponse -ne "N") {
$reponse = Read-Host "Répondez O ou N"
}

do {
$reponse = Read-Host "Répondez O ou N"
} while ($reponse -ne "O" -and $reponse -ne "N")

do {
$reponse = Read-Host "Répondez O ou N"
} until ($reponse -eq "O" -or $reponse -eq "N")
attention

Comme en Bash, une boucle sans condition de sortie atteignable tourne indéfiniment — Ctrl+C interrompt le script.

break et continue

foreach ($service in $services) {
if ($service.Status -eq "Running") { continue } # passe au suivant
if ($service.Name -eq "Spooler") { break } # sort de la boucle
}

Le comportement est identique à celui de Bash.

Parcourir des objets réels

foreach ($fichier in Get-ChildItem -Path $Chemin -Filter *.log) {
Write-Host "$($fichier.Name) : $([math]::Round($fichier.Length / 1KB, 1)) Ko"
}

Il n'y a rien à découper : $fichier.Length est directement un nombre, pas une chaîne à extraire avec du, cut ou awk comme en Bash — le rappel direct de la séance sur le pipeline et les objets.

Accumuler des résultats

$compteur = 0
$resultats = @()

foreach ($fichier in $fichiers) {
$compteur++
$resultats += [PSCustomObject]@{
Nom = $fichier.Name
Taille = $fichier.Length
}
}

[PSCustomObject]@{ ... } construit un objet personnalisé avec des propriétés nommées. Émettre ces objets depuis une boucle, plutôt que de simplement les afficher, permet de les réutiliser ensuite dans Sort-Object, Where-Object ou Export-Csv — c'est le vrai déclic à acquérir en PowerShell.

info

Get-ChildItem -Recurse ou un pipeline bien construit remplacent souvent une boucle explicite. En PowerShell, la boucle la plus lisible est parfois celle qu'on n'écrit pas.

Et en Bash ?
BashPowerShell
for f in "$@"; do ... doneforeach ($f in $args) { ... }
for ((i=0; i<10; i++))for ($i = 0; $i -lt 10; $i++)
while [ ... ]; do ... donewhile (...) { ... }
Extraire une taille avec du/cut$fichier.Length directement

Exemple pratique

<#
Script : Get-InfosSysteme.ps1
Rôle : parcourir tous les disques et les services critiques (v5)
#>

$disques = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"
$compteurAlertes = 0

foreach ($disque in $disques) {
$pourcentLibre = [math]::Round(($disque.FreeSpace / $disque.Size) * 100, 1)
Write-Host "$($disque.DeviceID) : $pourcentLibre % libre"

if ($pourcentLibre -lt 20) {
Write-Host " -> ALERTE espace disque" -ForegroundColor Red
$compteurAlertes++
}
}

$servicesCritiques = @("Spooler", "wuauserv", "WinDefend")

foreach ($nomService in $servicesCritiques) {
$service = Get-Service -Name $nomService -ErrorAction SilentlyContinue
if ($null -eq $service) {
Write-Host "$nomService : service introuvable" -ForegroundColor Yellow
} elseif ($service.Status -ne "Running") {
Write-Host "$nomService : arrêté" -ForegroundColor Red
$compteurAlertes++
}
}

Write-Host "Nombre total d'alertes : $compteurAlertes"

Test de mémorisation/compréhension


Quelle est la différence entre foreach et ForEach-Object ?


Quelle variable désigne l'élément courant dans Get-Service | ForEach-Object { ... } ?


Quelle boucle répète un traitement 10 fois à l'aide d'un compteur ?


Que fait continue dans une boucle PowerShell ?


Comment obtenir la taille en kilo-octets d'un fichier parcouru par une boucle ?


TP pour réfléchir et résoudre des problèmes

Étape 1 — Parcourir tous les disques locaux


Bonne pratique - Ne rien coder en dur

Ne fixez jamais un seul lecteur (« C: ») en dur dans le script : un poste peut avoir plusieurs volumes, et la boucle doit s'adapter à ce qui est réellement présent.

Étape 2 — Compter les alertes rencontrées


Bonne pratique - Initialiser son compteur avant la boucle

$compteurAlertes = 0 doit être écrit avant la boucle foreach, jamais à l'intérieur — sinon il serait réinitialisé à chaque itération.

Étape 3 — Boucler sur une liste de services critiques


Bonne pratique - Anticiper un service absent

-ErrorAction SilentlyContinue associé à un test $null sur le résultat évite une erreur rouge qui casserait l'affichage du rapport si un service n'existe pas sur la machine.

Étape 4 — Redemander tant que la réponse n'est pas O ou N


Bonne pratique - Toujours prévoir la sortie d'un while

Une boucle while doit toujours pouvoir atteindre une condition fausse : ici, la boucle se termine dès que l'utilisateur répond effectivement O ou N.

📌 Une solution