20 commandes PowerShell essentielles que tout administrateur système d'entreprise doit connaître en 2026

20 commandes PowerShell essentielles que tout administrateur système d'entreprise doit connaître en 2026

Il existe un décalage entre ce que l'on apprend dans les formations PowerShell et sa mise en pratique quotidienne en entreprise. Les formations abordent la syntaxe, mais le travail en entreprise exige une maîtrise des bonnes pratiques : celles qui permettent de gérer 200 machines depuis un seul terminal, de repérer les comptes inactifs avant un audit et de diagnostiquer une panne de spouleur d'impression sur trois sites avant même que le café ne refroidisse. Ce guide présente 20 commandes et pratiques PowerShell essentielles utilisées quotidiennement par les administrateurs système : exécution à distance, requêtes Active Directory, gestion des disques, analyse des journaux d'événements, diagnostics réseau, opérations sur le registre et génération de rapports automatisés. Tous les exemples sont prêts pour la production et ont été testés sur Windows Server 2019/2022 avec PowerShell 5.1 et 7.x.

1. Exécution à distance à grande échelle avec Invoke-Command

Automatisation d'entreprise par scripts PowerShell
PowerShell — la base de l'automatisation d'entreprise pour les administrateurs système Windows

Invoke-Command est essentiel à l'administration de systèmes Windows à grande échelle. Au lieu de se connecter à 50 machines une par une via RDP, vous déployez un bloc de script simultanément sur l'ensemble du réseau. Le paramètre -ThrottleLimit évite la saturation du réseau.

# Run a command on all workstations in an OU — 20 at a time
$computers = Get-ADComputer -Filter * -SearchBase "OU=Workstations,DC=corp,DC=local" |
    Select-Object -ExpandProperty Name

Invoke-Command -ComputerName $computers -ScriptBlock {
    Get-Service -Name "wuauserv" | Select-Object Name, Status, StartType
} -ThrottleLimit 20 | Sort-Object PSComputerName

Ajoutez -AsJob pour exécuter de manière asynchrone et Receive-Job plus tard pour collecter les résultats sans bloquer votre session.

2. Trouver les comptes AD inactifs

Les comptes utilisateurs inactifs représentent un risque pour la sécurité. Ce script permet de trouver tous les comptes activés qui ne se sont pas connectés depuis 90 jours et de les exporter au format CSV pour l'équipe de sécurité.

# Find all enabled accounts inactive for 90+ days
$cutoff = (Get-Date).AddDays(-90)
Get-ADUser -Filter {LastLogonDate -lt $cutoff -and Enabled -eq $true} `
    -Properties LastLogonDate, Department, Manager |
    Select-Object Name, SamAccountName, Department, LastLogonDate, Manager |
    Export-Csv -Path "C:Reportsinactive_users_$(Get-Date -f yyyyMMdd).csv" -NoTypeInformation

# Count by department
Get-ADUser -Filter {LastLogonDate -lt $cutoff -and Enabled -eq $true} `
    -Properties LastLogonDate, Department |
    Group-Object Department |
    Sort-Object Count -Descending

3. Lister tous les membres d'un groupe de sécurité (récursif)

Gestion à distance PowerShell d'une flotte Windows
Invoke-Command permet d'exécuter des scripts PowerShell simultanément sur des centaines de machines.

Les appartenances à des groupes imbriqués sont un véritable fléau lors des audits Active Directory. L'indicateur -Recursive sur Get-ADGroupMember permet d'obtenir une liste d'utilisateurs simple et claire.

# Recursively list all members of Domain Admins (including nested groups)
Get-ADGroupMember -Identity "Domain Admins" -Recursive |
    Get-ADUser -Properties DisplayName, EmailAddress, LastLogonDate |
    Select-Object DisplayName, SamAccountName, EmailAddress, LastLogonDate |
    Format-Table -AutoSize

4. Espace disque sur l'ensemble du domaine

Le manque d'espace disque interrompt silencieusement les services. Exécutez cette commande avant votre réunion hebdomadaire pour détecter les problèmes au plus tôt.

