PowerShell Remoting — настройка и удаленное управление

  • Tutorial
Здесь минимум теории, в основном практическая часть. Описывается как настроить WinRM, как изменить профиль сетевого адаптера, дается скрипт по добавлению в TrustedHosts с фильтрацией, объясняется зачем нужны доверенные хосты, и рассматриваются поверхностно удаленные подключения так чтобы можно было сесть и сразу админить удаленные машины.

Наиболее простой путь сконфигурировать удаленное управление это выполнить Enable-PSRemoting в оболочке powershell с правами администратора. При этом произойдет следущее:
  • запустится служба WinRM (если запущена перезапустится)
  • служба WinRM перейдет в состояние — автоматический запуск при старте
  • будет создан прослушиватель WinRM для HTTP трафика на порту 5985 для всех локальных IP адресов
  • будет создано правило файрвола для прослушивателя WinRM. Внимание, этот пункт завершится с ошибкой если любая из сетевых карточек имеет тип сети «публичная», т.к. открывать порт на такой карточке не хорошо. Если у вас при конфигурировании вышла такая ошибка измените профиль это сетевушки командлетом Set-NetConnectionProfile и после этого запустите Enable-PSRemoting снова. Если вам нужна сетевая карточка с профилем «Публичная сеть» запустите Enable-PSRemoting с параметром -SkipNetworkProfileCheck в этом случае будут созданы правила файрвола только из локальной сети.


После этого нужно разрешить подключаться к удаленной машине с той машины с которой будет происходить управление. Сделано это в целях безопасности для того чтобы уменьшить риск взлома сессии удаленного управления или DNS с подстановкой себя вместо удаленной машины и предотвратить исполнение скриптов на машинах которые вы принудительно не разрешили.

для проверки куда можно подключаться используем:
get-item wsman:\localhost\Client\TrustedHosts

для разрешения подключаться ко всем
set-item wsman:localhost\client\trustedhosts -value *

Если вы открываете доступ для всех указав * то WinRM будет подключаться ко ВСЕМ машинам без проверки. Помните, что вы открываете самого себя для потенциального взлома из локальной сети. Лучше указывать адреса хостов куда вам нужно подключится, тогда WinRM будет отклонять все остальные адреса или имена. Если машина с которой ведется управление находится в домене она будет доверять всем машинам этого домена. Если она не в домене, или в другом домене, то нужно указать в TrustedHosts адрес или имя машины на которую мы будем подключаться. Добавлять себя на машине к которой мы подключаемся не нужно.

в хелпе указаны команды, я их чуть чуть переделал в скрипт
######################################################################################
# добавляет NewHost в список TrustedHost с фильтрацией если такая строка уже есть
# можно дергать из командной строки указывая параметр напрямую например
# .\Add-TrustedHost.ps1 192.168.2.1
######################################################################################
param ( $NewHost = '192.168.2.89' )

Write-Host "adding host: $NewHost"

$prev = (get-item WSMan:\localhost\Client\TrustedHosts).value
if ( ($prev.Contains( $NewHost )) -eq $false)
{ 
    if ( $prev -eq '' ) 
    { 
        set-item WSMan:\localhost\Client\TrustedHosts -Value "$NewHost" 
    }
    else
    {
        set-item WSMan:\localhost\Client\TrustedHosts -Value "$prev, $NewHost"
    }
}

Write-Host ''
Write-Host 'Now TrustedHosts contains:'
(get-item WSMan:\localhost\Client\TrustedHosts).value

он проверяет на есть ли такая запись, если нет то добавляет в список. Вызывать можно из командной строки указав адрес или имя.

Есть разница указывать имя или адрес. Если в TrustedHosts будет только адрес то открыть сессию по имени не получится, и наоборот — если указать имя то прицепится по адресу не получится. Учитывайте это.


Часто встречается ссылка на команду
WinRM quickconfig

это не тоже самое что Enable-PSRemoting
в чем же разница
Enable-PSRemoting делает больше действий чем «winrm quickconfig». Командлет Set-WSManQuickConfig делает точно такие же действия как «winrm quickconfig». Enable-PSRemoting запускает Set-WSManQuickConfig когда ведет настройку системы

Set-WSManQuickConfig делает следущие действия:
  1. запускат WinRM сервис
  2. устанавливает автостарт службы WinRM в автоматический
  3. создает прослушиватель
  4. добавляет исключения файрвола

Enable-PSRemoting кроме этого делает еще следущее
  1. включает все зарегистрированные конфигурации сессий PowerShell для получения инструкций от удаленных машин
  2. регистрирует конфигурацию если она не зарегистрирована «Microsoft.PowerShell»
  3. регистрирует конфигурацию если она не зарегистрирована «Microsoft.PowerShell32» на 64 битных машинах
  4. убирает запрет «Deny Everyone» из дескриптора безопасности всех конфигураций сессий
  5. перезапускает сервис WinRM

