Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

Chapitre 418 minDébutant

PowerShell : variables, conditions et boucles

Par Josselyn C., prof de BTS SIO. Mis à jour le .

À la fin de ce chapitre, tu sauras

  • déclarer des variables typées et manipuler des chaînes ;
  • comparer avec les bons opérateurs et éviter le piège des types mélangés ;
  • ranger des données dans des tableaux et des tables de hachage ;
  • écrire des conditions et des boucles qui ont toujours une sortie.

4 exercices corrigés

Une variable PowerShell est un nom précédé de $ qui garde une valeur : un texte, un nombre, une date, un tableau ou un objet. Avec les opérateurs de comparaison, les conditions (if, switch) et les boucles (foreach, for, while), elle permet à un script de prendre des décisions et de répéter une action sur une liste de serveurs, de comptes ou de fichiers. Ce chapitre présente ces briques avec leurs pièges, dans des exemples dont tu peux vérifier chaque sortie.

Les variables et leur type

powershell
$serveur = 'srv-ad'                  # une chaîne de caractères
$seuil   = 15                        # un entier
$date    = Get-Date                  # un objet date
$actif   = $true                     # un booléen : $true ou $false
$rien    = $null                     # l'absence de valeur

Le nom d'une variable n'est pas sensible à la casse : $Serveur et $serveur sont la même variable. PowerShell devine le type d'après la valeur. Tu peux le forcer en le mettant entre crochets devant la variable ; la variable refusera ensuite une valeur qui ne se convertit pas :

TypeDéclarationRemarque
[string][string]$nom = 'Lefèvre'Texte
[int][int]$jours = 90Entier sur 32 bits ; [long] au-delà de 2 milliards
[double][double]$taux = 0.15Nombre décimal, toujours avec un point dans le code
[bool][bool]$appliquer = $false$true ou $false
[datetime][datetime]$limite = '2026-12-31'Date ; la chaîne au format aaaa-mm-jj se convertit dans toutes les langues
[string[]][string[]]$serveurs = 'srv-ad', 'srv-ad2'Tableau de chaînes

$x.GetType().Name donne le type d'une valeur : 'srv-ad'.GetType().Name répond String, (15).GetType().Name répond Int32.

Le piège des types mélangés. Avec +, c'est le type de l'opérande de gauche qui décide :

powershell
"18" + 2        # 182 : la gauche est une chaîne, 2 est collé à la fin
2 + "18"        # 20  : la gauche est un nombre, "18" est converti
[int]"18" + 2   # 20  : on convertit explicitement

Une saisie faite avec Read-Host est toujours une chaîne : convertis-la avant de calculer.