# Disk usage on every machine in the domain — filter under 10GB free
Invoke-Command -ComputerName (Get-ADComputer -Filter *).Name -ScriptBlock {
    Get-PSDrive -PSProvider FileSystem |
    Select-Object Name,
        @{N='Used(GB)'; E={[math]::Round($_.Used/1GB, 2)}},
        @{N='Free(GB)'; E={[math]::Round($_.Free/1GB, 2)}},
        @{N='Total(GB)'; E={[math]::Round(($_.Used+$_.Free)/1GB, 2)}}
} | Where-Object {$_.'Free(GB)' -lt 10} | Sort-Object 'Free(GB)'

5. Identifier les fichiers volumineux qui consomment de l'espace disque

# Find all files larger than 1 GB on C:
Get-ChildItem -Path "C:" -Recurse -ErrorAction SilentlyContinue |
    Where-Object {$_.Length -gt 1GB} |
    Sort-Object Length -Descending |
    Select-Object FullName, @{N='Size(GB)'; E={[math]::Round($_.Length/1GB, 2)}} |
    Select-Object -First 20

6. Arrêter un processus sur une machine distante

Lorsqu'une application bloquée empêche un utilisateur d'accéder à la machine via RDP, voici la solution à privilégier.

# Kill Chrome on a remote workstation without interrupting other processes
Invoke-Command -ComputerName "PC-USER-01" -ScriptBlock {
    $procs = Get-Process -Name "chrome" -ErrorAction SilentlyContinue
    if ($procs) {
        $procs | Stop-Process -Force
        Write-Output "Killed $($procs.Count) Chrome process(es)"
    } else {
        Write-Output "Chrome not running"
    }
}

7. Redémarrer un service sur plusieurs serveurs

# Restart the Print Spooler on three servers and confirm
"SRV-PRINT-01","SRV-PRINT-02","SRV-PRINT-03" | ForEach-Object {
    Invoke-Command -ComputerName $_ -ScriptBlock {
        Restart-Service -Name "Spooler" -Force
        $svc = Get-Service -Name "Spooler"
        Write-Output "$env:COMPUTERNAME: Spooler is $($svc.Status)"
    }
}

8. Consulter le journal des événements système pour identifier les erreurs critiques

# Last 50 critical or error events from the System log
Get-WinEvent -LogName System -MaxEvents 200 |
    Where-Object {$_.Level -in @(1,2)} |
    Select-Object TimeCreated, Id, LevelDisplayName,
        @{N='Msg'; E={$_.Message.Substring(0, [Math]::Min(100,$_.Message.Length))}} |
    Format-Table -AutoSize -Wrap

9. Détecter les tentatives d'attaque par force brute RDP

L'événement ID 4625 (échec de connexion) constitue un signal d'alerte précoce en cas d'attaques par force brute. Les échecs sont regroupés par adresse IP source et triés par nombre.

# Detect RDP brute force — group failed logins by source IP
$failures = Get-WinEvent -LogName Security -MaxEvents 5000 -ErrorAction SilentlyContinue |
    Where-Object {$_.Id -eq 4625}

$failures | ForEach-Object {
    $msg = $_.Message
    if ($msg -match 'Source Network Address:s+(S+)') {
        [PSCustomObject]@{
            Time    = $_.TimeCreated
            Source  = $matches[1]
            Account = if ($msg -match 'Account Name:s+(S+)') { $matches[1] } else { 'N/A' }
        }
    }
} | Group-Object Source |
    Sort-Object Count -Descending |
    Select-Object -First 10 Name, Count |
    Format-Table -AutoSize

10. Test de connectivité avancé (meilleur que le ping)

# Test HTTPS reachability with detailed output
Test-NetConnection -ComputerName "8.8.8.8" -Port 443 -InformationLevel Detailed

# Test multiple hosts and ports at once
$tests = @(
    @{Host="dc01.corp.local"; Port=389},
    @{Host="dc01.corp.local"; Port=636},
    @{Host="fileserver01"; Port=445},
    @{Host="mailserver01"; Port=25}
)
$tests | ForEach-Object {
    $r = Test-NetConnection -ComputerName $_.Host -Port $_.Port -WarningAction SilentlyContinue
    [PSCustomObject]@{
        Host    = $_.Host
        Port    = $_.Port
        Success = $r.TcpTestSucceeded
        RTT     = $r.PingReplyDetails.RoundtripTime
    }
} | Format-Table -AutoSize

11. Scanner de ports rapide

