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.
foreach | ForEach-Object | |
|---|---|---|
| Nature | Mot-clé du langage | Cmdlet de pipeline |
| Source | Une variable déjà chargée en mémoire | Le flux du pipeline |
| Variable de boucle | Nommé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")
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.
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.
| Bash | PowerShell |
|---|---|
for f in "$@"; do ... done | foreach ($f in $args) { ... } |
for ((i=0; i<10; i++)) | for ($i = 0; $i -lt 10; $i++) |
while [ ... ]; do ... done | while (...) { ... } |
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
TP pour réfléchir et résoudre des problèmes
Étape 1 — Parcourir tous les disques locaux
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
$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
-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
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.