"Как приручить дракона" - почему работает мультик, но не фильм?
"Как приручить дракона" - почему работает мультик, но не фильм?
https://oper.ru/news/read.php?t=1051627630
Аудиоверсия: https://oper.ru/video/getaudio/dragonfilm.mp3
Вспоминаем Powershell в нескольких частях. Часть 2. Windows update
Для ЛЛ: серия пометок по костылям
Конечная цель серии постов: написать свой очень маленький и очень кривой WSUS, поскольку развития WSUS больше не предвидится, но я про это писал
Часть 1. База из баз. Теория
Часть 1.1 Зачем ставить обновления на Linux и Windows и куда угодно, если в отделе работают проверенные электроником сотрудники, и все работает?
Часть 1.2 Чем плох WSUS, SCOM, прочее ПО, и факты в Ansible?
Часть 1.3 Почему Powershell, а не Python?
Часть 1.4 Прочие базовые вещи
Часть 1.5 Классы и объекты, для тех, кто пропускал школу
Часть 1.6 К теме обновлений в Windows
Часть 1.7 Как это все хранить и обрабатывать?
Часть 1.8 Давайте начинать. Мой первый класс
Часть 1.9 Немного магии, не очевидной с первого раза
Часть 1.10 Мой первый массив
Часть 1.11 Суй массив в файл. И забирай из файла
Часть 1.12 Теперь все вместе
Часть 2. Windows update
Часть 2.1 Служба обновлений и ее журнал
Часть 2. Windows update
Часть 2.1 Служба обновлений и ее журнал
Часть 2.2 Настраиваем удаленный доступ
Часть 2.3 Ловим исключения
Часть 2.4 Проблема слишком больших прав
Часть 2.5 Разрешение удаленного подключения
Часть 2.6 Параллельная обработка задач, -parallel, powershell jobs, Runspaces
Часть 2.7 И, наконец, получим первый список
Часть 2.8 Итого
Почему код написан вручную, а не через любой из ИИ?
Я пробовал и продолжаю пробовать. ИИ хорошо пишет маленькие задачи, и крайне полезен для сценариев «напиши вот так» - чтобы понять, как это работает. Но ИИ пишет странный код в некоторых сценариях, и написать промт для правки занимает столько же по времени, как написать правку самому.
Копилот вообще очень хорош, но не для всех сценариев.
Форматирование кода
Код не отформатирован отступами, пробелами, и так далее, для экономии места. Так делать, конечно, не надо.
Часть 2.1 Служба обновлений и ее журнал
Для второй части разберемся, что такое в первом приближении служба обновления, и что с ней как.
Для этого мне понадобится виртуальная машина, в моем случае с Windows Server 2025 Evaluation. Поскольку это Evaluation, и я не использую сабж в коммерческих целях, то мне не надо объяснять, что в данном случае это Fair use, насколько это возможно. Хотя для учебных целей мне бы и следовало купить и учебную лицензию (взять в институте), и Licence Windows Server CAL - Student only к нему.
Хотя мог бы сказать, как импортозаместители – что-то NVidia Microsoft дорого, давайте дешевле.
За работу обновления отвечает сервис wuauserv, он же Windows Update.
Он хранит свои логи много где, в том числе:
Events – Windows – Application -
Microsoft-Windows-WindowsUpdateClient/Operational
И в текстовом файле - %systemroot%\Logs\CBS, остальное убрали в ETL (Windows Update log files)
Но про это позже, в части три.
Для просмотра обновлений есть ущербный, но мне сойдет, командлет
Get-HotFix
Осталось все ничего.
В составе Windows есть сервис WinRM , живет на портах TCP/5985 = HTTP и TCP/5986 = HTTPS
Проверим локально:
netstat -an | findstr "5985"
Или по новой школе
Get-NetTCPConnection | where {$_.LocalPort -eq 5985}
Но вы можете посмотреть и параметры
get-Item WSMan:\localhost\Service\EnableCompatibilityHttpListener
get-Item WSMan:\localhost\Service\EnableCompatibilityHttpsListener
По умолчанию – false.
WinRM имеет свои настройки безопасности, подключений, итд. Если у вас что-то не работает, в 99% случаев эти настройки меняли сервисы имитационной безопасности, и сделали что-то плохое. Поэтому нужно знать, что они сделали, и как это чинить. Сами они это починить не могут. Сервисы имитационной безопасности, вообще все, ничего другого не умеют.
Часть 2.2 Настраиваем удаленный доступ
К делу. Заведем новый файл, в нем заведем переменную «где храним скрипты» и переменную версии, просто так чтобы была (не просто так)
$PfadZurSpeicherdatenbank = $PSScriptRoot
$Skriptversion = "10"
$MeineErsteLogin = $PfadZurSpeicherdatenbank + "\" + "dieparole.txt" #*
* Разрешается заменить dieparole на derparol. Если вы эльф
Проверим наличие файла с логином и паролем, и, если его нет, то предложим сохранить. Хранение файла с паролем не очень безопасно, и даже совсем не безопасно, но можно каждый раз вручную вводить.
Если файла нет, то создадим, и посмотрим что там внутри
$PfadZurSpeicherdatenbank = $PSScriptRoot
$Skriptversion = "10"
$MeineErsteLogin = $PfadZurSpeicherdatenbank + "\" + "dieparole.txt"
$DasPasswordFileExist = Test-Path -Path $MeineErsteLogin
if ($DasPasswordFileExist -eq $false) {$DieParole = Get-Credential
Export-Clixml -Path $MeineErsteLogin -InputObject $DieParole}
notepad $MeineErsteLogin
Как легко заметить, имя пользователя хранится в открытом виде, пароль лежит в зашифрованном виде, но, еще раз, это не безопасно.
Заведем список серверов. В моем случае список сделан вручную, но вы легко можете сформировать список из AD (через Get-ADComputer с фильтрами и без), или из любых других источников.
$MeineServerliste = @("192.168.10.155","192.168.10.156")
Для проверки доступности WinRM есть два командлета, или можно свой метод написать, если хочется. Командлеты: Test-NetConnection и Test-WSMan. Это не заменяющие, а дополняющие друг друга методы. Test-NetConnection ответит на вопрос «открыт ли TCP port и есть ли хотя бы пинг». Пинга может не быть, это нормально. Test-WSMan ответит на вопрос «ответил ли там кто-то»
Часть 2.3 Ловим исключения и ошибки
В powershell и любом коде иногда бывает событие «не смогла». Его надо обработать. Вариантов обработки много, это и классический Try-Catch-Finally, и варианты -ErrorAction and -ErrorVariable. Можно обрабатывать переменную $Error.
В чем проблема. Кроме часто встречаемого Silentlycontinue, нужно еще и ошибку как-то обработать.
Попробуем три варианта, с ошибками и без.
Remove-Variable Labubu1 -ErrorAction SilentlyContinue; Remove-Variable Labubu2 -ErrorAction SilentlyContinue
$GutenTag01 = Test-Netconnection -ComputerName $MeineServerliste[0] -Port 5985
$GutenTag02 = Test-WSMan -ComputerName $MeineServerliste[0]
$GutenTag03 = Test-WSMan -ComputerName $MeineServerliste[0] -Authentication Default -Credential $DieParole
$GutenTag04 = Test-WSMan -ComputerName $MeineServerliste[0] -Authentication Default -Credential $DieParole -ErrorVariable $Labubu1 -OutVariable $Labubu2
В моем случае сервер $MeineServerliste[0] точно включен и доступен, но.
$GutenTag01 выдаст объект «проверено, доступно».
$GutenTag02 отдаст три какие-то строки.
$GutenTag03 и $GutenTag04 не отдадут ничего, хотя в выводе я получу ошибку
The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting. Use winrm.cmd to configure TrustedHosts.
Тот же текст, что падает в переменную $Labubu1. Можно обрабатывать и так.
Часть 2.4 Проблема слишком больших прав
На этапе выдачи прав, особенно в сложной среде, возникают проблемы. Наибольшая проблема – менеджмент и отдел имитационной безопасности, прочитавшие пособие по информационной безопасности. Выглядит это так, как будто вахтер баба Маша, женщина как вахтер уважаемая, пришла в оружейную комнату за пулеметом. Потому что почему бы и нет. В итоге пулемет будет валяться в углу, приходи кто хочет, бери что хочет.
Будьте крайне осторожны с делегированием и разрешениями на данном этапе.
Часть 2.5 Разрешение удаленного подключения
Вернемся к делу. Выполню на удаленном сервере Enable-PSRemoting и посмотрю, что изменится. А потом сделаю
Set-Item WSMan:\localhost\Client\TrustedHosts -Value 192.168.10.100
где 192.168.10.100 – IP моего ПК. Делать так в продуктивной среде, конечно, ни надо ни в коем случае.
Firewall тоже не забудьте настроить.
Часть 2.5 Выбор методики первичного сбора информации
Есть несколько вариантов первичного сбора информации. Часть серверов может быть выключена. Часть не быть доступна с каким-то из логинов-паролей, или там не включен WinRM сервис. Или сервис включен, но не доступен, потому что так настроен Firewall.
Перед тем, как обрабатывать «весь список компьютеров», возможно, имеет смысл проверить «все ли включены и доступны», сократив список для обработки. Те, что не доступны, постепенно обработать вручную, или ввести для них дополнительные проверки.
Часть 2.6 Параллельная обработка задач, -parallel, powershell jobs, Runspaces
Если у вас 1..10.. 100 серверов, то их можно обработать и последовательно. Пусть на каждый уйдет даже 5 минут, всего 500 минут, поставил на ночь сбор первичной статистики, утром собрал. Если же вам надо быстро, и, конечно, асинхронно, потому что таймаут на некоторые тесты по умолчанию полчаса, то у вас не так много выбора между powershell jobs и runspaces
Поскольку тема достаточно сложная, то она будет вынесена в часть 4, или в часть 5.
Часть 2.7 И, наконец, получим первый список
$DataRemote1 = Get-HotFix -ComputerName $MeineServerliste[0] -Credential $DieParole
В нем есть, все что нам надо для первичной обработки, в том числе список установленных обновлений в поле
$DataRemote1[0].HotFixID
Остается дописать три строки:
$Fehlermeldung01 = "Achtung, da ist etwas schiefgelaufen"
if (Test-Path $MeineErsteSicherungsdatei){$NewKeinArray = Import-Clixml -Path $MeineErsteSicherungsdatei}
else {Write-Host $Fehlermeldung01}
Часть 2.8 Итого
$PfadZurSpeicherdatenbank = $PSScriptRoot
$Skriptversion = "10"/
$MeineErsteLogin = $PfadZurSpeicherdatenbank + "\" + "dieparole.txt"
$DasPasswordFileExist = Test-Path -Path $MeineErsteLoginif ($DasPasswordFileExist -eq $false) {
$DieParole = Get-Credential
Export-Clixml -Path $MeineErsteLogin -InputObject $DieParole}else {$DieParole = Import-Clixml $MeineErsteLogin}
#notepad $MeineErsteLogin$MeineServerliste = @("192.168.2.150","192.168.2.151")
Remove-Variable Labubu1 -ErrorAction SilentlyContinue; Remove-Variable Labubu2 -ErrorAction SilentlyContinue
$GutenTag01 = Test-Netconnection -ComputerName $MeineServerliste[0] -Port 5985
$GutenTag02 = Test-WSMan -ComputerName $MeineServerliste[0]
$GutenTag03 = Test-WSMan -ComputerName $MeineServerliste[0] -Authentication Default -Credential $DieParole -ErrorAction SilentlyContinue
$GutenTag04 = Test-WSMan -ComputerName $MeineServerliste[0] -Authentication Default -Credential $DieParole -ErrorVariable $Labubu1 -OutVariable $Labubu2 -ErrorAction SilentlyContinue$DataRemote1 = Get-HotFix -ComputerName $MeineServerliste[0] -Credential $DieParole
$DataRemote1[0].HotFixID
$Fehlermeldung01 = "Achtung, da ist etwas schiefgelaufen"if (Test-Path $MeineErsteSicherungsdatei){$NewKeinArray = Import-Clixml -Path $MeineErsteSicherungsdatei}
else {Write-Host $Fehlermeldung01}
Литература
Windows Update log files
Инвентаризация ИТ-активов штатными средствами Windows с минимальными правами доступа
Test-NetConnection
Test-WSMan
Powershell: How to encrypt and store credentials securely for use with automation scripts.
Save Credentials to File in PowerShell
Devblog -ErrorAction and -ErrorVariable
Everything you wanted to know about exceptions
Учебный блок (бесплатный от MS) Troubleshoot scripts and handle errors in Windows PowerShell
Mastering Error Handling in PowerShell with Try-Catch-Finally
Devblog PowerTip: Use PowerShell to View Trusted Hosts
Настройка удаленного взаимодействия в PowerShell (часть 1)
Настройка удаленного взаимодействия в PowerShell (часть 2)
UpdateService
JEA Session Configurations
Service Accounts Step-by-Step Guide - Managed service accounts and virtual accounts
Virtual Accounts well-known SID