В этой статье мы рассмотрим особенности использования командлета Invoke-Command для удаленного выполнения команд и скриптов. Возможно запускать команды удаленно на одном компьютере, или параллельно на множестве компьютерах в вашей сети. Командлет Invoke-Command использует возможности удаленного управления, заложенные в PowerShell Remoting. PowerShell Remoting позволяет удаленно подключаться к PowerShell сессиям на компьютерах через службу WinRM (Windows Remote Management) через протокол Web Services for Management (WS-Management). Этот сервис дает возможность принимать команды Powershell и устанавливать сеансы.
Настройка WinRM для PowerShell Remoting
Для связи между компьютерами в PowerShell Remoting используется протокол HTTP (порт TCP/5985) или HTTPS (порт TCP/5986). По умолчанию используется протокол HTTP, но даже этот трафик шифруется с помощью ключа AES-256 (впрочем, есть угроза атак man-in-the middle). Возможна аутентификация через Kerberos (в домене) или NTLM.
На удаленных компьютерах, к которым вы планируете подключаться должен быть запущена служба WinRM. Проверить это можно так:
Get-Service -Name "*WinRM*" | fl
Если служба не запущена, запустите ее:
Enable-PSRemoting
WinRM has been updated to receive requests. WinRM service started. WinRM is already set up for remote management on this computer.
Данная команда запустит службу WinRM (установит автоматический запуск), выставит настройки winrm по-умолчанию и добавит исключение в Windows Firewall. Команда Enable-PSRemoting –Force включает WinRM без запроса пользователя.
Теперь к компьютеру можно подключиться удаленно через PowerShell Remoting.
Set-WSManQuickConfig : ... WinRM firewall exception will not work since one of the network connection types on this machine is set to Public. Change the network connection type to either Domain or Private and try again.
Вам нужно изменить тип сети на частную (private), или использовать команду:
Enable-PSRemoting –SkipNetworkProfileCheck.
Также нужно включить правило Window Defender Firewall, которое разрешает доступ к WinRM в общедоступных сетях. Вы можете включить правило брандмауэра с помощью GPO или PowerShell:
Set-NetFirewallRule -Name 'WINRM-HTTP-In-TCP' -RemoteAddress Any
Чтобы проверить подключение к удаленному компьютер через PowerShell Remoting используется команда:
Test-WsMan compname1
Если у вас нет домена, или вы обращаетесь к компьютерам через PowerShell Remoting по IP адресам, в этом случае используется для аутентификации используется протокол NTLM. При использовании NTLM, при выполнении команду Invoke-Command появится ошибка:
[192.168.1.201] Connecting to remote server 192.168.1.201 failed with the following error message : The WinRM client cannot process the request. Default authentication may be used with an IP address under the following conditions: thetransport is HTTPS or the destination is in the TrustedHosts list, and explicit credentials are provided. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. + FullyQualifiedErrorId : CannotUseIPAddress,PSSessionStateBroken
Для корректной работы NTLM аутентификации, на компьютере, с которого вы будете устанавливать подключения нужно выполнить дополнительные действия: выпустить SSL сертификат и исопльзовать его для шифрования HTTPS трафика winrm, или добавить имя/IP адрес хоста в доверенные:
Set-Item wsman:\localhost\Client\TrustedHosts -value 192.168.1.201
Либо можно разрешить подключение ко все компьютерам (не рекомендуется, т.к. один из главных недостатков NTLM – он не осуществляет проверку подлинности).
Set-Item wsman:\localhost\Client\TrustedHosts -value *
Аналогичные настройки нужно сделать на удаленных хостах.
Чтобы вывести список доверенных хостов, выполните команду:
Get-Item WSMan:\localhost\Client\TrustedHosts
Чтобы применить изменения, перезапустите службу WinRM:
Restart-Service WinRM
Удаленное выполнение PowerShell с помощью Invoke-Command
Командлет Invoke-Command позволяет выполнить команду на одном или нескольких удаленных компьютерах.
Например, для запуска одиночной команды на удаленном компьютере можно использовать такую команду:
Invoke-Command -ComputerName dc01 -ScriptBlock {$PSVersionTable.PSVersion}
Эта команда выведет в вашу консоль значение версии PowerShell, установленной на удаленном компьютере, имя которого указано в параметре
-ComputerName
. В блоке
-ScriptBlock {[cmdlet]}
указывается команда, которую нужно запусть на удаленном компьютере.
По-умолчанию команда, посланная через Invoke-Command выполняется на удалённом компьютере от текущего пользователя. Если нужно выполнить команду от имени другого пользователя, сначала нужно запросить учетные данные пользователя и сохранить их в переменную:
$cred = Get-Credential
Invoke-Command -ComputerName comp-buh2 -Credential $cred -ScriptBlock {Get-NetAdapter}
Эта PowerShell команда выведет список сетевых интерфейсов на удаленном компьютере:
Можно задать несколько команд в блоке ScriptBlock, их нужно разделить точкой с запятой. Например следующая команда выведет текущий часовой пояс и изменит его на другой:
Invoke-Command -Computername dc01 -ScriptBlock {Get-TimeZone| select DisplayName;Set-TimeZone -Name "Astrakhan Standard Time”}
Invoke-Command позволяет выполнять не только отдельные команды, но и запускать скрипты PowerShell. Для этого используется аргумент
-FilePath
(вместо –ScriptBlock). При этом вы указываете путь к локальному PS1 файлу скрипта на вашем компьютере (вам не нужно копировать файл скрипт на удаленный компьютер):
Invoke-Command -ComputerName Server01 -FilePath c:\PS\Scripts\GetComputerInfo.ps1
Используем Invoke-Command для параллельного запуска команд на нескольких компьютерах
Командлет Invoke-Command можно использовать для параллельного выполнения команд на нескольких удаленных компьютерах.
В самом просто случае имена компьютеров, на которых нужно выполнить команды указываются через запятую:
Invoke-Command server1, server2, server3 -ScriptBlock {get-date}
Список компьютеров можно поместить в переменную (массив):
$servers = @(″server1″,″server2″,″server3″)
Invoke-Command -ScriptBlock { get-date} -ComputerName $servers
Или получить из текстового файла:
Invoke-Command -ScriptBlock {Restart-Service spooler} -ComputerName(Get-Content c:\ps\servers.txt)
Также можно получить список компьютеров в ADс помощью командлета Get-ADComputer из модуля AD PowerShell:
Чтобы выполнить команду на всех Windows Server в домене, исопльзуйте такой код:
$computers = (Get-ADComputer -Filter 'operatingsystem -like "*Windows server*" -and enabled -eq "true"').Name
Invoke-Command -ComputerName $computers -ScriptBlock {get-date} -ErrorAction SilentlyContinue
Если компьютер выключен, или недоступен, благодаря параметру SilentlyContinue скрипт не будет остановлен и продолжит выполнение на других компьютерах.
Чтобы понять с какого компьютера получены результаты, нужно использовать специальную переменную окружения PSComputerName.
$results = Invoke-Command server1, server2, server3 -ScriptBlock {get-date}
$results | Select-Object PSComputerName, DateTime
При запуске команды через Invoke-Command на нескольких компьютерах она выполняется параллельно. В Invoke-Command есть ограничение на максимальное количество компьютеров, которыми можно управлять одновременно (ограничение на количество одновременных PSSession). Оно определяется параметром ThrottleLimit (по умолчанию 32). Если вам нужно выполнить команду одновременно более чем на 32 компьютерах (например, на 128), используйте параметр –ThrottleLimit 128 (но это вызывает повышенную нагрузку на ваш компьютер).
Для запуска команд на удаленных компьютерах через Invoke-Command в фоновом режиме используется специальный атрибут
–AsJob
. В этом случае результат выполнения команды не возвращается в консоль. Чтобы получить результаты нужно использовать командлет
Receive-Job
.
Если вы хотите запускать команды на удаленном компьютере интерактивно, используйте командлет Enter-PSSession.