Aller au contenu
Réussir mon BTS SIO

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

Par exemple

Chapitre 316 minDébutant

Cmdlets, objets et pipeline PowerShell

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

À la fin de ce chapitre, tu sauras

  • trouver une cmdlet et lire son aide ;
  • lire les propriétés d'un objet avec Get-Member ;
  • filtrer, trier, regrouper et mesurer des objets dans le pipeline ;
  • appliquer la règle « filtrer à gauche, mettre en forme à droite ».

4 exercices corrigés1 schéma

Une cmdlet est une commande PowerShell de la forme Verbe-Nom, comme Get-Service ou New-ADUser, qui renvoie des objets et non du texte. Le pipeline | transmet ces objets d'une commande à la suivante, qui peut les filtrer, les trier, les regrouper ou les exporter en utilisant leurs propriétés par leur nom. Ce chapitre t'apprend à trouver la bonne commande, à lire un objet et à construire des pipelines qui répondent à une question d'administration en une ligne.

Anatomie d'une cmdlet

powershell
Get-Service -Name Spooler, W32Time -DependentServices

Le verbe dit l'action, le nom dit sur quoi elle porte, les paramètres commencent par un tiret. Les verbes sont normalisés : Get-Verb affiche la liste des verbes approuvés.

Dans Windows PowerShell 5.1, Get-Service accepte aussi -ComputerName srv-ad pour interroger un autre serveur ; ce paramètre n'existe plus dans PowerShell 7, où l'on passe par Invoke-Command (chapitre 11).

VerbeActionExemples
GetLire, sans rien modifierGet-Service, Get-ADUser, Get-ChildItem
SetModifier un objet existantSet-Service, Set-ADUser, Set-Content
NewCréerNew-Item, New-ADUser, New-SmbShare
RemoveSupprimerRemove-Item, Remove-ADUser
AddAjouter à un ensembleAdd-ADGroupMember, Add-Content
Start, Stop, RestartDémarrer, arrêterRestart-Service, Stop-Computer
Enable, DisableActiver, désactiverDisable-ADAccount, Enable-NetFirewallRule
TestVérifier, renvoie souvent vrai ou fauxTest-Path, Test-Connection, Test-NetConnection
Import, ExportLire ou écrire un fichier structuréImport-Csv, Export-Csv

Les paramètres ont trois formes :

  • nommé : -Name Spooler ;
  • positionnel : Get-Service Spooler, le premier argument sans nom va au paramètre -Name ;
  • commutateur (switch), sans valeur : Get-ChildItem -Recurse, Remove-Item -WhatIf.

