Introduction
Gérer 5 serveurs Windows en se connectant en RDP à chacun est inefficace. PowerShell Remoting (basé sur WinRM, Windows Remote Management) permet :
- Exécuter une commande sur 10 serveurs en parallèle
- Récupérer des infos depuis un script centralisé
- Installer des mises à jour sur tout un parc
- Auditer les configurations
C'est l'équivalent SSH du monde Windows : la base du sysadmin Windows moderne.
Prérequis
- 2+ Windows Server 2019/2022/2025 (ou Windows 10/11 Pro)
- Un user avec privilèges admin sur tous les serveurs
- Connectivité réseau entre les machines (TCP 5985 HTTP ou 5986 HTTPS)
Étape 1 : Activer WinRM sur les serveurs cibles
Sur chaque serveur cible (PowerShell en admin) :
Enable-PSRemoting -Force
Cette commande :
- Démarre le service WinRM
- Configure le firewall pour TCP 5985 (HTTP)
- Crée un listener WinRM
- Active la délégation pour les admins
Vérifiez :
Get-Service WinRM
Get-PSSessionConfiguration
winrm enumerate winrm/config/listener
Étape 2 : Tester la connexion depuis le serveur de management
Depuis votre poste admin (PowerShell) :
Test-WSMan -ComputerName srv-app-01
Sortie attendue :
wsmid : http://schemas.dmtf.org/wbem/wsman/identity/1/...
ProductVendor : Microsoft Corporation
ProductVersion : OS: 0.0.0 SP: 0.0 Stack: 3.0
Si erreur, voir la section dépannage.
Étape 3 : Configurer les TrustedHosts (pour hors domaine)
Si vos serveurs ne sont pas dans un domaine AD, vous devez ajouter les cibles aux TrustedHosts du client :
# Ajouter un serveur spécifique
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "srv-app-01" -Force
# Ajouter plusieurs
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "srv-app-01,srv-db-01,srv-web-01" -Force
# Tout autoriser (DEV uniquement)
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
# Vérifier
Get-Item WSMan:\localhost\Client\TrustedHosts
Étape 4 : Exécuter une commande à distance
Une commande, un serveur
Invoke-Command -ComputerName srv-app-01 -ScriptBlock {
Get-ComputerInfo | Select-Object CsName, OsName, OsVersion
} -Credential (Get-Credential)
Une fenêtre demande les credentials. Pour automatiser :
$cred = Get-Credential
Invoke-Command -ComputerName srv-app-01 -ScriptBlock { hostname } -Credential $cred
Une commande sur plusieurs serveurs en parallèle
$servers = @("srv-app-01", "srv-app-02", "srv-db-01")
Invoke-Command -ComputerName $servers -ScriptBlock {
Get-Service | Where-Object Status -eq 'Running' | Measure-Object | Select-Object Count
} -Credential $cred
Sortie : Get-Service exécuté en parallèle sur les 3 serveurs.
Étape 5 : Sessions persistantes (PSSession)
Pour lancer plusieurs commandes sans réauthentifier à chaque fois :
$session = New-PSSession -ComputerName srv-app-01 -Credential $cred
Invoke-Command -Session $session -ScriptBlock { Get-Service WinRM }
Invoke-Command -Session $session -ScriptBlock { Get-Process | Select -First 5 }
# Quand fini
Remove-PSSession $session
Session interactive (équivalent SSH)
Enter-PSSession -ComputerName srv-app-01 -Credential $cred
Le prompt change : [srv-app-01]: PS C:\Users\admin\>. Tapez Windows comme si vous étiez en local. Pour sortir :
Exit-PSSession
Étape 6 : Copier des fichiers via WinRM
$session = New-PSSession -ComputerName srv-app-01 -Credential $cred
# Push (local → remote)
Copy-Item -Path "C:\scripts\install.ps1" -Destination "C:\temp\install.ps1" -ToSession $session
# Pull (remote → local)
Copy-Item -Path "C:\logs\app.log" -Destination "C:\local-logs\srv-app-01_app.log" -FromSession $session
Remove-PSSession $session
Étape 7 : Scripts d'administration courants
Inventaire complet du parc
$servers = @("srv-app-01", "srv-app-02", "srv-db-01")
$cred = Get-Credential
$inventory = Invoke-Command -ComputerName $servers -Credential $cred -ScriptBlock {
[PSCustomObject]@{
Hostname = $env:COMPUTERNAME
OS = (Get-CimInstance Win32_OperatingSystem).Caption
Version = (Get-CimInstance Win32_OperatingSystem).Version
CPU = (Get-CimInstance Win32_Processor).Name
Cores = (Get-CimInstance Win32_Processor).NumberOfCores
RAM_GB = [math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory / 1GB, 2)
Disk_C_Free = [math]::Round((Get-PSDrive C).Free / 1GB, 2)
Uptime = (Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
LastUpdate = (Get-HotFix | Sort-Object InstalledOn -Descending | Select -First 1).InstalledOn
}
}
$inventory | Format-Table -AutoSize
$inventory | Export-Csv "C:\inventaire-parc.csv" -NoTypeInformation
Installer une mise à jour Windows partout
Invoke-Command -ComputerName $servers -Credential $cred -ScriptBlock {
Install-PackageProvider -Name NuGet -Force | Out-Null
Install-Module PSWindowsUpdate -Force | Out-Null
Import-Module PSWindowsUpdate
Get-WindowsUpdate -AcceptAll -Install -AutoReboot
}
Service status sur tout le parc
Invoke-Command -ComputerName $servers -Credential $cred -ScriptBlock {
Get-Service -Name "Spooler","WinRM","DNS" |
Select-Object @{N='Server';E={$env:COMPUTERNAME}}, Name, Status
} | Format-Table -AutoSize
Lister les utilisateurs actifs
Invoke-Command -ComputerName $servers -Credential $cred -ScriptBlock {
query user
}
Redémarrer plusieurs serveurs
Restart-Computer -ComputerName $servers -Credential $cred -Force -Wait -For PowerShell -Timeout 600
Étape 8 : Sécuriser avec HTTPS (WinRM sur SSL)
Par défaut WinRM utilise HTTP non chiffré (port 5985). En production, chiffrez avec HTTPS (port 5986).
Générer un certificat self-signed (test) ou utiliser une CA
$cert = New-SelfSignedCertificate -DnsName "srv-app-01" -CertStoreLocation "Cert:\LocalMachine\My"
Créer le listener HTTPS
$thumbprint = $cert.Thumbprint
New-Item -Path WSMan:\localhost\Listener -Transport HTTPS -Address * -CertificateThumbprint $thumbprint -Force
Ouvrir le firewall
New-NetFirewallRule -DisplayName "WinRM HTTPS" -Protocol TCP -LocalPort 5986 -Action Allow
Désactiver HTTP
Get-ChildItem WSMan:\localhost\Listener | Where-Object { $_.Keys -match "HTTP$" } | Remove-Item -Recurse
Disable-NetFirewallRule -DisplayName "Windows Remote Management (HTTP-In)"
Se connecter en HTTPS
Enter-PSSession -ComputerName srv-app-01 -UseSSL -Credential $cred
Pour un cert self-signed, ajoutez -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck).
Étape 9 : JEA (Just Enough Administration)
Pour donner à un user le droit d'exécuter certaines commandes sans le rendre admin :
# Créer une config session
New-PSSessionConfigurationFile -Path C:\Config\WebAdmin.pssc -SessionType RestrictedRemoteServer -RoleDefinitions @{'DOMAIN\WebOps' = @{ RoleCapabilities = 'WebOpsRole' }}
# Créer la role capability
New-PSRoleCapabilityFile -Path C:\Config\WebOpsRole.psrc -VisibleCmdlets @('Restart-Service', 'Get-Service', 'Get-IISSite')
# Enregistrer
Register-PSSessionConfiguration -Path C:\Config\WebAdmin.pssc -Name WebAdmin
Le user DOMAIN\WebOps peut maintenant se connecter à cette session restreinte et utiliser uniquement les cmdlets autorisés.
Étape 10 : Group Policy pour activer WinRM en masse
Pour activer WinRM sur tous les serveurs d'un domaine AD :
- GPMC.msc → créer/éditer une GPO
- Configuration ordinateur → Stratégies → Modèles d'administration → Composants Windows → Gestion de la communication à distance Windows (WinRM)
- Activer :
- WinRM Service : Allow remote server management through WinRM = Enabled
- Windows Firewall : ouvrir les ports 5985/5986
- Lier la GPO à l'OU des serveurs
gpupdate /force sur les serveurs pour appliquer immédiatement.
Dépannage
"WinRM cannot complete the operation"
Le service WinRM n'est pas démarré sur la cible :
Get-Service WinRM
Start-Service WinRM
Set-Service WinRM -StartupType Automatic
"Access is denied"
User pas dans le groupe Remote Management Users ou pas admin. Ajoutez :
Add-LocalGroupMember -Group "Remote Management Users" -Member "DOMAIN\username"
"The WinRM client cannot process the request"
Ajoutez la cible aux TrustedHosts (voir étape 3) ou utilisez HTTPS.
Firewall bloque
Get-NetFirewallRule | Where-Object DisplayName -like "*Windows Remote Management*" | Enable-NetFirewallRule
Timeout sur des commandes longues
$opt = New-PSSessionOption -OperationTimeout 600000 # 10 min
Invoke-Command -ComputerName srv -ScriptBlock {...} -SessionOption $opt
Commandes utiles
# Lister les sessions actives
Get-PSSession
# Killer toutes les sessions
Get-PSSession | Remove-PSSession
# Voir la config WinRM
winrm get winrm/config
winrm get winrm/config/listener
# Tester depuis CLI
winrm identify -r:http://srv-app-01:5985
# Reset complet WinRM
winrm quickconfig -force
winrm invoke restore winrm/config
# Lister les listeners
winrm enumerate winrm/config/listener
# Récupérer le journal WinRM
Get-WinEvent -LogName "Microsoft-Windows-WinRM/Operational" -MaxEvents 50
Conclusion
Avec PowerShell Remoting maîtrisé :
- Vous administrez 1 ou 100 serveurs avec le même effort
- Les scripts s'exécutent en parallèle automatiquement
- Vous évitez les sessions RDP (plus rapide, audit-friendly)
Pour aller plus loin :
- Combinez avec DSC (Desired State Configuration) pour de l'infra as code
- Utilisez Azure Arc pour gérer des serveurs Windows on-prem depuis le cloud
- Migrez vers Ansible ou Puppet pour de l'orchestration multi-OS
Ressources
- Documentation officielle : https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/running-remote-commands
- Microsoft PowerShell Gallery : https://www.powershellgallery.com
- Tuto VeryCloud — Active Directory :
/docs/article/active-directory - Tuto VeryCloud — Tâches planifiées :
/docs/article/task-scheduler


















