Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

Chapitre 1114 minDébutant

Exécution à distance : PowerShell Remoting, WinRM et SSH

Par Josselyn C., prof de BTS SIO. Mis à jour le .

À la fin de ce chapitre, tu sauras

  • lancer des commandes sur plusieurs serveurs Windows avec Invoke-Command ;
  • transmettre des valeurs et des scripts à une machine distante ;
  • utiliser PowerShell sur SSH vers Linux et Windows Server 2025 ;
  • automatiser SSH en Bash avec une clé, sans affaiblir la sécurité.

3 exercices corrigés1 schéma

Exécuter à distance, c'est lancer des commandes ou un script sur un autre ordinateur sans ouvrir de session graphique dessus. Sous Windows, PowerShell utilise pour cela WinRM (le PowerShell Remoting, sur les ports 5985 et 5986) ; sous Linux, et désormais aussi sous Windows, on utilise SSH (port 22). Ce chapitre montre comment administrer d'un coup plusieurs serveurs depuis le poste d'administration, comment passer des valeurs et des scripts à une machine distante, et comment le faire sans affaiblir la sécurité.

Le principe

Chez Sorbier, les techniciens n'ouvrent pas de bureau à distance sur les serveurs pour chaque vérification : depuis le poste d'administration, dans le VLAN 99, ils envoient des commandes aux serveurs Windows par WinRM et aux serveurs Linux par SSH. Le pare-feu n'autorise ces ports que depuis le VLAN d'administration.

poste d'administration192.168.10.209VLAN 99 ADMINpare-feu : seulement depuis le VLAN 99VLAN 20 SERVEURS : Windows Serversrv-ad.177srv-ad2.181srv-fichiers.178Invoke-Command -ComputerName …en parallèle, résultats marqués PSComputerNameServeurs Linux Debian 13srv-journaux.180, VLAN 20srv-web.225, VLAN 60 DMZssh -o BatchMode=yes, clé ed25519WinRM, TCP 5985KerberosSSH, TCP 22clé ed25519
Depuis le poste d'administration : WinRM vers les serveurs Windows, SSH vers les serveurs Linux, autorisés depuis le seul VLAN 99

PowerShell Remoting avec WinRM

Le service WinRM (Windows Remote Management) écoute sur le port TCP 5985 (HTTP) ou 5986 (HTTPS). Dans un domaine, même sur 5985, l'échange est authentifié et chiffré par Kerberos : le contenu ne circule pas en clair. Le remoting est activé par défaut sur Windows Server ; sur un poste Windows 11, Enable-PSRemoting l'active, et une GPO peut le faire sur tout un parc.

Vérifier qu'un serveur accepte le remoting :

powershell
Test-WSMan -ComputerName srv-ad
Test-NetConnection -ComputerName srv-ad -Port 5985

Une session interactive, comme une connexion SSH :

powershell
Enter-PSSession -ComputerName srv-fichiers
[srv-fichiers]: PS C:\Users\adm1-clambert\Documents> Get-Service LanmanServer
[srv-fichiers]: PS C:\Users\adm1-clambert\Documents> Exit-PSSession

L'invite affiche le nom de la machine distante entre crochets. Tout ce que tu tapes s'exécute là-bas.

Une commande sur plusieurs serveurs, avec Invoke-Command : c'est l'outil des scripts. Les serveurs sont contactés en parallèle (32 à la fois par défaut, réglable avec -ThrottleLimit) et chaque résultat porte une propriété PSComputerName qui dit d'où il vient.

powershell
Invoke-Command -ComputerName srv-ad, srv-ad2, srv-fichiers -ScriptBlock {
    $c = Get-PSDrive -Name C
    [pscustomobject]@{
        LibreGo   = [math]::Round($c.Free / 1GB, 1)
        Demarrage = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
    }
} | Select-Object PSComputerName, LibreGo, Demarrage

