PowerShell Remoting: инвентаризация 150 серверов за 10 минут вместо целого дня
PowerShell 2.0 встроен в Windows 7 и Server 2008 R2. Написали первый скрипт с Remoting - опрос 150 серверов параллельно вместо дня ручной работы.
PowerShell 2.0 вошёл в состав Windows 7 и Windows Server 2008 R2, принеся WS-Management Remoting и фоновые задания
Когда мы разворачивали Windows 7 и Server 2008 R2, главная нашумевшая часть была про Hyper-V, DirectAccess и прочие вещи. PowerShell 2.0, который там же шёл в комплекте, воспринимался как «ну, хорошо, обновили командную строку». А потом мы написали первый скрипт с Remoting - и это изменило ощущение от ручного сопровождения довольно существенно.
Откуда взялась задача
Один из наших клиентов - несколько площадок, суммарно около 150 серверов под управлением Windows Server 2003/2008. Раз в квартал нужно сдавать инвентаризационный отчёт: имя, роли, объём RAM, дисковое пространство (свободное и занятое), версии ключевого ПО. До сих пор это делалось так: инженер идёт по списку, заходит на каждый сервер через RDP или на худой конец через консоль, руками смотрит нужные параметры, записывает в таблицу. 150 серверов - это полный рабочий день, если не больше. Половину времени тратишь на ожидание RDP-сессии и прокликивание свойств системы.
PowerShell 1.0 уже позволял автоматизировать локальные задачи, но для удалённого управления нужно было WMI через DCOM, что то работало, то капризничало на нестандартных конфигурациях файрволов. PowerShell 2.0 принёс WS-Management Remoting - это протокол поверх HTTP/HTTPS, стандартный, управляемый через WinRM. Включил на серверах, и дальше работаешь со всем парком как с одним.
Как включали Remoting
На серверах под 2008 R2 WinRM 2.0 уже есть, его только нужно включить:
winrm quickconfig
На серверах под 2003 WinRM нужно установить отдельным пакетом. Это несколько минут на машину, но один раз. Групповой политикой или через скрипт с psexec - без разницы, главное сделать.
В нашем случае большинство серверов уже были на 2008/2008 R2, так что покрытие получилось хорошее с минимальными усилиями.
Что написали
Скрипт использует Invoke-Command с параметром -ComputerName и списком серверов. PowerShell 2.0 умеет выполнять команды параллельно через фоновые задания (Jobs) или через тот же Invoke-Command с параметром -AsJob. Мы пошли через прямой Invoke-Command со списком - он сам справляется с параллелизмом, запуская несколько сессий одновременно.
Внутри удалённого блока: Get-WmiObject Win32_ComputerSystem для RAM, Get-WmiObject Win32_LogicalDisk для дисков, Get-WmiObject Win32_OperatingSystem для версии ОС. Всё это возвращается объектами, и уже локально из этих объектов собирается итоговая таблица в CSV.
Примерная структура:
$servers = Get-Content servers.txt
$result = Invoke-Command -ComputerName $servers -ScriptBlock {
$os = Get-WmiObject Win32_OperatingSystem
$cs = Get-WmiObject Win32_ComputerSystem
$disk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'"
[PSCustomObject]@{
Host = $env:COMPUTERNAME
OS = $os.Caption
RAMgb = [math]::Round($cs.TotalPhysicalMemory / 1GB, 1)
DiskFreeGb = [math]::Round($disk.FreeSpace / 1GB, 1)
DiskSizeGb = [math]::Round($disk.Size / 1GB, 1)
}
} -ErrorAction SilentlyContinue
$result | Export-Csv -Path inventory.csv -NoTypeInformation -Encoding UTF8
Это упрощённая версия. В реальном скрипте добавили обработку ошибок, таймаут на сессию, несколько дисков вместо только C:, и отдельный список серверов, которые не ответили - чтобы разобраться с ними потом вручную.
Что получилось
Первый запуск по всем 150 серверам - около десяти минут. Включая время ожидания недоступных хостов и формирование файла. На выходе готовый CSV, который без дополнительной обработки открывается в Excel и превращается в нужный отчёт.
Недоступных оказалось семь штук - три по причине WinRM не был включён, четыре по сетевым причинам. По ним прошлись отдельно, вручную. Но это семь, а не сто пятьдесят.
Главная практическая ценность не в десяти минутах сами по себе - а в том, что задача перестала быть «выделить человека на день». Теперь это запустить скрипт, подождать, открыть файл. Инженер за это время сделает что-то полезное, а не ходит по RDP-сессиям.
Что заметили по ходу
Объекты, не текст. Это принципиальная разница с bash/cmd. Invoke-Command возвращает объекты PowerShell, а не строки. Не нужно парсить вывод - просто берёшь нужное свойство. После привычки делать это через grep по тексту переключение в голове занимает немного времени, но потом идёт естественно.
ErrorAction SilentlyContinue нужен аккуратно. Мы первые запуски делали без него - и скрипт замирал на недоступных хостах, ожидая таймаута на каждом по очереди. С параметром -ThrottleLimit можно управлять количеством параллельных сессий, по умолчанию 32 - для нашего парка достаточно.
Аутентификация. Remoting работает через Kerberos при наличии домена - никаких паролей в скрипте. На серверах в рабочих группах нужно либо CredSSP, либо добавить в TrustedHosts. У клиента все серверы в домене, так что этой проблемы не было.
Что дальше
Скрипт инвентаризации - первый, но не последний. Уже видно несколько очевидных применений: проверка наличия нужных обновлений на всём парке, удалённый сбор логов событий по конкретным ID, массовый перезапуск зависшей службы. Всё это раньше решалось либо скриптами через psexec с костылями, либо руками.
Сопровождение инфраструктуры с большим числом Windows-серверов без инструмента вроде Remoting - это всегда выбор между «медленно и надёжно» и «быстро, но только если повезёт с psexec». Теперь появился третий вариант.