Licence ASR
Bien plus qu'un terminal.
De l'âge de pierre à l'Open Source.
Windows était "point-and-click". L'automatisation était un enfer.
Héritage MS-DOS.
Trop basique.
Puissant mais complexe.
Faille de sécurité ambulante.
Pendant ce temps, Linux avait Bash...
Jeffrey Snover propose une idée radicale.
"Sur Unix, tout est fichier texte, donc Bash parse du texte. Sur Windows, tout est API et .NET. Nous avons besoin d'un Shell qui parse des Objets."
Nom de code du projet : Monad.
La différence fondamentale avec Bash/Linux.
Manipule du TEXTE.
ls -l | awk '{print $9}'
Nécessite du parsing (awk, sed, cut, regex). Si l'affichage change, le script
casse.
Manipule des OBJETS .NET.
Get-ChildItem | Select-Object Name
On accède aux propriétés (Name, Length, LastWriteTime). Robuste et structuré.
Guerre des langages ou alliance stratégique ?
| Critère | PowerShell (Le Gestionnaire) | Python (Le Constructeur) |
|---|---|---|
| Administration Windows | Roi absolu (AD, Exchange, O365) | Possible mais via des wrappers complexes |
| Performance Calcul | Lent (Surcharge Objets .NET) | Très rapide (Bibliothèques C/C++) |
| Linux / Mac | Possible (PowerShell Core 7) | Natif partout (Installé par défaut) |
| Complexité du code | Verbeux (Verb-Noun) mais lisible | Concis, syntaxe stricte |
Python (Nécessite souvent des librairies externes comme requests)
import requests
r = requests.get('https://api.github.com')
print(r.json()['current_user_url'])
PowerShell (Natif, pas d'installation)
$r = Invoke-RestMethod -Uri 'https://api.github.com'
Write-Host $r.current_user_url
En PowerShell, le JSON est converti implicitement en objet navigable.
Verbe-Nom : La grammaire de PowerShell.
Structure : Verbe-Nom (Singulier)
# Processus (Gestionnaire des tâches)
Get-Process -Name "chrome"
Stop-Process -Name "notepad" -Force
# Services (Daemons)
Get-Service | Where-Object Status -eq 'Stopped'
Restart-Service "Spooler"
# Fichiers
Get-ChildItem -Path "C:\Temp" -Recurse # équivalent ls -R
New-Item -Path ".\config.json" -ItemType File
Typage dynamique (mais forçable).
$maChaine = "Bonjour $env:USERNAME" # Interpolation de variable
$monEntier = 42
[int]$forceType = "100" # Casting explicite
# Tableaux (Arrays)
$monTableau = @("Rouge", "Vert", "Bleu")
$monTableau[0] # Rouge
# HashTables (Dictionnaires clé/valeur)
$config = @{
Serveur = "192.168.1.10"
Port = 8080
}
Write-Host $config.Serveur
Pas de == ou != ici !
| Opérateur | Description | Exemple |
|---|---|---|
-eq / -ne |
Égal / Différent | $a -eq 10 |
-gt / -lt |
Plus grand / Plus petit | $a -gt 5 |
-like |
Wildcard (*) | "Test" -like "T*" |
-match |
Regex | "A12" -match "[A-Z]\d{2}" |
-in / -contains |
Présence dans une liste | 5 -in (1,2,5,8) |
# Condition IF
if ($a -gt 10) { Write-Host "Grand" } else { Write-Host "Petit" }
# Boucle FOREACH (Classique)
foreach ($file in $files) { Write-Host $file.Name }
# Boucle PIPELINE (La méthode PowerShell)
Get-Service | ForEach-Object {
if ($_.Status -eq 'Stopped') {
Write-Warning "Service $($_.Name) à l'arrêt"
}
}
$_ représente l'objet courant dans le pipeline.
L'art de l'affichage.
⚠️ Les commandes Format-* détruisent l'objet pour créer de
l'affichage. À utiliser uniquement à la toute fin !
# Tableau propre (pour les yeux)
Get-Process | Sort-Object CPU -Descending | Format-Table Name, CPU -AutoSize
# Liste détaillée
Get-Service "wuauserv" | Format-List *
# GridView : L'outil magique interactif
Get-Process | Out-GridView -PassThru | Stop-Process
Format-Table
Format-List
Out-Gridview
Industrialiser le code.
function Get-SystemInfo {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]$ComputerName,
[int]$Port = 80
)
Write-Verbose "Connexion à $ComputerName..."
return [PSCustomObject]@{
Host = $ComputerName
Status = "Online"
}
}
# ❌ MAUVAIS (Syntaxe C#/Python)
Get-SystemInfo("PC-01", 8080)
# ✅ BON (Syntaxe Shell)
Get-SystemInfo -ComputerName "PC-01" -Port 8080
Regrouper des fonctions dans un fichier MonOutil.psm1.
# Importation manuelle
Import-Module ".\MonOutil.psm1"
# Lister les commandes du module
Get-Command -Module MonOutil
# Auto-loading :
# Si le module est dans $env:PSModulePath,
# PS le charge automatiquement si on appelle une fonction.
Par défaut, Windows bloque les scripts (.ps1).
Restricted : Rien ne passe.RemoteSigned : Scripts locaux OK, scripts internet doivent être signés.Bypass : Open bar (Dangereux).# Vérifier
Get-ExecutionPolicy
# Modifier (Scope CurrentUser recommandé)
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
Interopérabilité et Formats.
Conversion instantanée Objet <-> Fichier.
# Export
Get-Process | Select Name, Id, CPU | Export-Csv "proc.csv" -NoTypeInformation
Get-Service | ConvertTo-Json | Out-File "services.json"
# Import (Devient immédiatement un objet manipulable)
$users = Import-Csv "users.csv"
Write-Host "Premier user : $($users[0].Nom)"
$config = Get-Content "config.json" | ConvertFrom-Json
Write-Host $config.ApiUrl
Invoke-RestMethod parse automatiquement le JSON/XML.
$url = "https://api.github.com/users/microsoft/repos"
$repos = Invoke-RestMethod -Uri $url -Method Get
# On peut directement filtrer les résultats de l'API
$repos | Where-Object stargazers_count -gt 1000 | Select name, html_url
Indispensable pour l'orchestration Cloud moderne.
WMI, Jobs et Réseau.
Accès bas niveau (BIOS, Disques physiques, Températures).
# La méthode moderne (CIM)
Get-CimInstance -ClassName Win32_OperatingSystem | Select LastBootUpTime
Get-CimInstance -ClassName Win32_LogicalDisk |
Where-Object DriveType -eq 3 |
Select DeviceID, FreeSpace, Size
Ne bloquez pas votre console pour un scan long.
# Démarrer un job
$job = Start-Job -ScriptBlock {
Get-ChildItem -Path C:\ -Recurse -Filter *.log
}
# Vérifier l'état
Get-Job
# Récupérer les résultats
$logs = Receive-Job -Job $job -Keep
Gérer 1 serveur comme 1000.
# 1. Session interactive (comme SSH)
Enter-PSSession -ComputerName "Srv-AD-01"
# 2. Exécution de masse (Invoke-Command)
# Exécute le script sur 3 serveurs EN PARALLÈLE
Invoke-Command -ComputerName "Srv1", "Srv2", "Srv3" -ScriptBlock {
Get-Service "Spooler" | Restart-Service
}
Active Directory, Azure & SQL.
# Création
New-ADUser -Name "J.Doe" -SamAccountName "jdoe" -Path "OU=HR,DC=lan"
# Audit : Comptes inactifs depuis 90 jours
Search-ADAccount -AccountInactive -TimeSpan 90.00:00:00 |
Where-Object Enabled -eq $true |
Select Name, LastLogonDate
Connect-AzAccount
# Gestion des ressources Cloud
New-AzResourceGroup -Name "ProjetL3" -Location "WestEurope"
Get-AzVM -Status | Where-Object PowerState -eq "VM running"
Azure Cloud Shell permet de faire ça directement dans le navigateur.
Exécuter des requêtes et récupérer des objets.
# Module SqlServer
$data = Invoke-Sqlcmd -ServerInstance "DB-SRV" -Database "Prod" -Query "SELECT * FROM Users"
# Export direct des résultats SQL vers CSV
$data | Export-Csv "export_sql.csv"
Oubliez regedit.exe.
Pour PowerShell, le registre est un système de fichiers comme les autres.
PowerShell monte les ruches principales comme des lecteurs.
# Lister les lecteurs disponibles
Get-PSDrive -PSProvider Registry
On se déplace dans le registre comme dans C:\.
# Changer de lecteur (Drive)
Set-Location HKLM:
# Ou simplement : cd HKLM:
# Aller dans le dossier Run (Démarrage auto)
cd Software\Microsoft\Windows\CurrentVersion\Run
# Lister le contenu
Get-ChildItem # Ou : ls, dir
Les clés sont des "Items", les valeurs sont des "ItemProperties".
# Lire une valeur spécifique
Get-ItemProperty -Path . -Name "SecurityHealth"
# Créer une entrée (Ex: Désactiver une feature)
New-ItemProperty -Path . -Name "7Z" -Value 1 -PropertyType DWORD
# Supprimer une entrée (Nettoyage malware ?)
Remove-ItemProperty -Path . -Name "MaliciousScript"
Attention : Nécessite une console Administrateur pour HKLM.
Créer des petits outils GUI sans Visual Studio.
Add-Type -AssemblyName System.Windows.Forms
$form = New-Object System.Windows.Forms.Form
$form.Text = "Outil Admin"
$btn = New-Object System.Windows.Forms.Button
$btn.Text = "Cliquez-moi"
$btn.Add_Click({ [System.Windows.Forms.MessageBox]::Show("Bravo!") })
$form.Controls.Add($btn)
$form.ShowDialog()
Module PSWriteHTML (communauté).
New-HTML {
New-HTMLTable -Title "Processus lourds" -DataTable (Get-Process | Select -First 10)
New-HTMLChart -Title "CPU Usage" -Type Bar
} -FilePath "report.html" -Show
Rendre le terminal beau et informatif.
Affiche : Branche Git, Version .NET, Temps d'exécution, Erreurs.
winget install JanDeDobbeleer.OhMyPosh
Set-PoshPrompt -Theme atomic
Valider votre infrastructure automatiquement.
Pester n'est pas que pour les développeurs.
C'est de l'Infrastructure as Code (IaC).
On ne teste pas du code, on teste l'état de la machine.
Describe "Vérification du Serveur Web" {
Context "Sécurité Réseau" {
It "Le port 443 (HTTPS) doit être ouvert" {
# Test réel de connexion
$conn = Test-NetConnection -Port 443 -ComputerName "localhost"
$conn.TcpTestSucceeded | Should -Be $true
}
}
}
Si tout est vert, le serveur est conforme. Si c'est rouge, alerte !
Tester sans toucher à la Production.
Le Mocking remplace une commande réelle par une version simulée.
Remove-Item ou
Stop-Service.
Describe "Script de Nettoyage" {
# On 'Mock' la commande dangereuse.
# Elle ne s'exécutera pas réellement.
Mock Remove-Item { Write-Host "Fausse suppression !" }
It "Doit tenter de supprimer les vieux fichiers" {
# On lance le vrai script
Invoke-NettoyageLogs -Path "C:\Logs"
# On vérifie que le script a BIEN essayé de supprimer
Assert-MockCalled Remove-Item -Times 1
}
}
Forcer une commande à renvoyer une valeur spécifique pour tester la logique.
# On force Get-Date à renvoyer une date fixe
# pour tester un calcul d'expiration
Mock Get-Date { return [datetime]"2025-01-01" }
$resultat = MonScript-CalculAge
$resultat | Should -Be 365
Prochaine étape : Pratiquer sur des VMs !