Toutes les cmdlets acceptent aussi des paramètres communs : -Verbose (affiche le détail), -ErrorAction (que faire en cas d'erreur, chapitre 7) et, pour celles qui modifient quelque chose, -WhatIf (montre ce qui serait fait sans le faire) et -Confirm (demande une confirmation).

Les alias. ls, dir et gci sont trois alias de Get-ChildItem ; cd de Set-Location, cat de Get-Content, % de ForEach-Object, ? de Where-Object. Ils font gagner du temps au clavier, mais dans un script, écris toujours le nom complet : le script se lit sans connaître les alias, et sous Linux, ls lance le vrai programme ls, pas Get-ChildItem.

Trouver la commande et lire son aide

Tu n'as pas à connaître les milliers de cmdlets par cœur. Trois commandes suffisent pour trouver et comprendre celle qu'il te faut.

powershell
Get-Command -Noun *DnsServerResourceRecord*   # toutes les commandes sur les enregistrements DNS
Get-Command -Verb Get -Module SmbShare        # les commandes de lecture du module des partages
Get-Help Get-ChildItem -Examples              # des exemples prêts à adapter
Get-Help Get-ChildItem -Parameter Filter      # le détail d'un paramètre
Get-Help about_Comparison_Operators           # les rubriques « about_ » expliquent le langage
Update-Help -UICulture en-US                  # télécharger l'aide complète, en anglais

La touche Tab complète les noms de commandes, de paramètres et même de valeurs (Get-Service -Name Sp puis Tab). Ctrl+Espace affiche toutes les possibilités. Get-Help -Online ouvre la page de documentation dans le navigateur.

Un objet : des propriétés et des méthodes

Une cmdlet Get- renvoie des objets. Chacun a des propriétés (des valeurs : nom, état, taille) et des méthodes (des actions qu'on peut lui demander). Get-Member affiche les deux.

powershell
$spouleur = Get-Service -Name Spooler
$spouleur | Get-Member -MemberType Property

Le résultat commence par le type de l'objet, System.ServiceProcess.ServiceController, puis donne une ligne par propriété, avec son type : CanStop (bool), DependentServices (la liste des services qui en dépendent), DisplayName (string), ServiceName (string), StartType (le mode de démarrage), Status (l'état). PowerShell 7 en ajoute quelques-unes, comme Description ou UserName, le compte qui fait tourner le service. On lit une propriété avec un point :

powershell
$spouleur.Status        # Running
$spouleur.StartType     # Automatic
$spouleur.DisplayName   # Spouleur d'impression

Ce que PowerShell affiche n'est qu'un résumé de l'objet, choisi par un fichier de format. Get-Service montre trois colonnes, mais chaque service en a bien plus : Select-Object * ou Format-List * les montre toutes.

Le pipeline : des objets d'une commande à l'autre

Le pipeline | envoie chaque objet produit par la commande de gauche à la commande de droite, un par un. Chaque commande du milieu reçoit des objets complets et en renvoie d'autres.

Get-Serviceproduit tous les servicesWhere-ObjectAutomatic et StoppedSort-Object Nametri par nomSelect-Objectgarde Name et StatusDNSRunningAutomaticSpoolerStoppedAutomaticFaxStoppedManualBITSStoppedAutomaticDNSécartéSpoolergardéFaxécartéBITSgardéBITSStoppedAutomaticSpoolerStoppedAutomaticBITSStoppedSpoolerStoppeddes objets complets,aux propriétés nomméesEn Bash : des lignes de textesystemctl list-units … | awk '{print $2}'à découper en colonnes
En PowerShell, le pipeline transporte des objets entiers ; en Bash, des lignes de texte à découper

Les six cmdlets de pipeline à connaître :

CmdletRôleExemple
Where-ObjectGarder les objets qui vérifient une conditionWhere-Object Status -eq 'Stopped'
Select-ObjectGarder certaines propriétés, ou les premiers objetsSelect-Object Name, Status -First 5
Sort-ObjectTrierSort-Object Length -Descending
Group-ObjectRegrouper et compterGroup-Object Department
Measure-ObjectCompter, additionner, moyenne, minimum, maximumMeasure-Object Length -Sum
ForEach-ObjectFaire une action pour chaque objetForEach-Object { $_.Name.ToUpper() }

Dans un bloc de script { … } du pipeline, $_ (ou $PSItem, son nom long) désigne l'objet en cours. Where-Object a deux syntaxes équivalentes :

powershell
# Syntaxe complète : un bloc de script, qui accepte plusieurs conditions
Get-Service | Where-Object { $_.StartType -eq 'Automatic' -and $_.Status -eq 'Stopped' }

# Syntaxe simplifiée : une seule condition, sans $_ ni accolades
Get-Service | Where-Object Status -eq 'Stopped'

Un exemple pas à pas

Pour t'exercer sans dépendre de ton poste, crée une petite liste d'objets qui décrit l'espace disque des serveurs de Sorbier. [pscustomobject] fabrique un objet à partir d'une table de propriétés (chapitre 4) :

powershell
$disques = @(
    [pscustomobject]@{ Serveur = 'srv-ad';       Lecteur = 'C'; TailleGo = 80;   LibreGo = 31 }
    [pscustomobject]@{ Serveur = 'srv-ad2';      Lecteur = 'C'; TailleGo = 80;   LibreGo = 12 }
    [pscustomobject]@{ Serveur = 'srv-fichiers'; Lecteur = 'C'; TailleGo = 120;  LibreGo = 9 }
    [pscustomobject]@{ Serveur = 'srv-fichiers'; Lecteur = 'D'; TailleGo = 2000; LibreGo = 410 }
    [pscustomobject]@{ Serveur = 'srv-gestion';  Lecteur = 'C'; TailleGo = 100;  LibreGo = 7 }
)
$disques
text
Serveur      Lecteur TailleGo LibreGo
-------      ------- -------- -------
srv-ad       C             80      31
srv-ad2      C             80      12
srv-fichiers C            120       9
srv-fichiers D           2000     410
srv-gestion  C            100       7

Les disques qui ont moins de 15 Go libres, du plus plein au moins plein :

powershell
$disques | Where-Object LibreGo -lt 15 | Sort-Object LibreGo | Select-Object Serveur, Lecteur, LibreGo
text
Serveur      Lecteur LibreGo
-------      ------- -------
srv-gestion  C             7
srv-fichiers C             9
srv-ad2      C            12

Le total d'espace libre, et le nombre de disques par serveur :

powershell
($disques | Measure-Object -Property LibreGo -Sum).Sum
$disques | Group-Object Serveur | Select-Object Name, Count
text
469

Name         Count
----         -----
srv-ad           1
srv-ad2          1
srv-fichiers     2
srv-gestion      1

Measure-Object renvoie un objet dont la propriété Sum contient le total : les parenthèses exécutent le pipeline d'abord, puis .Sum lit la propriété du résultat.

Les propriétés calculées

Select-Object peut créer une colonne qui n'existe pas, à partir des autres. On lui donne une table avec un nom (Name) et un bloc de calcul (Expression) :

powershell
$disques | Select-Object Serveur, Lecteur,
    @{ Name = 'PctLibre'; Expression = { [math]::Round($_.LibreGo / $_.TailleGo * 100) } }
text
Serveur      Lecteur PctLibre
-------      ------- --------
srv-ad       C             39
srv-ad2      C             15
srv-fichiers C              8
srv-fichiers D             20
srv-gestion  C              7

Filtrer à gauche, mettre en forme à droite

Deux règles font la différence entre un pipeline rapide et juste, et un pipeline lent ou faux.

Filtrer le plus tôt possible. Quand la commande de départ sait filtrer elle-même, laisse-la faire : elle ne produit que les objets utiles, au lieu de tout produire pour que Where-Object jette le reste.

powershell
# Lent : parcourt tout D:\Partages, puis jette ce qui n'est pas un .log
Get-ChildItem -Path D:\Partages -Recurse | Where-Object Extension -eq '.log'

# Rapide : le système de fichiers ne renvoie que les .log
Get-ChildItem -Path D:\Partages -Recurse -Filter *.log

C'est encore plus vrai pour l'annuaire : Get-ADUser -Filter "Department -eq 'Comptabilité'" demande au contrôleur de domaine les seuls comptes voulus, alors que Get-ADUser -Filter * | Where-Object … rapatrie tout l'annuaire sur le réseau.

Mettre en forme en dernier. Format-Table et Format-List transforment les objets en instructions d'affichage. Après eux, il n'y a plus de propriétés à trier ou à exporter : ils se placent tout à la fin, et jamais avant Export-Csv.

powershell
# Faux : le CSV contient des lignes de mise en forme illisibles
Get-Service | Format-Table Name, Status | Export-Csv services.csv

# Juste : Select-Object garde des objets, Export-Csv les écrit
Get-Service | Select-Object Name, Status | Export-Csv services.csv -NoTypeInformation

Afficher ou renvoyer : Write-Output et Write-Host

Write-Output envoie des objets dans le pipeline : ils peuvent être stockés dans une variable, filtrés, exportés. Write-Host écrit directement à l'écran, en couleur si on veut, mais ce texte ne part pas dans le pipeline.

powershell
$a = Write-Output "rapport"   # $a contient "rapport"
$b = Write-Host "rapport"     # « rapport » s'affiche, $b est vide

Dans un script, renvoie les résultats avec Write-Output (ou en écrivant simplement la valeur), et réserve Write-Host aux messages destinés à la personne devant l'écran. Pour les messages de suivi, PowerShell a des flux séparés, que l'on peut rediriger chacun vers un fichier :

FluxNuméroCmdletAffiché par défaut
Succès (les résultats)1Write-OutputOui
Erreur2Write-ErrorOui, en rouge
Avertissement3Write-WarningOui, en jaune
Détail4Write-VerboseNon, sauf avec -Verbose
Débogage5Write-DebugNon, sauf avec -Debug
Information6Write-Information, Write-HostOui pour Write-Host
powershell
.\Rapport.ps1 2> erreurs.txt      # les erreurs dans un fichier, le reste à l'écran
.\Rapport.ps1 *> tout.txt         # tous les flux dans le même fichier
.\Rapport.ps1 | Out-File rapport.txt -Encoding utf8

Exercices

Exercice 1 sur 4 Trouver la commande Réussi À revoir

Sans chercher sur Internet, quelle commande tapes-tu pour :

  1. lister toutes les commandes qui contiennent « Firewall » dans leur nom ;
  2. voir des exemples d'utilisation de Test-NetConnection ;
  3. connaître toutes les propriétés des objets renvoyés par Get-ChildItem sur un fichier ;
  4. savoir de quelle commande gci est l'alias ?
Voir la réponseMasquer la réponse de l'exercice 1
  1. Get-Command *Firewall* (ou Get-Command -Noun *Firewall* pour chercher dans la partie nom seulement).
  2. Get-Help Test-NetConnection -Examples.
  3. Get-ChildItem C:\Windows\notepad.exe | Get-Member -MemberType Property, ou Get-Item C:\Windows\notepad.exe | Select-Object * pour voir aussi les valeurs.
  4. Get-Alias gci, qui répond gci -> Get-ChildItem.

Tu avais trouvé ?

Exercice 2 sur 4 Écrire le pipeline Réussi À revoir

Avec la variable $disques de ce chapitre, écris le pipeline qui :

  1. affiche les disques C seulement, avec le serveur et l'espace libre ;
  2. affiche le serveur qui a le moins d'espace libre, et seulement lui ;
  3. calcule l'espace libre total des disques C ;
  4. affiche les disques avec une colonne OccupeGo (taille moins espace libre), triés par OccupeGo décroissant.

Donne aussi le résultat des questions 2 et 3.

Voir la réponseMasquer la réponse de l'exercice 2
powershell
# 1.
$disques | Where-Object Lecteur -eq 'C' | Select-Object Serveur, LibreGo
# 2.
$disques | Sort-Object LibreGo | Select-Object -First 1
# 3.
($disques | Where-Object Lecteur -eq 'C' | Measure-Object -Property LibreGo -Sum).Sum
# 4.
$disques | Select-Object Serveur, Lecteur, @{ Name = 'OccupeGo'; Expression = { $_.TailleGo - $_.LibreGo } } |
    Sort-Object OccupeGo -Descending

Pour la question 2, le résultat est le disque C de srv-gestion, avec 7 Go libres. Pour la question 3 : 31 + 12 + 9 + 7 = 59. Le disque D de srv-fichiers (410 Go) est exclu par le filtre. Pour la question 4, l'ordre obtenu est srv-fichiers D (1590), srv-fichiers C (111), srv-gestion (93), srv-ad2 (68), srv-ad (49).

Tu avais trouvé ?

Exercice 3 sur 4 Trouve l'erreur Réussi À revoir

Chacun de ces pipelines ne donne pas le résultat attendu. Explique pourquoi.

  1. Get-Process | Format-Table Name, CPU | Sort-Object CPU -Descending
  2. $r = Get-Service | Where-Object Status -eq 'Stopped' | Write-Host puis $r.Count
  3. Get-ChildItem C:\Scripts | Where-Object { Extension -eq '.ps1' }
Voir la réponseMasquer la réponse de l'exercice 3
  1. Format-Table est placé avant Sort-Object : il produit des instructions d'affichage, qui n'ont plus de propriété CPU. Le tri ne fonctionne pas et l'affichage est incohérent. Il faut trier d'abord : Get-Process | Sort-Object CPU -Descending | Format-Table Name, CPU.
  2. Write-Host affiche les services à l'écran mais ne renvoie rien dans le pipeline : $r est vide et $r.Count vaut 0. Il faut supprimer | Write-Host pour que $r reçoive les objets.
  3. Dans un bloc de script, la propriété s'écrit $_.Extension. Écrite seule, Extension est prise pour une commande, qui n'existe pas : erreur « Le terme Extension n'est pas reconnu ». Correction : Where-Object { $_.Extension -eq '.ps1' }, ou la syntaxe simplifiée Where-Object Extension -eq '.ps1'. Mieux encore, filtrer à gauche : Get-ChildItem C:\Scripts -Filter *.ps1.

Tu avais trouvé ?

Exercice 4 sur 4 L'arrondi surprise Réussi À revoir

Un technicien calcule le pourcentage d'espace libre avec [math]::Round($_.LibreGo / $_.TailleGo * 100). Pour un disque de 2000 Go avec 410 Go libres, il obtient 20 et s'attendait à 21. Pour un disque de 120 Go avec 9 Go libres, il obtient 8. Explique ces deux résultats et corrige le calcul pour obtenir l'arrondi « scolaire ».

Voir la réponseMasquer la réponse de l'exercice 4

410 / 2000 × 100 = 20,5 et 9 / 120 × 100 = 7,5 : les deux valeurs sont exactement à mi-chemin. [math]::Round applique par défaut l'arrondi au pair le plus proche : 20,5 va vers 20 (pair) et 7,5 vers 8 (pair). Pour arrondir toujours vers le haut à mi-chemin :

powershell
[math]::Round($_.LibreGo / $_.TailleGo * 100, [MidpointRounding]::AwayFromZero)

qui donne 21 et 8. Pour un indicateur d'espace disque, l'écart d'un point n'a pas d'importance ; pour un montant ou une note, il en a.

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 : PowerShell : variables, conditions et bouclesRevoir le sommaire du cours