Skip to content

PowerShell Remoting

Configuration et utilisation de PowerShell Remoting (WinRM) pour l'administration à distance.

Architecture

POWERSHELL REMOTING ARCHITECTURE
══════════════════════════════════════════════════════════

Client                          Serveur
  │                               │
  │    WS-Management (WinRM)      │
  │  ──────────────────────────►  │
  │      HTTP(S) / 5985-5986      │
  │                               │
  │   ┌─────────────────────┐     │
  │   │  Session PowerShell │     │
  │   │  - Invoke-Command   │     │
  │   │  - Enter-PSSession  │     │
  │   │  - New-PSSession    │     │
  │   └─────────────────────┘     │

Configuration WinRM

Activer le Remoting

# Activer WinRM (run as admin)
Enable-PSRemoting -Force

# Ou via winrm
winrm quickconfig

# Ce que fait Enable-PSRemoting :
# 1. Démarre le service WinRM
# 2. Configure le service en démarrage auto
# 3. Crée un listener HTTP sur 5985
# 4. Configure le firewall
# 5. Enregistre les configurations de session

# Vérifier la configuration
Get-PSSessionConfiguration
winrm enumerate winrm/config/listener

Configuration du Listener

# Voir les listeners
Get-WSManInstance -ResourceURI winrm/config/listener -Enumerate

# Créer un listener HTTPS
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object Subject -like "*$(hostname)*"
New-WSManInstance -ResourceURI winrm/config/listener -SelectorSet @{Transport="HTTPS"; Address="*"} `
    -ValueSet @{CertificateThumbprint=$cert.Thumbprint}

# Supprimer un listener
Remove-WSManInstance -ResourceURI winrm/config/listener -SelectorSet @{Transport="HTTP"; Address="*"}

Configuration Avancée

# Voir toute la configuration
winrm get winrm/config

# Augmenter les limites
Set-WSManQuickConfig
Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB 1024
Set-Item WSMan:\localhost\Shell\MaxConcurrentUsers 10
Set-Item WSMan:\localhost\MaxTimeoutms 1800000

# Configurer le nombre max de connexions
Set-Item WSMan:\localhost\Service\MaxConnections 100

# TrustedHosts (hors domaine)
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "server01,server02,10.10.1.*"
# Ou tout autoriser (non recommandé)
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*"

Utilisation de Base

Sessions Interactives

# Session interactive
Enter-PSSession -ComputerName server01

# Avec credentials
$cred = Get-Credential
Enter-PSSession -ComputerName server01 -Credential $cred

# Session HTTPS
Enter-PSSession -ComputerName server01 -UseSSL

# Quitter la session
Exit-PSSession

Invoke-Command

# Exécuter une commande à distance
Invoke-Command -ComputerName server01 -ScriptBlock { Get-Process }

# Plusieurs serveurs
Invoke-Command -ComputerName server01,server02,server03 -ScriptBlock { Get-Service }

# Avec credentials
Invoke-Command -ComputerName server01 -Credential $cred -ScriptBlock { whoami }

# Passer des paramètres
$serviceName = "WinRM"
Invoke-Command -ComputerName server01 -ScriptBlock {
    param($name)
    Get-Service -Name $name
} -ArgumentList $serviceName

# Utiliser $using: (plus simple)
$serviceName = "WinRM"
Invoke-Command -ComputerName server01 -ScriptBlock {
    Get-Service -Name $using:serviceName
}

# Exécuter un script local sur une machine distante
Invoke-Command -ComputerName server01 -FilePath "C:\Scripts\Audit.ps1"

Sessions Persistantes

# Créer une session
$session = New-PSSession -ComputerName server01

# Utiliser la session
Invoke-Command -Session $session -ScriptBlock { $var = "test" }
Invoke-Command -Session $session -ScriptBlock { $var }  # Variable persistante

# Sessions multiples
$sessions = New-PSSession -ComputerName server01,server02,server03
Invoke-Command -Session $sessions -ScriptBlock { hostname }

# Copier des fichiers via session
Copy-Item -Path "C:\local\file.txt" -Destination "C:\remote\" -ToSession $session
Copy-Item -Path "C:\remote\file.txt" -Destination "C:\local\" -FromSession $session

# Fermer les sessions
Remove-PSSession -Session $session
Get-PSSession | Remove-PSSession

Sessions Disconnected

# Créer une session déconnectable
$session = New-PSSession -ComputerName server01 -Name "LongTask"

# Lancer une tâche longue
Invoke-Command -Session $session -ScriptBlock {
    Start-Sleep -Seconds 3600
    Get-Process
} -AsJob

# Déconnecter
Disconnect-PSSession -Session $session

# Reconnecter (depuis n'importe quel poste)
$session = Get-PSSession -ComputerName server01 -Name "LongTask" -State Disconnected
Connect-PSSession -Session $session

# Récupérer les résultats
Receive-PSSession -Session $session

Authentification

Kerberos (Défaut en Domaine)

# Authentification Kerberos automatique
Invoke-Command -ComputerName server01.corp.local -ScriptBlock { whoami }

# Vérifier le type d'auth
$session = New-PSSession -ComputerName server01
$session.Runspace.ConnectionInfo.AuthenticationMechanism

CredSSP (Délégation)

# Activer CredSSP sur le client
Enable-WSManCredSSP -Role Client -DelegateComputer "server01.corp.local"

# Activer CredSSP sur le serveur
Enable-WSManCredSSP -Role Server

# Utiliser CredSSP (permet double-hop)
$cred = Get-Credential
Invoke-Command -ComputerName server01 -Credential $cred -Authentication CredSSP -ScriptBlock {
    # Peut accéder à d'autres ressources réseau
    Get-ChildItem \\fileserver\share
}

# ⚠️ CredSSP stocke les credentials en mémoire - risque de vol
# Préférer Kerberos constrained delegation ou Resource-Based Constrained Delegation

Certificats

# Authentification par certificat
$cert = Get-ChildItem Cert:\CurrentUser\My | Where-Object Subject -like "*admin*"

Invoke-Command -ComputerName server01 -CertificateThumbprint $cert.Thumbprint -ScriptBlock {
    whoami
}

JEA (Just Enough Administration)

Créer une Configuration JEA

# Créer le dossier de module
$modulePath = "C:\Program Files\WindowsPowerShell\Modules\JEA-DNSAdmin"
New-Item -Path $modulePath -ItemType Directory
New-Item -Path "$modulePath\RoleCapabilities" -ItemType Directory

# Fichier de capacités de rôle
New-PSRoleCapabilityFile -Path "$modulePath\RoleCapabilities\DNSAdmin.psrc" `
    -VisibleCmdlets @(
        "Get-DnsServer*",
        "Add-DnsServerResourceRecord*",
        "Remove-DnsServerResourceRecord*"
    ) `
    -VisibleFunctions @("Get-Date", "Write-Output") `
    -VisibleExternalCommands @("C:\Windows\System32\nslookup.exe")