источник
Enable-PSRemoting TechNet
Set-WSManQuickConfig TechNet



Удаленные подключения
1. Сессии 1-to-1
открываются командой
Enter-PSSession -ComputerName Test

Вы получите оболочку на удаленной машине. Подключится можно к самому себе указав localhost. Альтернативные кредиталы указываются с параметром -Credential, выход происходит командлетом Exit-PSSession

Ограничения следующие:
  • нельзя сделать второй прыжок — только 1 сессия, внутри сессии подключиться дальше нельзя
  • вы не можете использовать команды имеющие графический интерфейс. Если вы это сделаете оболочка повиснет, нажмите Ctrl+C чтобы отвисло
  • вы не можете запускать команды имеющие свой собственый шел, например nslookup, netsh
  • вы можете запускать скрипты если политика запуска на удаленной машине позволяет их запускать
  • нельзя прицепится к интерактивной сессии, вы заходите как «network logon», как будто прицепились к сетевому диску. Поэтому не запустятся логон скрипты, и вы можете не получить домашнюю папку на удаленной машине (лишний довод чтобы не мапать хом фолдеры логон скриптами)
  • вы не сможете взаимодействовать с юзером на удаленной машине даже если он туда залогинен. Не получится показать ему окошко или попечатать чтонибудь ему.

этот способ лучше всего для простых операций, зашел, подергал сервер и отключился. Если нужно удержать переменные в скопе, нужна длительная операция (много часов или дней), нужно больше возможностей по администрированию то нужно использовать технику попродвинутее.
Комментарий.
объекты переданные по сети обрезаются и перестают быть живыми. У них удаляются методы, свойства остаются. Вытащить объект на свою машину, поколдовать и засунуть обратно не получится. Если нужно больше пишите, допишу отдельно.


2. Сессии 1-to-many
Invoke-Command

определяем что будем исполнять так:
$sb = { команды для удаленной машины разделенные точкой с запятой }

передаем на удаленные машины Test1 и Test2
Invoke-Command -ComputerName Test1, Test2 -ScriptBlock $sb

за раз можно забросить на 32 машины. Если альтернативные кредиталы то используем параметр -Credential

Чтобы передать целиком скрипт вместо параметра -ScriptBlock пишем -FilePath, удаленной машине НЕ нужно иметь доступ к файлу, он будет разобран на запчасти, передан через HTTP и выполнен с той стороны.
Запомним что на той стороне будет новый скоп, так что ваш скрипт не получит значений из вашей консоли, а переменные скрипта могут оказаться на той стороне пустыми. Поэтому передавайте сразу целиком готовые инструкции и скрипты с параметрами.

для полноценного использования Invoke-Command надо уметь превращать строки в скрипт блоки. Например у вас есть команды которые зависят от какогото списка, вам нужно сгенерировать строку, превратить ее в ScriptBlock и отправить на удаленный комп:
$sb = [Scriptblock]::Create( $SomeString )

kuda78
В статье пропущен очень важный момент — передача параметров в скрипт на удаленной машине.

$deployRemote = {
param(
[string]$targetEnvName,
[string]$targetUsername)
$Global:ErrorActionPreference = «Stop»
#…
}

Invoke-Command -Session $session -ScriptBlock $deployRemote -ArgumentList ($targetEnvName, $targetUsername)

Да действительно пропущен. Сделал сознательно чтобы не загромождать обзор параметрами и описаниями. Спасибо. Параметр -ArgumentList работает как со скрипт блоками так и со сценариями

3. Сессии
Это когда с той стороны создается копия пошика постоянно висящая в памяти, и в нее отправляются команды. Как результат к ней можно переподключится, ченить долгое запустить на исполнение, цепляться из разных скриптов или разными юзерами. Например у вас есть набор скриптов решающих одну задачу по частям, каждый из них поочереди может подключатся к одной удаленной сессии, видеть результаты работы предыдущих команд, иметь одни загруженные модули, общие переменные, общее окружение, до тех пор пока сессия не будет принудительно закрыта.

Создание сессии происходит командлетом New-PSSession, результат можно поместить в переменную
$DC01 = New-PSSession -ComputerName DC01
$Controllers = New-PSSession DC01, DC02, DC03

использовать можно такие же параметры подключения как в Invoke-Command

Как использовать:
если 1-to-1
Enter-PSSession -Session $DC01

если 1-to-many
Invoke-Command -Sessions $Controllers -ScriptBlock {get-eventlog -logname security -newest 50}

посмотреть какие сессии открыты можно с помощью Get-PSSession, закрыть Remove-PSSession
закрыть вообще все сессии
Get-PSSession | Remove-PSSession