Les variables automatiques. PowerShell en remplit certaines pour toi : $env:COMPUTERNAME et $env:USERNAME (variables d'environnement), $PSScriptRoot (le dossier du script en cours, très utile pour trouver un fichier posé à côté), $PSVersionTable, $_ dans le pipeline, $? (la dernière commande a-t-elle réussi ?), $LASTEXITCODE (le code de sortie du dernier programme externe), $Error (les dernières erreurs).

Les chaînes de caractères

Les guillemets doubles remplacent les variables par leur valeur ; les apostrophes gardent le texte tel quel.

powershell
$nom = 'Moussa'
"Bonjour $nom"                 # Bonjour Moussa
'Bonjour $nom'                 # Bonjour $nom
"Le service a $(2 + 3) jours"  # Le service a 5 jours : $( ) calcule une expression
"Serveur : $($disque.Serveur)" # Pour une propriété, il faut $( ) : "$disque.Serveur" afficherait l'objet puis « .Serveur »

Le caractère d'échappement est l'accent grave ` : `n pour un saut de ligne, `t pour une tabulation, `$ pour un dollar littéral dans des guillemets doubles. En fin de ligne, il sert aussi à continuer une commande sur la ligne suivante, mais un espace invisible après lui casse tout : préfère couper après un |, une virgule ou une accolade.

L'opérateur -f met en forme une chaîne à partir de valeurs numérotées :

powershell
'{0} : {1} Go libres sur {2}' -f 'srv-ad', 31, 80   # srv-ad : 31 Go libres sur 80
'{0:D3}' -f 7                                       # 007 : trois chiffres
'{0,-12}|' -f 'srv-ad'                              # « srv-ad      | » : aligné à gauche sur 12 caractères

Les méthodes et opérateurs utiles sur les chaînes :

ÉcritureRésultat
'srv-ad'.ToUpper()SRV-AD
' Paul '.Trim()Paul
'Lefèvre'.Length7
'jlefevre'.Substring(0, 1)j
'srv-ad.ad.sorbier.example'.Split('.')[0]srv-ad
'a;b;c' -split ';'un tableau de trois chaînes a, b, c
'srv-ad', 'srv-ad2' -join ', 'srv-ad, srv-ad2
'srv-ad' -replace 'ad', 'dc'srv-dc (le premier argument est une expression régulière, chapitre 9)
'rapport.csv'.EndsWith('.csv')True

Pour un long texte sur plusieurs lignes, la chaîne ici (here-string) commence par @" en fin de ligne et se termine par "@ en début de ligne :

powershell
$corps = @"
Bonjour,
Le serveur $serveur a moins de $seuil Go libres.
Le service informatique
"@

Les opérateurs de comparaison

PowerShell n'utilise pas =, < et > pour comparer : = affecte une valeur, > redirige vers un fichier. Les comparaisons s'écrivent avec des tirets.

OpérateurSensExemple vrai
-eq, -neÉgal, différent'srv-ad' -eq 'SRV-AD'
-gt, -ge, -lt, -lePlus grand, plus grand ou égal, plus petit, plus petit ou égal12 -lt 15
-like, -notlikeComparaison avec jokers * et ?'srv-ad2' -like 'srv-ad*'
-match, -notmatchExpression régulière'PC-0042' -match '^PC-\d{4}$'
-contains, -notcontainsLa collection contient-elle la valeur ?@('srv-ad', 'srv-ad2') -contains 'srv-ad2'
-in, -notinLa valeur est-elle dans la collection ?'srv-ad2' -in @('srv-ad', 'srv-ad2')
-and, -or, -not (ou !)Et, ou, non($a -gt 0) -and ($a -lt 10)

Ce second point explique une règle de style : pour tester $null, mets $null à gauche. $null -eq $resultat répond toujours vrai ou faux, alors que $resultat -eq $null filtrerait le tableau si $resultat en est un.

Les opérateurs arithmétiques

+, -, *, / et % (le reste de la division). La division de deux entiers donne un décimal quand elle ne tombe pas juste : 7 / 2 vaut 3.5. PowerShell connaît les suffixes KB, MB, GB, TB : 1GB vaut 1 073 741 824, ce qui convertit des octets en une division.

powershell
(Get-PSDrive C).Free / 1GB              # l'espace libre de C: en Go, avec décimales
[math]::Round((Get-PSDrive C).Free / 1GB, 1)
17 % 5                                  # 2
[math]::Floor(7 / 2)                    # 3

Les tableaux et les tables de hachage

Un tableau est une liste ordonnée. On le crée avec des virgules, ou avec @( ) qui garantit d'obtenir un tableau même avec un seul élément (ou aucun).

powershell
$serveurs = 'srv-ad', 'srv-ad2', 'srv-fichiers'
$serveurs[0]         # srv-ad : on compte à partir de 0
$serveurs[-1]        # srv-fichiers : -1 est le dernier
$serveurs.Count      # 3
$serveurs += 'srv-gestion'
1..5                 # le tableau 1, 2, 3, 4, 5

+= ne modifie pas le tableau : il en crée un nouveau, une copie plus longue. Sur quelques dizaines d'éléments, aucune importance ; sur des milliers, c'est très lent. Pour construire une grande liste, récupère directement la sortie de la boucle :

powershell
$carres = foreach ($n in 1..5) { $n * $n }   # $carres contient 1, 4, 9, 16, 25

Une table de hachage associe des clés à des valeurs, comme un petit dictionnaire. [ordered] garde les clés dans l'ordre où on les a écrites.

powershell
$passerelles = [ordered]@{
    POSTES   = '192.168.10.126'
    SERVEURS = '192.168.10.190'
    ADMIN    = '192.168.10.222'
}
$passerelles['SERVEURS']        # 192.168.10.190
$passerelles.ADMIN              # 192.168.10.222
$passerelles.DMZ = '192.168.10.238'
$passerelles.Contains('DMZ')    # True
$passerelles.Keys               # POSTES, SERVEURS, ADMIN, DMZ

Une table de hachage précédée de [pscustomobject] devient un objet, avec des propriétés : c'est la façon standard de produire des résultats que l'on pourra trier, filtrer et exporter en CSV.

powershell
[pscustomobject]@{ Serveur = 'srv-ad'; LibreGo = 31; Etat = 'OK' }

Les conditions : if et switch

powershell
$libreGo = 12
if ($libreGo -lt 10) {
    Write-Output "CRITIQUE : $libreGo Go libres"
} elseif ($libreGo -lt 15) {
    Write-Output "ATTENTION : $libreGo Go libres"
} else {
    Write-Output "OK : $libreGo Go libres"
}
text
ATTENTION : 12 Go libres

Les conditions sont évaluées dans l'ordre et la première vraie gagne : mets toujours la plus stricte en premier. Dans une condition, une valeur non booléenne est convertie : 0, '', $null et un tableau vide valent faux, tout le reste vaut vrai. if (Test-Path $dossier) et if ($comptes) (« s'il y a au moins un compte ») sont donc des tests courants.