Cet exemple réunit les trois serveurs Windows pour montrer le parallélisme. Dans un domaine qui applique le modèle en tiers, les contrôleurs de domaine (srv-ad, srv-ad2) ne s'administrent qu'avec un compte de niveau 0 (adm0-…), depuis un poste réservé à ce niveau : on ne mélange pas, dans une même commande, des machines de niveaux différents. On lance donc une commande vers srv-ad et srv-ad2 avec le compte de niveau 0, une autre vers srv-fichiers avec le compte de niveau 1 (cours Windows Server).

Les objets reviennent sérialisés : PowerShell les transporte en XML, et ce qui arrive est une copie de leurs propriétés, sans leurs méthodes (leur type est préfixé par Deserialized.). Pour agir sur un objet, il faut donc le faire dans le bloc de script, sur la machine distante : Invoke-Command -ComputerName srv-ad -ScriptBlock { Restart-Service DNS }, et non récupérer le service pour appeler sa méthode ensuite.

Passer des valeurs et des scripts

Le bloc de script s'exécute sur la machine distante, où les variables de ton script n'existent pas. Deux façons de lui transmettre une valeur :

powershell
$service = 'Spooler'

# $using: lit la variable locale au moment de l'envoi
Invoke-Command -ComputerName srv-fichiers -ScriptBlock { Get-Service -Name $using:service }

# -ArgumentList passe des valeurs au param() du bloc
Invoke-Command -ComputerName srv-fichiers -ScriptBlock {
    param($nom)
    Get-Service -Name $nom
} -ArgumentList $service

-FilePath envoie un script local pour qu'il s'exécute à distance, sans le copier au préalable : Invoke-Command -ComputerName srv-ad, srv-ad2 -FilePath .\Get-EtatServicesAD.ps1.

Pour enchaîner plusieurs commandes sur les mêmes machines, ouvre des sessions persistantes : la connexion n'est établie qu'une fois, et les variables restent d'une commande à l'autre.

powershell
$sessions = New-PSSession -ComputerName srv-ad, srv-ad2
Invoke-Command -Session $sessions -ScriptBlock { $journal = Get-WinEvent -LogName 'Directory Service' -MaxEvents 50 }
Invoke-Command -Session $sessions -ScriptBlock { $journal | Where-Object Level -eq 2 }
Copy-Item -Path .\outils\ -Destination C:\Scripts\ -ToSession $sessions[0] -Recurse
Remove-PSSession $sessions

Copy-Item -ToSession et -FromSession copient des fichiers par la session WinRM, sans partage réseau.

Hors du domaine, et le « double saut »

Vers une machine hors du domaine, Kerberos n'est pas disponible. Il faut alors soit configurer WinRM en HTTPS (port 5986) avec un certificat, soit ajouter la machine à la liste TrustedHosts du client, ce qui revient à faire confiance à son nom sans vérifier son identité. La première solution est la bonne ; la seconde n'est acceptable que dans une maquette.

Le double saut (second hop) surprend tous les débutants : dans une session ouverte sur srv-gestion, une commande qui accède à un troisième serveur (Get-ChildItem \\srv-fichiers\Compta) échoue avec un accès refusé. Par sécurité, Kerberos ne délègue pas ton identité au-delà de la première machine (Kerberos et la délégation). La solution la plus simple est de ne pas faire de double saut : lance la commande directement vers srv-fichiers, ou copie le fichier par la session. Évite CredSSP, qui contourne le problème en envoyant ton mot de passe à la machine distante, où un attaquant pourrait le récupérer.

PowerShell sur SSH

PowerShell 7 sait utiliser SSH au lieu de WinRM. C'est la méthode pour administrer de la même façon des serveurs Linux et Windows, ou une machine hors domaine sans configurer WinRM en HTTPS. Les paramètres changent : -HostName et -UserName au lieu de -ComputerName.

powershell
Enter-PSSession -HostName srv-web -UserName mdiallo
Invoke-Command -HostName srv-web, srv-journaux -UserName mdiallo -ScriptBlock { Get-Content /etc/os-release -TotalCount 1 }

La machine distante doit avoir PowerShell 7 et un serveur SSH qui déclare PowerShell comme sous-système. Sur Debian, une ligne dans /etc/ssh/sshd_config (avant tout bloc Match), puis sudo systemctl restart ssh :

text
Subsystem powershell /usr/bin/pwsh -sshs -NoLogo

Windows Server 2025 installe le serveur OpenSSH par défaut, désactivé. On l'active dans le Gestionnaire de serveur (Serveur local > Accès SSH à distance), ou en PowerShell, puis on déclare le sous-système dans C:\ProgramData\ssh\sshd_config :

powershell
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
Get-NetFirewallRule -Name OpenSSH-Server-In-TCP | Select-Object Name, Enabled
text
Subsystem powershell c:/progra~1/powershell/7/pwsh.exe -sshs -NoLogo

Le chemin court progra~1 évite l'espace de Program Files, que le fichier de configuration d'OpenSSH ne sait pas protéger.

SSH depuis Bash

ssh lance une commande sur une machine distante et renvoie sa sortie et son code de retour, comme si la commande était locale :

bash
ssh mdiallo@srv-web 'df -h / && systemctl is-active nginx'

Pour un script qui tourne seul, l'authentification se fait par clé, jamais par mot de passe saisi :

bash
ssh-keygen -t ed25519 -C "mdiallo@poste-admin"      # crée ~/.ssh/id_ed25519 et id_ed25519.pub
ssh-copy-id mdiallo@srv-web                          # dépose la clé publique sur le serveur
ssh mdiallo@srv-web                                  # plus de mot de passe à taper

Protège la clé privée par une phrase de passe et charge-la dans l'agent (ssh-add) pour ne la taper qu'une fois par session. Une clé sans phrase de passe, pour un script planifié, se dédie à ce seul usage, sur un compte de service aux droits limités, et le serveur peut restreindre ce qu'elle a le droit de lancer (option command= devant la clé dans authorized_keys).

Le fichier ~/.ssh/config évite de répéter les options :

text
Host srv-web
    HostName 192.168.10.225
    User mdiallo
    IdentityFile ~/.ssh/id_ed25519

Host srv-journaux
    HostName 192.168.10.180
    User mdiallo

Avec ce fichier, ssh srv-web suffit. Si l'architecture impose un bastion, une ligne ProxyJump bastion dans un bloc Host fait passer la connexion par lui automatiquement.

Dans un script, ajoute deux options à chaque ssh : BatchMode=yes, qui fait échouer immédiatement la connexion au lieu de demander un mot de passe que personne ne tapera, et ConnectTimeout, qui évite d'attendre deux minutes un serveur éteint.

bash
#!/usr/bin/env bash
set -uo pipefail          # pas de -e : un serveur injoignable ne doit pas arrêter le tour
serveurs=(srv-web srv-journaux)
echec=0
for s in "${serveurs[@]}"; do
    if utilisation=$(ssh -o BatchMode=yes -o ConnectTimeout=5 "$s" "df --output=pcent / | tail -n 1"); then
        echo "$s : ${utilisation// /} utilisé"
    else
        echo "$s : injoignable" >&2
        echec=1
    fi
done
exit "$echec"