прицепится к сессии можно с помощью Connect-PSSession, отключиться через Disconnect-PSSession

Invoke-Command может создать сразу disconnected сессию, он отправляет команды на исполнение и отключатся, позже можно подключится и сгрузить результаты работы. Делается это параметром -Disconnected. Получение результатов через командлет Recieve-PSSession.

Сессии имеют очень много настроек, возможно даже создание сессий с обрезаным набором команд, модулей и т.п. Называется custom endpoints
Поделиться публикацией

Похожие публикации

Комментарии 10

    +1
    Блин, люди!!! Ну хотя бы заголовки статей вычитывайте на ошибки!
      +1
      спасибо
        0
        Не за что. Извините, что не в личку.
        Просто иногда выбешивает… Нервный я видимо :)
      0
      Есть вопрос. Как заставить WinRM принимать простые методы авторизации (к примеру, NTLM) по "логину и паролю" для доменного пользователя?
      Я встретился с тем, что если пользователь локальный, нет никаких проблем (plaintext или какое-то простое простое хеширование типа NTLM-шного), а если доменный, то надо городить или транзитную виндовую машину или krb + патчить curl.
      Есть одна библиотека для ruby с надстройкой над gss_api, но с ней тоже есть проблемы.
        +2
        Возможно я не совсем правильно понял вопрос, но аутентификацию доменными пользователями делаю следующим образом:

        $securePassword = convertto-securestring $targetPassword -asplaintext -force
        $cred = New-Object System.Management.Automation.PsCredential($targetUsername, $securePassword)
        $session = new-PSsession $targetServer -authentication credssp -credential $cred

        Предварительно необходимо разрешить передавать и получать CredSSP

        #Server Side:
          Enable-PSRemoting -Force
          Enable-WSManCredSSP -Role server
        
        #Client Side:
          Enable-WSManCredSSP -Role client -DelegateComputer '$($this.server)'

        И настроить к каким серверам возможен доступ либо через реестр либо через редактор групповых политик

        HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\CredentialsDelegation
        HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly
        
          0
          Спасибо за подробности.
          Я действительно упустил важный момент: я пытаюсь исполнять команды с линуксовой машины, поэтому ограничен в инструментарии.
            +1
            WsMan имеет очень много настроек например
            Cross-domain Remoting
            Remoting doesn’t work across Active Directory domains by default. If your computer is in DOMAINA, and you need to remote into a machine that belongs to DOMAINB, you’ll have to do a bit of work first. You’ll still need to ensure that your user account has permissions to do whatever it is you’re attempting in DOMAINB—the configuration setting we’re showing you only enables the Remoting connectivity. This is a Registry setting, so be careful when making this change:

            New-ItemProperty -Name LocalAccountTokenFilterPolicy -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System  -PropertyType DWord -Value 1

            This code will enable all members of a machine’s Administrators group, regardless of the domain they’re in, to use Remoting on the machine. So, in our example, you’d make this change on the machine in DOMAINB—the destination machine of the Remoting connection.

            или вот еще
            Several common parameters are used by the Remoting cmdlets:
            -Authentication specifies an authentication mechanism. Kerberos is the default; you can also specify Basic, CredSSP, Digest, Negotiate, and NegotiateWithImplicitCredential. CredSSP is a common alternative that offers a solution to the “second hop” problem, which we’ll discuss later. Note that the protocol you specify must be enabled in WinRM before it can be used, and only Kerberos is enabled by default.
            You can see the authentication protocols configured on the client by using this:

            ls wsman:\localhost\client\auth

            The remote authentication configuration can be viewed like this:

            Connect-WSMan -ComputerName server02 ls wsman:server02\service\auth

            тоесть он имеет в виду что можно принудительно указать Invoke-Command -ScriptBlock -Credential $cred -Authentication CredSSP
            подробнее см help Invoke-Command -Examples

            дайте пожалуйста обратную реакцию — нужно ли это добавить в статью? я посчитал что статья получится излишне перегруженной.
              0
              Большое спасибо за информацию.
              думаю, в конкретно этой статье это лишнее, но в статье вида "working with wsman/Winrm from non-windows OS" (а вдруг) пригодиться.
              Суть в том, что winRM фактически HTTP-SOAP API, где открыто всё почти всё, кроме авторизации, отличной от Basic/NTLM.
              Как только у меня будет возможность это всё проверить, я тут же сообщу результат.
              Еще раз спасибо.
        +1
        В статье пропущен очень важный момент — передача параметров в скрипт на удаленной машине.

        $deployRemote = {
            param(
                [string]$targetEnvName,
                [string]$targetUsername)
            $Global:ErrorActionPreference = "Stop"
            # ...
        }
        
        Invoke-Command -Session $session -ScriptBlock $deployRemote -ArgumentList ($targetEnvName, $targetUsername)

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое