
I. Présentation
L’administration à distance est une pratique courante et à encourager pour améliorer l’efficacité des administrateurs système et réseau. PowerShell offre plusieurs options pour permettre à l’administrateur d’exécuter des commandes ou des scripts à distance sur un ensemble de machines. Il peut s’agir de postes de travail ou de serveurs, selon les besoins.
Parmi les options envisageables, il y a le cmdlet PowerShell nommé Invoke-Command. Il permet d’exécuter une commande ou un script sur un ou plusieurs ordinateurs distants, via les protocoles WinRM ou SSH, en fonction du contexte.
Il est également possible d’utiliser les deux méthodes suivantes :
Utiliser une session à distance PowerShell, via les cmdlets New-PSSession et Enter-PSSession
Utiliser le paramètre -ComputerName de certains cmdlets pour cibler directement une machine distante
Dans ce tutoriel, nous allons uniquement explorer l’utilisation du cmdlet Invoke-Command pour exécuter des commandes à distance sur plusieurs machines. En complément, je vous oriente vers ce précédent article :
II. Prérequis pour l’exécution à distance
Avant d’utiliser Invoke-Command, il est essentiel de s’assurer que la configuration de l’environnement est correcte. Ici, nous utiliserons la configuration la plus simple pour éviter d’alourdir l’article avec la configuration de WinRM, à savoir : exécuter des commandes entre plusieurs machines intégrées à un domaine Active Directory, ce qui facilite l’authentification et l’approbation mutuelle des hôtes.
WinRM est associé à la fonctionnalité de Gestion à distance de Windows. L’état par défaut est le suivant :
Sur Windows Server, la Gestion à distance est activée par défaut, ce qui signifie que WinRM est en écoute
Sur Windows 10 et Windows 11, la Gestion à distance est désactivée par défaut, il n’est donc pas possible de se connecter à un poste de travail à distance sans effectuer de configuration
Pour activer WinRM (Windows Remote Management) sur une machine, il suffit d’exécuter cette commande :
Enable-PSRemoting
Cette commande active WinRM, ce qui va démarrer le service associer, mettre en écoute la machine sur le port 5985/TCP (HTTP) et configurer le pare-feu pour permettre les connexions distantes. Pour configurer WinRM sur un ensemble de machines, suivez ce tutoriel :
Vous pouvez déterminer si le service WinRM est en cours d’exécution ou non sur une machine distante, via cette commande (en adaptant le nom de l’hôte ciblé) :
Test-WSMan -ComputerName W11-01.it-connect.local
III. Utilisation de Invoke-Command
Une fois l’environnement configuré, Invoke-Command peut être utilisé pour exécuter des commandes à distance. Dans la suite de cet article, nous étudierons différents exemples d’utilisation. Avant de commencer, sachez que cette commande peut :
Exécuter un bloc de code contenant une ou plusieurs commandes via le paramètre -ScriptBlock
Exécuter un script PowerShell (.ps1) via le paramètre -FilePath
A. Exécuter une commande seule
L’exécution d’une commande sur un ordinateur distant nommé W11-01.it-connect.local se fait comme suit :
Invoke-Command -ComputerName W11-01.it-connect.local -ScriptBlock { Get-Process }
Cette commande récupère la liste des processus en cours d’exécution sur la machine distante, grâce à l’exécution de Get-Process.
B. Exécuter un script PowerShell
Il est aussi possible d’exécuter un script complet en spécifiant un fichier PowerShell au format PS1. Si la machine distante n’a pas accès au script via le réseau, ce n’est pas gênant. Le plus important, c’est que ce script soit accessible par la machine depuis laquelle Invoke-Command est exécuté :
Invoke-Command -ComputerName W11-01.it-connect.local -FilePath “C:\Scripts\MonScript.ps1”
Cela permet d’automatiser des tâches sur plusieurs machines, que ce soit des postes de travail ou des serveurs.
Note : pour exécuter la commande ou le script en arrière-plan en tant que job, ajoutez le paramètre -AsJob.
Dans le cas où le script à exécuter se situe déjà sur la machine distante et qu’il n’est pas accessible depuis l’ordinateur source, utilisez cette syntaxe :
Invoke-Command -ComputerName W11-01.it-connect.local -ScriptBlock { C:\Scripts\MonScript.ps1 }
C. Exécuter une commande sur plusieurs machines
Pour exécuter une commande sur plusieurs machines, vous n’avez qu’à spécifier plusieurs noms d’hôtes séparés par une virgule. Voici un exemple pour redémarrer le service Spouleur d’impression sur 2 machines différentes :
Invoke-Command -ComputerName W11-01.it-connect.local,W11-02.it-connect.local -ScriptBlock { Restart-Service -Name Spooler }
Personnellement, je préfère stocker la liste des machines dans un tableau et appeler la variable via Invoke-Command. C’est aussi plus pratique si vous avez plusieurs commandes à exécuter via des appels différents d’Invoke-Command.
$ComputersList = @(“W11-01.it-connect.local”,”W11-02.it-connect.local”)
Invoke-Command -ComputerName $ComputersList -ScriptBlock { Restart-Service -Name Spooler }
Cela simplifie la gestion de plusieurs machines. Voici un autre exemple pour redémarrer un ensemble de machines à distance :
Invoke-Command -ComputerName $ComputersList -ScriptBlock { Restart-Computer -Force }
Nous pourrions aussi récupérer une liste d’ordinateurs de façon dynamique depuis l’Active Directory, puis exécuter une action sur chaque machine de cette liste.
# Obtenir la liste des computers à partir de l’OU “OU=PC,OU=IT-Connect,DC=it-connect,DC=local”
$ComputersListAD = (Get-ADComputer -Filter * -SearchBase “OU=PC,OU=IT-Connect,DC=it-connect,DC=local”).DNSHostName
# Obtenir l’espace disque disponible sur chaque machine de la liste
Invoke-Command -ComputerName $ComputersListAD -ScriptBlock { Get-CimInstance -Class Win32_LogicalDisk | Select-Object -Property DeviceID, Name, @{
label=’UsedSpace’
expression={(($_.Size – $_.FreeSpace)/1GB).ToString(‘F2’)}
} }
Ici, nous utilisons le paramètre -ScriptBlock, mais il est tout à fait possible d’exécuter un script sur le même principe via le paramètre -FilePath.
D. Préciser des identifiants
Si l’utilisateur actuel n’a pas les droits nécessaires, il est possible de fournir des identifiants en ajoutant le paramètre -Credential. Il attend comme valeur un objet PSCredential avec un nom d’utilisateur et un mot de passe, et que nous pourrons générer via Get-Credential :
$Identifiants = Get-Credential
Invoke-Command -ComputerName W11-01.it-connect.local -Credential $Identifiants -ScriptBlock { Get-Service }
Cela garantit que l’exécution se fait avec les permissions de l’utilisateur spécifié, sinon, c’est l’utilisateur actuel au niveau de la session PowerShell qui est utilisé.
E. Utiliser une session persistante
Une autre façon de faire, plutôt que d’utiliser -Credential et -ComputerName, c’est d’utiliser une session WinRM (persistante) ou une connexion SSH. Pour le premier cas, il convient de créer une nouvelle session via New-PSSession et d’utiliser le paramètre -Session, tandis que pour le second cas, le paramètre -SSHConnection doit être spécifié.
Par exemple :
$MaSession = New-PSSession -ComputerName W11-01.it-connect.local -Credential IT-Connect\admin.pc
Invoke-Command -Session $MaSession -ScriptBlock { Restart-Computer -Force }
Quand vous utilisez -ComputerName, PowerShell va créer une session pour exécuter la commande puis fermer la session dans la foulée. S’il y a besoin de partager des données entre plusieurs commandes exécutées de façon indépendante, il est nécessaire d’utiliser une session persistante, comme dans l’exemple ci-dessus. Cette méthode présente l’avantage de conserver les données dans une même session, jusqu’à ce qu’elle soit fermée.
F. Utiliser des arguments
Vous pouvez utiliser des arguments pour passer des valeurs ou des valeurs de variables entre la machine locale et la machine distante. Cela s’effectue via l’utilisation du paramètre -ArgumentList et de la variable spéciale $Args.
Dans l’exemple ci-dessous, la variable $ServiceName est définie sur la machine locale. Sa valeur est passée à la machine distante via l’utilisation du paramètre -ArgumentList et cette valeur est utilisée lors de l’exécution de la commande via l’appel $args[0]. Étant donné qu’il peut y avoir plusieurs arguments (séparés par une virgule), cela génère un tableau dont la première valeur est stockée à l’index 0.
$ServiceName = “winrm”
Invoke-Command -ComputerName $ComputersList -ScriptBlock { Get-Service $args[0] } -ArgumentList $ServiceName
L’image ci-dessous illustre bien le fonctionnement.
IV. Conclusion
Invoke-Command est une commande indispensable pour administrer des machines à distance via PowerShell, que ce soit pour exécuter une seule commande ou un script complet. Grâce à ce mécanisme, il est possible d’optimiser la gestion de son infrastructure et de gagner en efficacité.
Pour apprendre PowerShell, retrouvez mon cours en ligne et mon livre :
Ingénieur système et réseau, cofondateur d’IT-Connect et Microsoft MVP “Cloud and Datacenter Management”. Je souhaite partager mon expérience et mes découvertes au travers de mes articles. Généraliste avec une attirance particulière pour les solutions Microsoft et le scripting. Bonne lecture.