Tutoriels gratuits et ouverts à toutes et à tous · conçus au Lycée Chevrollier — AngersÀ propos

Série « Parcours PowerShell » · partie 3 / 8

PowerShell niveau 2 — Variables et données

Stocker, typer et transformer : variables, tableaux, tables de hachage et chaînes : niveau 2 du parcours PowerShell, avec exercices corrigés et QCM.

Systèmes✎ B. Jousseaume📅 17 octobre 2026⏱ 4 h📶 Débutant

1. Les variables

Un nom de variable commence par $. L’affectation se fait avec = ; le type est déduit automatiquement.

PS> $nom = "Chevrollier"
PS> $anneeScolaire = 2026
PS> $estActif = $true
PS> $services = Get-Service           # une variable peut contenir des objets

PS> $nom.GetType().Name
String
  • Le nom est insensible à la casse : $nom et $Nom désignent la même variable.
  • Les valeurs booléennes s’écrivent $true et $false, avec le dollar.
  • $null représente l’absence de valeur.
  • Une variable peut contenir un seul objet ou toute une collection.

Typer explicitement

On peut imposer un type, ce qui protège contre les mauvaises surprises :

PS> [int]$age = "42"          # converti en nombre
PS> $age + 1
43
PS> [int]$age = "quarante"
Impossible de convertir la valeur « quarante » en type « System.Int32 ».
TypeUsage
[int], [double]Nombres entiers, nombres décimaux
[string]Texte
[bool]$true ou $false
[datetime]Date et heure
[array], [hashtable]Collection, table de hachage

2. Les variables automatiques et d’environnement

VariableContenu
$PSVersionTableVersions de PowerShell et de ses composants
$PWDDossier courant
$?Succès ($true) ou échec de la dernière commande
$ErrorHistorique des erreurs ; $Error[0] est la plus récente
$PSScriptRootDossier du script en cours (très utile au niveau 4)
$env:USERNAME, $env:COMPUTERNAMEVariables d’environnement Windows
$env:TEMP, $env:USERPROFILEDossiers temporaire et personnel
PS> Get-ChildItem Env: | Select-Object Name, Value -First 5      # toutes les variables d'environnement

3. Les tableaux

$jours = "lundi", "mardi", "mercredi"
$nombres = @(1, 2, 3, 4, 5)           # @() force le tableau, même à un seul élément
$vide = @()

$jours[0]            # lundi         (le premier élément porte l'indice 0)
$jours[-1]           # mercredi      (le dernier)
$jours[0..1]         # lundi, mardi  (une plage)
$jours.Count         # 3
$jours += "jeudi"    # ajoute un élément

Le pipeline fonctionne sur les tableaux comme sur les résultats de commandes :

$nombres | Where-Object { $_ -gt 2 } | Measure-Object -Sum
$jours | Sort-Object -Descending

4. Les tables de hachage

Une table de hachage associe des clés à des valeurs, comme une fiche.

$poste = @{
    Nom        = "PC-SALLE-207"
    Ram        = 16
    Systeme    = "Windows 11"
    Utilisateur = "bjousseaume"
}

$poste["Nom"]            # PC-SALLE-207
$poste.Ram               # 16
$poste.Disque = 512      # ajout d'une clé
$poste.Remove("Ram")     # suppression
$poste.Keys              # la liste des clés

Les tables de hachage servent partout : propriétés calculées du niveau 1, paramètres d’une commande, données de configuration d’un script.

# Le splatting : préparer les paramètres d'une commande dans une table
$parametres = @{
    Path        = "$env:USERPROFILE\Desktop\rapport.csv"
    Delimiter   = ";"
    Encoding    = "UTF8"
    NoTypeInformation = $true
}
Get-Service | Export-Csv @parametres

5. Les chaînes de caractères

La différence entre guillemets doubles et apostrophes est fondamentale :

$nom = "Bruno"

"Bonjour $nom"                 # Bonjour Bruno      (interpolation)
'Bonjour $nom'                 # Bonjour $nom       (texte brut)
"Résultat : $($poste.Ram) Go"  # $( ) pour évaluer une expression
"Tabulation`tici"             # échappement : accent grave puis t
OpérationExempleRésultat
Concaténer"a" + "b"ab
Répéter"-" * 20une ligne de 20 tirets
Découper"a;b;c" -split ";"un tableau de 3 éléments
Joindre$jours -join ", "une chaîne
Remplacer"2026-09" -replace "-", "/"2026/09
Mettre en forme"{0:N2}" -f 3.141593,14
Méthodes$texte.ToUpper(), .Trim(), .Substring(0,3)

Les blocs de texte

$message = @"
Bonjour $nom,
Votre poste $($poste.Nom) a été inventorié le $(Get-Date -Format "dd/MM/yyyy").
"@

Ce bloc, appelé here-string, conserve les retours à la ligne. Les marqueurs @" et "@ doivent être seuls sur leur ligne.

6. Comparer et convertir

"10" -eq 10           # True  : la chaîne est convertie en nombre
10 -eq "10"           # True
"abc" -like "a*"      # True
$null -eq $valeur     # la bonne façon de tester la présence d'une valeur

[int]"42" + 1                       # 43
[datetime]"2026-09-24"              # objet date
(Get-Date).AddDays(30)              # arithmétique de dates
[math]::Round(3.14159, 2)           # 3,14

