У цій статті ми розглянемо особливості використання командлет Invoke-Command для віддаленого виконання команд і скриптів. Можливо запускати команди віддалено на одному комп’ютері, або паралельно на безлічі комп’ютерах у вашій мережі. Командлет Invoke-Command використовує можливості віддаленого управління, закладені в Віддалення PowerShell. PowerShell Remoting дозволяє віддалено підключатися до PowerShell сесій на комп’ютерах через службу WinRM (Windows Remote 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 сертифікат або додати ім’я / IP адреса хоста в довірені:
Set-Item wsman:localhostClientTrustedHosts -value 192.168.1.201
Або можна авторизувати до все комп’ютерів (не рекомендується, тому що один з головних недоліків NTLM – він не здійснює перевірку справжності).
Set-Item wsman:localhostClientTrustedHosts -value *
Аналогічні настройки потрібно зробити на віддалених хостах.
Щоб вивести список довірених хостів, виконайте команду:
Get-Item WSMan:localhostClientTrustedHosts
Щоб застосувати зміни, запустіть службу 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:PSScriptsGetComputerInfo.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:psservers.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
.