# Configuration de session
New-PSSessionConfigurationFile -Path "$modulePath\DNSAdmin.pssc" `
    -SessionType RestrictedRemoteServer `
    -RunAsVirtualAccount `
    -RoleDefinitions @{
        "CORP\DNS-Admins" = @{ RoleCapabilities = "DNSAdmin" }
    } `
    -TranscriptDirectory "C:\Transcripts" `
    -LanguageMode RestrictedLanguage

# Enregistrer la configuration
Register-PSSessionConfiguration -Name "DNSAdmin" -Path "$modulePath\DNSAdmin.pssc" -Force

# Utiliser JEA
Enter-PSSession -ComputerName server01 -ConfigurationName DNSAdmin

Audit JEA

# Les transcriptions sont dans C:\Transcripts
Get-ChildItem C:\Transcripts

# Voir les sessions JEA
Get-PSSessionConfiguration | Where-Object { $_.RunAsVirtualAccount }

Configuration GPO

Déploiement WinRM

Computer Configuration > Policies > Administrative Templates >
Windows Components > Windows Remote Management (WinRM)

WinRM Client:
  - Trusted Hosts (si nécessaire)

WinRM Service:
  - Allow remote server management through WinRM
  - Specify channel binding token hardening level

Windows Remote Shell:
  - Allow Remote Shell Access

Firewall

# Règles firewall requises
New-NetFirewallRule -DisplayName "WinRM HTTP" -Direction Inbound -Protocol TCP -LocalPort 5985 -Action Allow
New-NetFirewallRule -DisplayName "WinRM HTTPS" -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow

# Ou activer le groupe prédéfini
Enable-NetFirewallRule -DisplayGroup "Windows Remote Management"

Troubleshooting

Diagnostics

# Tester la connectivité WinRM
Test-WSMan -ComputerName server01

# Test avec authentification
Test-WSMan -ComputerName server01 -Authentication Negotiate -Credential $cred

# Voir les erreurs détaillées
$DebugPreference = "Continue"
Enter-PSSession -ComputerName server01

# Logs WinRM
Get-WinEvent -LogName "Microsoft-Windows-WinRM/Operational" -MaxEvents 50

# Vérifier le service
Get-Service WinRM
Get-Service WinRM -ComputerName server01

Erreurs Courantes

# "Access Denied"
# → Vérifier les permissions et le groupe Remote Management Users
Get-LocalGroupMember -Group "Remote Management Users"

# "WinRM cannot complete the operation"
# → Vérifier TrustedHosts (hors domaine)
Get-Item WSMan:\localhost\Client\TrustedHosts

# "The WinRM client cannot process the request"
# → Vérifier le firewall
Test-NetConnection -ComputerName server01 -Port 5985

# Kerberos double-hop
# → Utiliser CredSSP ou configurer delegation

Bonnes Pratiques

Checklist Remoting:
  Sécurité:
    - [ ] HTTPS en production si possible
    - [ ] Éviter TrustedHosts = "*"
    - [ ] Préférer Kerberos à CredSSP
    - [ ] Utiliser JEA pour limiter les droits
    - [ ] Activer la transcription

  Performance:
    - [ ] Sessions persistantes pour tâches répétées
    - [ ] Parallélisation avec -ThrottleLimit
    - [ ] Fan-out raisonnable (pas 1000 serveurs en parallèle)

  Opérations:
    - [ ] Tester sur un serveur avant déploiement
    - [ ] Capturer les erreurs avec -ErrorAction
    - [ ] Logging des actions administratives

Voir aussi :