${utilisation// /} retire tous les espaces de la valeur ( 42% devient 42%). Le script continue au serveur suivant quand l'un ne répond pas, mais se termine avec le code 1 : la supervision saura qu'il y a eu un problème.

Pour exécuter tout un script local sur une machine distante, sans le copier, envoie-le sur l'entrée standard de bash : ssh srv-web 'bash -s' < verif.sh. Pour copier des fichiers, scp convient aux copies simples, rsync -a -e ssh aux synchronisations (chapitre 13).

Exercices

Exercice 1 sur 3 Le tour des contrôleurs Réussi À revoir

Écris la commande qui affiche, pour srv-ad et srv-ad2, l'état des services NTDS, DNS, Netlogon et DHCPServer, avec le nom du serveur, en une seule exécution depuis le poste d'administration. Que faut-il vérifier si srv-ad2 répond « WinRM cannot complete the operation » ?

Voir la réponseMasquer la réponse de l'exercice 1
powershell
Invoke-Command -ComputerName srv-ad, srv-ad2 -ScriptBlock {
    Get-Service -Name NTDS, DNS, Netlogon, DHCPServer
} | Select-Object PSComputerName, Name, Status

Ce message signifie que WinRM n'a pas pu joindre le serveur. Dans l'ordre : le serveur est-il allumé et le nom se résout-il (Resolve-DnsName srv-ad2) ? Le port répond-il (Test-NetConnection srv-ad2 -Port 5985) ? Le pare-feu de srv-ad2, ou celui entre les VLAN, autorise-t-il le port 5985 depuis le VLAN 99 ? Le service WinRM tourne-t-il (Get-Service WinRM, à vérifier sur la console du serveur) ? Enfin, Test-WSMan srv-ad2 confirme que le service répond.

Tu avais trouvé ?

Exercice 2 sur 3 La variable qui n'arrive pas Réussi À revoir

Ce script doit afficher les 20 derniers événements du journal System de chaque serveur, mais il échoue avec une erreur sur le paramètre -MaxEvents. Explique et donne deux corrections.

powershell
$nombre = 20
Invoke-Command -ComputerName srv-fichiers, srv-gestion -ScriptBlock {
    Get-WinEvent -LogName System -MaxEvents $nombre
}
Voir la réponseMasquer la réponse de l'exercice 2

Le bloc s'exécute sur les serveurs distants, où $nombre n'existe pas : il vaut $null, que -MaxEvents refuse. Correction avec $using: :

powershell
Invoke-Command -ComputerName srv-fichiers, srv-gestion -ScriptBlock {
    Get-WinEvent -LogName System -MaxEvents $using:nombre
}

Ou avec -ArgumentList :

powershell
Invoke-Command -ComputerName srv-fichiers, srv-gestion -ScriptBlock {
    param($n)
    Get-WinEvent -LogName System -MaxEvents $n
} -ArgumentList $nombre

Tu avais trouvé ?

Exercice 3 sur 3 Préparer un accès SSH pour un script Réussi À revoir

Un script de srv-journaux doit récupérer chaque nuit la configuration nginx de srv-web, avec le compte sauvegarde. Donne les étapes et les commandes pour que la connexion se fasse par clé, sans mot de passe, et sans que le script reste bloqué si srv-web est éteint ou si son empreinte change.

Voir la réponseMasquer la réponse de l'exercice 3
  1. Sur srv-journaux, sous le compte sauvegarde, créer une clé dédiée : ssh-keygen -t ed25519 -f ~/.ssh/id_sauvegarde -C "sauvegarde@srv-journaux". Sans phrase de passe, puisque le script tourne seul : elle ne servira qu'à cet usage.
  2. Déposer la clé publique sur srv-web, dans le compte sauvegarde qui n'a que le droit de lire les fichiers à récupérer : ssh-copy-id -i ~/.ssh/id_sauvegarde.pub sauvegarde@srv-web.
  3. Se connecter une fois à la main (ssh -i ~/.ssh/id_sauvegarde sauvegarde@srv-web) et vérifier que l'empreinte affichée est celle du serveur (ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub sur srv-web) : elle est alors enregistrée dans known_hosts.
  4. Dans le script, appeler ssh avec -i ~/.ssh/id_sauvegarde -o BatchMode=yes -o ConnectTimeout=10 : pas de question bloquante, abandon rapide si le serveur ne répond pas, et refus de se connecter si l'empreinte change, puisque StrictHostKeyChecking garde sa valeur par défaut.

Pour aller plus loin, on limite la clé à la seule commande utile en la préfixant, dans ~sauvegarde/.ssh/authorized_keys sur srv-web, par command="tar -czf - -C /etc nginx",restrict : même volée, la clé ne permet rien d'autre.

Tu avais trouvé ?

Chapitre terminé !

Fais les 3 exercices avant de passer à la suite : c'est en t'entraînant que tout se fixe.

chapitres
–
de série
–
du cours
–
Chapitre suivant : Scripts Active Directory : créer des comptes en masse depuis un CSVRevoir le sommaire du cours