switch compare une valeur à une liste de cas. Avec -Wildcard, les cas acceptent les jokers ; avec -Regex, des expressions régulières.

powershell
$nom = 'srv-fichiers'
switch -Wildcard ($nom) {
    'srv-ad*' { 'Contrôleur de domaine' }
    'srv-fi*' { 'Serveur de fichiers' }
    'srv-*'   { 'Autre serveur' }
    default   { 'Inconnu' }
}
text
Serveur de fichiers
Autre serveur

Contrairement à d'autres langages, switch teste tous les cas, et srv-fichiers correspond aussi à srv-*. Pour s'arrêter au premier cas vérifié, termine chaque bloc par break : 'srv-fi*' { 'Serveur de fichiers'; break }.

Les boucles

foreach parcourt une collection. C'est la boucle la plus utilisée dans les scripts d'administration.

powershell
$serveurs = 'srv-ad', 'srv-ad2', 'srv-fichiers'
foreach ($s in $serveurs) {
    Write-Output "Vérification de $s"
}

Ne confonds pas le mot-clé foreach (… in …), qui parcourt une collection déjà en mémoire, et la cmdlet ForEach-Object, qui traite les objets au fil du pipeline. Le résultat est le même ; ForEach-Object consomme moins de mémoire sur un très grand flux, foreach est plus rapide sur une collection déjà chargée.

for répète avec un compteur :

powershell
for ($i = 1; $i -le 3; $i++) {
    'PC-{0:D4}' -f $i
}
text
PC-0001
PC-0002
PC-0003

while répète tant qu'une condition est vraie ; do … until exécute au moins une fois, puis répète jusqu'à ce que la condition devienne vraie. Pratique pour attendre qu'un serveur redémarre :

powershell
$essai = 0
do {
    $essai++
    $joignable = Test-Connection -TargetName srv-ad2 -Count 1 -Quiet
    if (-not $joignable) { Start-Sleep -Seconds 10 }
} until ($joignable -or $essai -ge 30)

