1. Services
Get-Service # tous les services
Get-Service -Name Spooler | Format-List * # toutes les propriétés
Get-Service | Where-Object { $_.Status -eq "Stopped" -and $_.StartType -eq "Automatic" }
Start-Service -Name Spooler
Restart-Service -Name Spooler -Force
Stop-Service -Name Spooler -WhatIf
Set-Service -Name Spooler -StartupType Manual # nécessite les droits administrateur
Services automatiques arrêtés : un classique du diagnostic
Get-Service | Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
Select-Object Name, DisplayName, Status
2. Processus
Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 Name, Id, CPU
Get-Process -Name notepad | Stop-Process -WhatIf
Start-Process notepad
Start-Process "notepad" -ArgumentList "C:\Temp\note.txt"
# Qui a lancé ce processus, et depuis quel exécutable ?
Get-CimInstance Win32_Process -Filter "Name = 'notepad.exe'" |
Select-Object ProcessId, ExecutablePath, CommandLine
3. Système et matériel : CIM
CIM (successeur de WMI) donne accès à l’inventaire complet de la machine.
| Classe | Contenu |
|---|---|
Win32_OperatingSystem | Version, date d’installation, dernier démarrage |
Win32_ComputerSystem | Modèle, fabricant, mémoire totale, domaine |
Win32_BIOS | Numéro de série, version du BIOS |
Win32_LogicalDisk | Disques logiques, taille et espace libre |
Win32_Processor | Processeur, nombre de cœurs |
Win32_NetworkAdapterConfiguration | Configuration IP détaillée |
$os = Get-CimInstance Win32_OperatingSystem
$os.LastBootUpTime
(New-TimeSpan -Start $os.LastBootUpTime).Days # uptime en jours
(Get-CimInstance Win32_BIOS).SerialNumber # numéro de série (inventaire)
Get-CimInstance Win32_LogicalDisk -Filter "DriveType = 3" |
Select-Object DeviceID,
@{N = "TailleGo"; E = { [math]::Round($_.Size / 1GB, 1) }},
@{N = "LibreGo"; E = { [math]::Round($_.FreeSpace / 1GB, 1) }},
@{N = "Libre%"; E = { [math]::Round($_.FreeSpace / $_.Size * 100, 1) }}
4. Réseau
| Commande | Remplace | Usage |
|---|---|---|
Get-NetIPConfiguration | ipconfig | Vue d’ensemble d’une interface |
Get-NetIPAddress | ipconfig /all | Adresses détaillées |
Test-NetConnection | ping, telnet | Test d’accès, y compris sur un port |
Resolve-DnsName | nslookup | Résolution DNS |
Get-NetTCPConnection | netstat | Connexions et ports en écoute |
Get-NetAdapter | — | État des cartes réseau |
Test-NetConnection -ComputerName srv-fichiers -Port 445
Test-NetConnection www.wikipedia.org -InformationLevel Detailed
Resolve-DnsName lycee-chevrollier.fr -Type A
# Ports en écoute et processus associé : diagnostic et sécurité
Get-NetTCPConnection -State Listen |
Select-Object LocalAddress, LocalPort, OwningProcess,
@{N = "Processus"; E = { (Get-Process -Id $_.OwningProcess).Name }} |
Sort-Object LocalPort
5. Registre
Le registre s’explore comme un système de fichiers, avec les mêmes commandes.
Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" |
Select-Object ProductName, DisplayVersion, CurrentBuild
# Écriture (console administrateur)
New-Item -Path "HKCU:\Software\Lycee" -Force | Out-Null
New-ItemProperty -Path "HKCU:\Software\Lycee" -Name "Salle" -Value "207" -PropertyType String -Force
Get-ItemPropertyValue -Path "HKCU:\Software\Lycee" -Name "Salle"
Remove-Item "HKCU:\Software\Lycee" -Recurse
6. Journaux d’événements
# Le journal système, 20 dernières entrées
Get-WinEvent -LogName System -MaxEvents 20 | Select-Object TimeCreated, Id, LevelDisplayName, Message
# Filtrage efficace (FilterHashtable filtre côté journal, donc rapide)
Get-WinEvent -FilterHashtable @{
LogName = "System"
Level = 2 # 2 = erreur
StartTime = (Get-Date).AddDays(-7)
} | Group-Object ProviderName | Sort-Object Count -Descending | Select-Object Count, Name
# Échecs d'ouverture de session (journal Sécurité, console administrateur)
Get-WinEvent -FilterHashtable @{ LogName = "Security"; Id = 4625; StartTime = (Get-Date).AddDays(-1) } |
Select-Object TimeCreated, @{N = "Compte"; E = { $_.Properties[5].Value }}
7. Comptes locaux et logiciels
Get-LocalUser | Select-Object Name, Enabled, LastLogon, PasswordExpires
Get-LocalGroupMember -Group "Administrateurs"
New-LocalUser -Name "tpuser" -Description "Compte de TP" -NoPassword
Add-LocalGroupMember -Group "Utilisateurs" -Member "tpuser"
Disable-LocalUser -Name "tpuser"
Remove-LocalUser -Name "tpuser"
# Logiciels installés : le registre est plus fiable que Win32_Product
$chemins = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
)
Get-ItemProperty $chemins -ErrorAction SilentlyContinue |
Where-Object DisplayName |
Select-Object DisplayName, DisplayVersion, Publisher, InstallDate |
Sort-Object DisplayName
8. Mini-projet : le rapport de diagnostic du poste
9. Bilan
Exercices corrigés
Tous ces exercices se pratiquent sur une machine virtuelle de test. Les commandes de lecture sont sans danger, mais les habitudes se prennent sur la maquette.
Exercice 5.1 — Services et processus
Voir le corrigé
# 1.
Get-Service | Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
Select-Object Name, DisplayName, Status |
Export-Csv "$env:USERPROFILE\Desktop\services-ko.csv" -Delimiter ";" -Encoding UTF8 -NoTypeInformation
# 2.
Get-Process -IncludeUserName |
Sort-Object WorkingSet -Descending |
Select-Object -First 10 Name, Id, UserName,
@{N = "Mo"; E = { [math]::Round($_.WorkingSet / 1MB, 1) }}
# 3.
function Restart-ServiceSafe {
[CmdletBinding(SupportsShouldProcess)]
param([Parameter(Mandatory)][string]$Nom)
$service = Get-Service -Name $Nom -ErrorAction SilentlyContinue
if (-not $service) {
Write-Warning "Service $Nom introuvable"
return
}
if ($service.Status -eq "Running") {
Write-Verbose "$Nom fonctionne déjà"
return
}
if ($PSCmdlet.ShouldProcess($Nom, "Démarrage")) {
try {
Start-Service -Name $Nom -ErrorAction Stop
"$(Get-Date -Format s) - $Nom démarré par $env:USERNAME" | Add-Content services.log
}
catch { Write-Error "Échec du démarrage de $Nom : $($_.Exception.Message)" }
}
}
Explication
-IncludeUserName exige une console administrateur : sans cela, la commande échoue avec un message explicite. Restart-ServiceSafe illustre le bon ordre : vérifier l’existence, vérifier l’état, agir seulement si nécessaire.
Exercice 5.2 — Diagnostic réseau
Voir le corrigé
# 1.
Get-NetIPConfiguration | Select-Object InterfaceAlias, IPv4Address, IPv4DefaultGateway, DNSServer
# 2.
foreach ($site in "www.wikipedia.org", "www.education.gouv.fr") {
$ok = (Test-NetConnection $site -Port 443 -WarningAction SilentlyContinue).TcpTestSucceeded
"{0} : {1}" -f $site, $(if ($ok) { "OK" } else { "Échec" })
}
# 3.
Get-NetTCPConnection -State Listen |
Select-Object LocalPort, OwningProcess,
@{N = "Processus"; E = { (Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Name }} |
Sort-Object LocalPort
# 4.
function Test-SiteWeb {
param([string[]]$Domaine)
foreach ($d in $Domaine) {
$dns = $null
try { $dns = Resolve-DnsName $d -Type A -ErrorAction Stop } catch {}
$test = Test-NetConnection $d -Port 443 -WarningAction SilentlyContinue
[PSCustomObject]@{
Site = $d
DnsOk = [bool]$dns
Port443 = $test.TcpTestSucceeded
TempsMs = $test.PingReplyDetails.RoundtripTime
}
}
}
Test-SiteWeb -Domaine "www.wikipedia.org", "serveur-inexistant.local" | Format-Table -AutoSize
Explication
Test-NetConnection renvoie un objet complet : TcpTestSucceeded pour le port, PingSucceeded pour ICMP, RoundtripTime pour le délai. -WarningAction SilentlyContinue masque l’avertissement quand le ping échoue mais que le port répond.
Exercice 5.3 — Audit du poste
Voir le corrigé
# 1.
Get-LocalUser | Where-Object Enabled | Select-Object Name, LastLogon
Get-LocalGroupMember -Group "Administrateurs"
# 2.
Get-WinEvent -FilterHashtable @{ LogName = "System"; Level = 2; StartTime = (Get-Date).AddDays(-7) } |
Group-Object ProviderName | Sort-Object Count -Descending | Select-Object Count, Name
# 3.
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" | ForEach-Object {
if (Test-Path $_) {
Get-ItemProperty $_ | Select-Object -Property * -ExcludeProperty PS*
}
}
# 4.
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue |
Where-Object DisplayName |
Select-Object DisplayName, DisplayVersion, Publisher |
Sort-Object DisplayName |
Export-Csv "$env:USERPROFILE\Desktop\logiciels.csv" -Delimiter ";" -Encoding UTF8 -NoTypeInformation
Explication
Get-WinEvent -FilterHashtable filtre côté journal, ce qui est incomparablement plus rapide que Get-WinEvent | Where-Object. La recherche dans les descriptions utilise -match avec (?i) pour ignorer la casse.
Pour aller plus loin
Ajoute -ErrorAction SilentlyContinue sur Get-WinEvent : si aucun événement ne correspond, la cmdlet considère cela comme une erreur.
Mini-projet
Voir le corrigé
[CmdletBinding()]
param(
[string]$CheminRapport = "$env:USERPROFILE\Desktop\diagnostic_$env:COMPUTERNAME.html",
[int]$SeuilDisquePct = 15
)
$os = Get-CimInstance Win32_OperatingSystem
$identite = [PSCustomObject]@{
Machine = $env:COMPUTERNAME
Systeme = $os.Caption
Version = $os.Version
UptimeJours = (New-TimeSpan -Start $os.LastBootUpTime).Days
Date = Get-Date
}
$disques = Get-CimInstance Win32_LogicalDisk -Filter "DriveType = 3" |
Select-Object DeviceID,
@{N = "LibreGo"; E = { [math]::Round($_.FreeSpace / 1GB, 1) }},
@{N = "LibrePct"; E = { [math]::Round($_.FreeSpace / $_.Size * 100, 1) }},
@{N = "Alerte"; E = { if (($_.FreeSpace / $_.Size * 100) -lt $SeuilDisquePct) { "OUI" } else { "" } }}
$servicesKo = Get-Service | Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
Select-Object Name, DisplayName
$processus = Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 5 Name, Id,
@{N = "Mo"; E = { [math]::Round($_.WorkingSet / 1MB, 1) }}
$reseau = Get-NetIPConfiguration | Select-Object InterfaceAlias, IPv4Address, IPv4DefaultGateway
$internet = (Test-NetConnection www.wikipedia.org -Port 443 -WarningAction SilentlyContinue).TcpTestSucceeded
$erreurs = Get-WinEvent -FilterHashtable @{ LogName = "System"; Level = 2; StartTime = (Get-Date).AddDays(-7) } -ErrorAction SilentlyContinue |
Group-Object ProviderName | Sort-Object Count -Descending | Select-Object Count, Name -First 10
$admins = Get-LocalGroupMember -Group "Administrateurs" | Select-Object Name, ObjectClass
$style = "<style>body{font-family:Segoe UI,sans-serif;margin:2rem}table{border-collapse:collapse;margin-bottom:2rem}
th{background:#1A1A1A;color:#fff;text-align:left;padding:6px 10px}td{border-bottom:1px solid #ccc;padding:4px 10px}h2{margin-top:2rem}</style>"
$corps = @(
($identite | ConvertTo-Html -Fragment -PreContent "<h2>Identité</h2>")
($disques | ConvertTo-Html -Fragment -PreContent "<h2>Disques</h2>")
($servicesKo | ConvertTo-Html -Fragment -PreContent "<h2>Services automatiques arrêtés</h2>")
($processus | ConvertTo-Html -Fragment -PreContent "<h2>Processus les plus gourmands</h2>")
($reseau | ConvertTo-Html -Fragment -PreContent "<h2>Réseau (Internet : $internet)</h2>")
($erreurs | ConvertTo-Html -Fragment -PreContent "<h2>Erreurs système (7 jours)</h2>")
($admins | ConvertTo-Html -Fragment -PreContent "<h2>Administrateurs locaux</h2>")
) -join "`n"
ConvertTo-Html -Head $style -Body $corps -Title "Diagnostic $env:COMPUTERNAME" |
Out-File $CheminRapport -Encoding utf8
[PSCustomObject]@{
Machine = $env:COMPUTERNAME
ServicesArretes = $servicesKo.Count
DisquesEnAlerte = ($disques | Where-Object Alerte).Count
InternetOk = $internet
Rapport = $CheminRapport
}
Explication
Le rapport assemble des fragments HTML produits séparément. Chaque section reste un objet jusqu’au dernier moment, ce qui permet à la fois le rendu HTML et la sortie d’un résumé exploitable.
Pour aller plus loin
Pour un rendu plus soigné, remplace le CSS en ligne par une feuille de style commune à tous tes rapports : ils deviennent reconnaissables et lisibles par n’importe quel collègue.
🧠 Testez vos connaissances
5 questions. Répondez puis cliquez sur « Corriger ». Rien n’est enregistré : c’est de l’auto-évaluation.
© 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.