# Scan common ports on a target host
$target = "192.168.1.1"
$ports = @(22, 80, 443, 445, 3389, 5985, 8080, 8443)
$ports | ForEach-Object {
    $tcp = New-Object Net.Sockets.TcpClient
    try {
        $tcp.Connect($target, $_)
        [PSCustomObject]@{Port=$_; Status="OPEN"}
    } catch {
        [PSCustomObject]@{Port=$_; Status="CLOSED"}
    } finally {
        $tcp.Close()
    }
} | Format-Table -AutoSize

12. Traceroute avec latence

# Trace route to a destination with per-hop latency
Test-NetConnection -ComputerName "rootpilot.fr" -TraceRoute -Hops 20

13. Lire les valeurs du registre à distance

# Read OS build info from a remote machine
Invoke-Command -ComputerName "PC-01" -ScriptBlock {
    Get-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersion" |
    Select-Object ProductName, CurrentBuild, ReleaseId, DisplayVersion
}

# Check if auto-update is enabled on all servers
(Get-ADComputer -Filter {OperatingSystem -like "*Server*"}).Name | ForEach-Object {
    Invoke-Command -ComputerName $_ -ScriptBlock {
        $val = Get-ItemProperty "HKLM:SOFTWAREPoliciesMicrosoftWindowsWindowsUpdateAU" `
            -Name "NoAutoUpdate" -ErrorAction SilentlyContinue
        [PSCustomObject]@{
            Server     = $env:COMPUTERNAME
            AutoUpdate = if ($val.NoAutoUpdate -eq 1) {"Disabled"} else {"Enabled"}
        }
    } -ErrorAction SilentlyContinue
}

14. Déployer une clé de registre sur l'ensemble de la flotte

# Push a registry policy change to all domain machines
$computers = (Get-ADComputer -Filter *).Name
Invoke-Command -ComputerName $computers -ThrottleLimit 30 -ScriptBlock {
    $path = "HKLM:SOFTWAREPoliciesMicrosoftWindowsWindowsUpdate"
    if (-not (Test-Path $path)) { New-Item -Path $path -Force | Out-Null }
    Set-ItemProperty -Path $path -Name "DisableWindowsUpdateAccess" -Value 0 -Type DWord
    Write-Output "$env:COMPUTERNAME: registry key set"
}

15. Exportation de l'inventaire complet du matériel

Avant la période budgétaire, générez un inventaire matériel complet en une seule commande. Celle-ci extrait le système d'exploitation, la RAM, le processeur, la date du dernier démarrage et l'espace disque disponible de chaque machine du domaine.

# Generate full hardware inventory — export to CSV
$inventory = Invoke-Command -ComputerName (Get-ADComputer -Filter *).Name `
    -ThrottleLimit 20 -ErrorAction SilentlyContinue -ScriptBlock {
    [PSCustomObject]@{
        Computer    = $env:COMPUTERNAME
        OS          = (Get-CimInstance Win32_OperatingSystem).Caption
        RAM_GB      = [math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory/1GB, 0)
        CPU         = (Get-CimInstance Win32_Processor).Name
        LastBoot    = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
        DiskFree_GB = [math]::Round((Get-PSDrive C).Free/1GB, 1)
        IPAddress   = (Get-NetIPAddress -AddressFamily IPv4 |
                       Where-Object {$_.PrefixOrigin -ne "WellKnown"} |
                       Select-Object -First 1).IPAddress
    }
}
$reportPath = "C:Reportsinventory_$(Get-Date -f yyyyMMdd).csv"
$inventory | Export-Csv $reportPath -NoTypeInformation
Write-Host "Report saved to $reportPath ($($inventory.Count) machines)"

16. Vérifier à distance l'état des mises à jour Windows

# Check pending updates on a remote machine
Invoke-Command -ComputerName "SRV-01" -ScriptBlock {
    $UpdateSession  = New-Object -ComObject Microsoft.Update.Session
    $UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
    $Updates = $UpdateSearcher.Search("IsInstalled=0 and Type='Software'")
    Write-Output "Pending updates: $($Updates.Updates.Count)"
    $Updates.Updates | Select-Object Title, MsrcSeverity | Format-Table -AutoSize
}

17. Surveiller les services en cours d'exécution — Détecter les services arrêtés

# Find Automatic services that are stopped (excluding known benign ones)
Invoke-Command -ComputerName (Get-ADComputer -Filter *).Name -ScriptBlock {
    Get-Service | Where-Object {
        $_.StartType -eq "Automatic" -and $_.Status -eq "Stopped" -and
        $_.Name -notin @("MapsBroker","CDPSvc","PimIndexMaintenanceSvc")
    } | Select-Object Name, DisplayName, Status
} | Where-Object {$_.Name} | Sort-Object PSComputerName

18. Générer un rapport de tâche planifiée

# List all non-Microsoft scheduled tasks across the domain
Invoke-Command -ComputerName (Get-ADComputer -Filter *).Name -ScriptBlock {
    Get-ScheduledTask |
    Where-Object {$_.TaskPath -notlike "Microsoft*"} |
    Select-Object TaskName, TaskPath, State,
        @{N='LastRun'; E={(Get-ScheduledTaskInfo $_).LastRunTime}}
} | Sort-Object PSComputerName, TaskName

19. Exporter tous les paramètres GPO au format HTML

# Export all Group Policy Objects to individual HTML reports
Import-Module GroupPolicy
$outputDir = "C:ReportsGPO_$(Get-Date -f yyyyMMdd)"
New-Item -ItemType Directory -Path $outputDir -Force | Out-Null

Get-GPO -All | ForEach-Object {
    $name = $_.DisplayName -replace "[^a-zA-Z0-9_-]", "_"
    Get-GPOReport -Guid $_.Id -ReportType HTML -Path "$outputDir$name.html"
    Write-Output "Exported: $($_.DisplayName)"
}
Write-Output "Reports saved to $outputDir"

20. Automatiser un rapport quotidien d'administrateur système

Combinez les modèles ci-dessus dans un récapitulatif matinal. Enregistrez-le comme tâche planifiée pour qu'il s'exécute à 7 h et obtenez ainsi l'état de votre environnement avant même d'ouvrir un ticket.

# Daily health check — disk warnings + failed logins
$report = [System.Text.StringBuilder]::new()

# Disk warnings (free < 10 GB)
[void]$report.AppendLine("=== DISK WARNINGS ===")
$diskWarnings = Invoke-Command -ComputerName (Get-ADComputer -Filter *).Name -ScriptBlock {
    Get-PSDrive C | Where-Object {[math]::Round($_.Free/1GB,1) -lt 10} |
    Select-Object @{N='Computer';E={$env:COMPUTERNAME}}, @{N='FreeGB';E={[math]::Round($_.Free/1GB,1)}}
} -ErrorAction SilentlyContinue
[void]$report.AppendLine(($diskWarnings | Format-Table -AutoSize | Out-String))

# Failed logins last hour
$since = (Get-Date).AddHours(-1)
$failed = Get-WinEvent -LogName Security -MaxEvents 500 -ErrorAction SilentlyContinue |
    Where-Object {$_.Id -eq 4625 -and $_.TimeCreated -gt $since}
[void]$report.AppendLine("=== FAILED LOGINS (last 1h): $($failed.Count) ===")

# Send report
Send-MailMessage -From "sysadmin@corp.local" -To "it-team@corp.local" `
    -Subject "Daily Sysadmin Report - $(Get-Date -f 'yyyy-MM-dd')" `
    -Body $report.ToString() -SmtpServer "mail.corp.local"

Conclusion

Gestion de flotte Windows pour entreprises
Automatisation PowerShell — gestion d'un parc Windows d'entreprise à partir d'une seule console

Ces 20 modèles couvrent l'essentiel de l'administration PowerShell en entreprise : accès aux machines à grande échelle, interrogation d'Active Directory, surveillance des disques et des services, analyse des événements de sécurité et génération de rapports automatisés. Aucun ne nécessite de modules tiers autres que les outils RSAT standard que tout administrateur système Windows devrait déjà avoir installés. Leur véritable puissance réside dans leur combinaison : effectuez un inventaire pour identifier les machines disposant de peu d'espace disque, puis transmettez directement leurs noms d'hôtes à un script de nettoyage. Commencez par intégrer deux ou trois de ces modèles à votre boîte à outils quotidienne, et en une semaine, vous vous demanderez comment vous avez pu vous en passer. Enregistrez vos modèles préférés sous forme de scripts dans un dossier partagé afin que toute votre équipe puisse en profiter.