7. Mini-projet : l’inventaire structuré

8. Bilan

Exercices corrigés

Les erreurs de ce niveau viennent presque toujours de deux causes : un mauvais type (du texte au lieu d’un nombre) ou de mauvais guillemets. En cas de doute, $variable.GetType().Name donne la réponse.

Exercice 2.1 — Collections

Voir le corrigé
# 1.
$jours = "lundi", "mardi", "mercredi", "jeudi", "vendredi"
$jours[2]
$jours | Sort-Object

# 2.
$poste = @{ Nom = "PC-207"; Systeme = "Windows 11"; MemoireGo = 16 }
$poste.DateReleve = Get-Date

# 3.
[PSCustomObject]$poste | Export-Csv "$env:USERPROFILE\Desktop\poste.csv" -Delimiter ";" -Encoding UTF8 -NoTypeInformation

# 4.
$arretes = Get-Service | Where-Object Status -eq "Stopped" | Select-Object -ExpandProperty Name
$arretes.Count

Explication

[PSCustomObject] accepte directement une table de hachage, ce qui permet de passer de l’une à l’autre sans réécrire les données. C’est l’objet à privilégier dès qu’on veut trier, filtrer ou exporter.

Exercice 2.2 — Transformer

Voir le corrigé
# 1.
"Le poste $($poste.Nom) dispose de $($poste.MemoireGo) Go"

# 2.
("CHEVROLLIER;SIO;207" -split ";")[-1]

# 3.
Get-Date -Format "dddd dd MMMM yyyy"
(Get-Date).AddDays(45).ToString("dddd dd MMMM yyyy")

# 4.
[math]::Round(1572864 / 1MB, 2)      # 1,5

Explication

$( ) permet d’évaluer une expression complète dans une chaîne, y compris un appel de méthode ou une propriété imbriquée. Sans lui, "$poste.Nom" afficherait la table suivie de « .Nom ».

Pour aller plus loin

# Mise en forme avec l'opérateur -f, pratique pour aligner
"{0,-12} {1,6:N1} Go" -f $poste.Nom, $poste.MemoireGo

Mini-projet

Voir le corrigé
$os = Get-CimInstance Win32_OperatingSystem
$cs = Get-CimInstance Win32_ComputerSystem
$c  = Get-PSDrive C

$inventaire = [PSCustomObject]@{
    Machine      = $env:COMPUTERNAME
    Utilisateur  = $env:USERNAME
    Systeme      = $os.Caption
    Version      = $os.Version
    MemoireGo    = [math]::Round($cs.TotalPhysicalMemory / 1GB, 1)
    DisqueCLibreGo = [math]::Round($c.Free / 1GB, 1)
    DateReleve   = Get-Date -Format "yyyy-MM-dd HH:mm"
}

$inventaire | Format-List
$inventaire | Export-Csv "$env:USERPROFILE\Desktop\inventaire.csv" -Delimiter ";" -Encoding UTF8 -NoTypeInformation
$inventaire | ConvertTo-Json | Out-File "$env:USERPROFILE\Desktop\inventaire.json" -Encoding utf8

Import-Csv "$env:USERPROFILE\Desktop\inventaire.csv" -Delimiter ";"

Explication

L’objet unique rassemble des informations issues de trois sources différentes. Comme c’est un véritable objet, il s’exporte aussi bien en CSV qu’en JSON, et il pourra plus tard être renvoyé par une fonction.

Pour aller plus loin

ConvertTo-Json -Depth 5 est souvent nécessaire quand l’objet contient plusieurs niveaux : la profondeur par défaut est de 2.

🧠 Testez vos connaissances

5 questions. Répondez puis cliquez sur « Corriger ». Rien n’est enregistré : c’est de l’auto-évaluation.

1. Quelle est la différence entre "Bonjour $nom" et 'Bonjour $nom' ?

💬 C’est l’interpolation. Pour une expression complète, on utilise "$($objet.Propriete)".

2. Comment écrire correctement un test d’absence de valeur ?

💬 Avec une collection, l’ordre inverse peut donner un résultat inattendu : $null se place toujours à gauche.

3. Que crée @{ Nom = "PC-207"; Ram = 16 } ?

💬 Pour obtenir un objet triable et exportable, on écrit [PSCustomObject]@{ ... }.

4. Pourquoi éviter $tableau += $element dans une grande boucle ?

💬 Sur des milliers d’éléments, on utilise une List et sa méthode Add().

5. Comment demander un mot de passe sans l’afficher à l’écran ?

💬 Pour un couple identifiant/mot de passe, Get-Credential est encore préférable. L’historique de la console est enregistré sur le disque.

© 2026 Bruno Jousseaume. Ce cours est publié sous licence CC BY-NC-SA 4.0 : vous pouvez le partager et l’adapter en citant l’auteur et un lien vers cette page, sans usage commercial, et en partageant vos adaptations sous la même licence.

Pour aller plus loin

Bastion Guacamole : dépanner les connexions RDP

Une démarche méthodique pour diagnostiquer une connexion RDP qui échoue à travers le bastion : journal de guacd, tableau de diagnostic, NLA et NTLM, réseau, fiche de suivi d’incident.

Avancé⏱ 1 h 30 · 8 octobre 2026