Test-Connection -TargetName … -Quiet répond True ou False (dans Windows PowerShell 5.1, le paramètre s'appelle -ComputerName). La limite de 30 essais évite une boucle infinie si le serveur ne revient jamais : toute boucle d'attente doit avoir une sortie.

Dans une boucle, continue passe directement à l'élément suivant et break sort de la boucle.

Demander une valeur

Read-Host pose une question et renvoie la réponse sous forme de chaîne :

powershell
$reponse = Read-Host "Nombre de jours d'inactivité"
if ($reponse -match '^\d+$') {
    $jours = [int]$reponse
} else {
    Write-Warning "« $reponse » n'est pas un nombre entier"
}

Dans un script d'administration, les questions posées en cours d'exécution sont à éviter : le script ne peut plus tourner seul, la nuit, dans une tâche planifiée. On préfère des paramètres, donnés au lancement (chapitre 6).

Exercices

Exercice 1 sur 4 Prédire la sortie Réussi À revoir

Donne exactement ce qu'affiche chaque ligne.

powershell
"5" + 3
5 + "3"
'Admin' -eq 'ADMIN'
'Admin' -ceq 'ADMIN'
@(4, 18, 9, 25) -gt 10
'srv-ad2' -like 'srv-ad?'
17 % 4
'{0}-{1:D2}' -f 'PC', 7
Voir la réponseMasquer la réponse de l'exercice 1
text
53
8
True
False
18
25
True
1
PC-07

"5" + 3 colle les caractères car la gauche est une chaîne ; 5 + "3" convertit "3" en nombre. -eq ignore la casse, -ceq non. Sur un tableau, -gt renvoie les éléments qui vérifient la condition, chacun sur sa ligne. Le ? de -like remplace exactement un caractère (2). 17 = 4 × 4 + 1. D2 écrit l'entier sur deux chiffres au moins.

Tu avais trouvé ?

Exercice 2 sur 4 Les seuils d'alerte Réussi À revoir

Écris une boucle qui parcourt la variable $disques du chapitre 3 et affiche pour chaque disque une ligne serveur lecteur: état (libre Go), où l'état vaut CRITIQUE sous 10 Go libres, ATTENTION sous 15 Go, OK sinon. Donne la sortie.

Voir la réponseMasquer la réponse de l'exercice 2
powershell
foreach ($d in $disques) {
    if ($d.LibreGo -lt 10) { $etat = 'CRITIQUE' }
    elseif ($d.LibreGo -lt 15) { $etat = 'ATTENTION' }
    else { $etat = 'OK' }
    "$($d.Serveur) $($d.Lecteur): $etat ($($d.LibreGo) Go)"
}
text
srv-ad C: OK (31 Go)
srv-ad2 C: ATTENTION (12 Go)
srv-fichiers C: CRITIQUE (9 Go)
srv-fichiers D: OK (410 Go)
srv-gestion C: CRITIQUE (7 Go)

$( ) est indispensable autour de $d.Serveur dans la chaîne : sans lui, PowerShell remplacerait $d par tout l'objet et laisserait « .Serveur » en texte. La chaîne seule sur sa ligne est envoyée dans le pipeline, comme avec Write-Output.

Tu avais trouvé ?

Exercice 3 sur 4 Construire des noms Réussi À revoir

Le service informatique numérote les postes de l'entrepôt ENT-001 à ENT-012. Écris une boucle qui produit ces douze noms, puis une table de hachage qui associe chaque nom à une adresse IP du VLAN 30 (192.168.10.128/27), en commençant à 192.168.10.129. Quelle adresse reçoit ENT-012 ? Reste-t-on dans le réseau ?

Voir la réponseMasquer la réponse de l'exercice 3
powershell
$postes = [ordered]@{}
for ($i = 1; $i -le 12; $i++) {
    $nom = 'ENT-{0:D3}' -f $i
    $postes[$nom] = "192.168.10.$(128 + $i)"
}
$postes['ENT-012']

ENT-012 reçoit 192.168.10.140 (128 + 12). Le réseau 192.168.10.128/27 contient 32 adresses, de .128 (réseau) à .159 (diffusion) : les hôtes vont de .129 à .158, et la passerelle de Sorbier est .158. Les adresses .129 à .140 sont bien dans la plage. Dans la réalité, ces terminaux reçoivent leur adresse du serveur DHCP de l'annuaire (cours Windows Server) : une table comme celle-ci servirait à créer des réservations.

Tu avais trouvé ?

Exercice 4 sur 4 Le switch qui en dit trop Réussi À revoir

Ce code doit afficher le type de chaque serveur, mais srv-ad2 produit deux lignes. Pourquoi ? Corrige-le.

powershell
foreach ($s in 'srv-ad2', 'srv-web') {
    switch -Wildcard ($s) {
        'srv-ad*' { "$s : contrôleur de domaine" }
        'srv-*'   { "$s : serveur membre" }
    }
}
Voir la réponseMasquer la réponse de l'exercice 4

switch teste tous les cas : srv-ad2 correspond à srv-ad* puis à srv-*, et les deux blocs s'exécutent. Il faut un break dans le premier cas :

powershell
foreach ($s in 'srv-ad2', 'srv-web') {
    switch -Wildcard ($s) {
        'srv-ad*' { "$s : contrôleur de domaine"; break }
        'srv-*'   { "$s : serveur membre" }
    }
}
text
srv-ad2 : contrôleur de domaine
srv-web : serveur membre

Dans un switch, break sort du switch seulement, pas de la boucle foreach qui l'entoure : srv-web est bien traité ensuite.

Tu avais trouvé ?

Chapitre terminé !

Fais les 4 exercices avant de passer à la suite : c'est en t'entraînant que tout se fixe.

chapitres
–
de série
–
du cours
–
Chapitre suivant : Bash : variables, conditions et bouclesRevoir le sommaire du cours