Горячее
Лучшее
Свежее
Подписки
Сообщества
Блоги
Эксперты
Войти
Забыли пароль?
или продолжите с
Создать аккаунт
Регистрируясь, я даю согласие на обработку данных и условия почтовых рассылок.
или
Восстановление пароля
Восстановление пароля
Получить код в Telegram
Войти с Яндекс ID Войти через VK ID
ПромокодыРаботаКурсыРекламаИгрыПополнение Steam
Пикабу Игры +1000 бесплатных онлайн игр 2D-аркадный рогалик о подземных раскопках! Разрушайте блоки в погоне за сокровищами, улучшайте свой бур и развивайте навыки. Выполняйте задания, соревнуйтесь с друзьями и докажите, что вы — самый лучший искатель сокровищ!

Бурить-Копать!

Аркады, Мидкорные, 2D

Играть

Топ прошлой недели

  • solenakrivetka solenakrivetka 7 постов
  • Animalrescueed Animalrescueed 53 поста
  • ia.panorama ia.panorama 12 постов
Посмотреть весь топ

Лучшие посты недели

Рассылка Пикабу: отправляем самые рейтинговые материалы за 7 дней 🔥

Нажимая «Подписаться», я даю согласие на обработку данных и условия почтовых рассылок.

Спасибо, что подписались!
Пожалуйста, проверьте почту 😊

Помощь Кодекс Пикабу Команда Пикабу Моб. приложение
Правила соцсети О рекомендациях О компании
Промокоды Биг Гик Промокоды Lamoda Промокоды МВидео Промокоды Яндекс Маркет Промокоды Пятерочка Промокоды Aroma Butik Промокоды Яндекс Путешествия Промокоды Яндекс Еда Постила Футбол сегодня
0 просмотренных постов скрыто
NicePiterDetka
NicePiterDetka

Новогодняя елка на powershell⁠⁠

24 дня назад

В Винде. (Тестил на win 11 дефолт, доп библиотеки не загружал).

Открываем powershell. Правый клик на кнопке пуск - выполнить. Вводим powershell.
Открывается окно.
Вставляем текст из буфера (мы типа его скопировали предварительно туда).
Ругнется что вы копируете многобукв. Жмем paste anyway.
Клацаем энтер.
Ну все. Смотрим что получилось.

Код собственно:
Как можете бегло увидеть ничего криминального. Тупо вывод на экран в циклах.

function Show-AnimatedTree {
$height = 7
$frames = 20

for ($frame = 0; $frame -lt $frames; $frame++) {
Clear-Host
Write-Host "`n`t✨ Мерцающая Ёлочка ✨`n" -ForegroundColor Yellow

for ($i = 1; $i -le $height; $i++) {
$spaces = " " * ($height - $i)
$line = ""

for ($j = 1; $j -le (2 * $i - 1); $j++) {
# Случайным образом добавляем мерцание
if ((Get-Random -Maximum 4) -eq 0) {
$line += [char]0x2591 # Светлый символ
} else {
$line += "*"
}
}

Write-Host $spaces -NoNewline
# Разноцветные ярусы
switch ($i % 3) {
0 { Write-Host $line -ForegroundColor DarkGreen }
1 { Write-Host $line -ForegroundColor Green }
2 { Write-Host $line -ForegroundColor DarkYellow }
}
}

# Ствол
$trunkSpaces = " " * ($height - 2)
Write-Host $trunkSpaces -NoNewline; Write-Host "▓▓▓" -ForegroundColor Red

# Звезда на верхушке (мерцает)
$starSpaces = " " * ($height - 1)
if ($frame % 2 -eq 0) {
Write-Host $starSpaces -NoNewline; Write-Host "★" -ForegroundColor Yellow
} else {
Write-Host $starSpaces -NoNewline; Write-Host "☆" -ForegroundColor White
}

Start-Sleep -Milliseconds 300
}
}

Show-AnimatedTree

Может кому пригодится удивить знакомых и подруг на скорых праздниках. 😉

Показать полностью
[моё] Ёлки Powershell Windows Новый Год Текст
6
7
DmitriitheFals
Лига Сисадминов
Серия Кудахтеры: Ansible

Ansible для детского сада. Часть 6. Пока что не СУБД для Linux Server Update Services (LSUS)⁠⁠

1 месяц назад

А за скрюченной рекой
В скрюченном домишке
Жили летом и зимой
Скрюченные мышки.
Корней Чуковский. Скрюченная песня

У меня постоянное ощущение того, что я описываю не велосипед с костылями, а велосипед, который давно изобретен, на котором все катались лет 15 назад, если не 20. Что-то типа «введение в линукс и все вокруг для 10 класса». Что на информатике учат.
Поскольку этот текст пишется 50\50 – половина сделана еще осенью 2024, а половину я переделываю в ходе самообучения, и когда время и желание есть, то не удивляйтесь, что в тексте попадаются странные решения.

Для лиги лени: много примеров, как делать не надо, и как точно не работает

Ansible для детского сада в скольки то частях. Часть 1.Про все сразу
Ansible для детского сада в скольки то частях. Часть 2. Костылируем жалкое подобие WSUS - Linux Server Update Services (LSUS)
Ansible для детского сада. Часть 3. Настраиваем подобие безопасности и все остальное
Подготовка Git

Ansible для детского сада. Часть 4. Первичная настройка конечного клиента
4.1 Теоретически все просто
4.2 Сначала готовим открытую часть сертификата без пароля через Putty в Windows и еще раз вспоминаем что генерирует Putty в Windows, а что нужно в ssh
4.3 Детский скрипт, и как не надо делать
4.4 Отлаживаем SSH, снова и опять
4.5 Проблемы с переносом строки и не только
4.6 Проверяем, что получилось
4.7 Почти переходим к второму Ansible плейбуку
4.8 Воюем с пробелами в Anisble и восстанавливаем пример из первой статьи
4.9 Возвращаемся к основной задаче

Ansible для детского сада в скольки то частях. Часть 5. Приделываем костыли
5.1 Теоретическое обоснование костылей, или «зачем».
5.2 Выбор dataflow
5.3 Собираем Ansible facts без плейбука
5.4 Разбираем полученную выгрузку

Ansible для детского сада. Часть 6. Пока что не СУБД для Linux Server Update Services (LSUS)
6.1 Введение
6.2 Еще раз про готовые решения – Spacewalk, Satellite, Foreman + katello, Rudder
6.3 Переходим к проектированию на минималках
6.4 Начинаем писать код
6.4 Начинаем писать код или Powershell класс в классе. Часть 1
6.5 Продолжаем писать код или Powershell класс в классе. Часть 2

Ansible для детского сада. Часть 7, опять не связанная с Ansible
Ansible для детского сада. Часть 8. Теперь костыльная БД для Linux Server Update Services (LSUS)

Ansible для детского сада. Часть 6. Пока что не СУБД для Linux Server Update Services (LSUS)

Все, что мне было надо, я писал во второй части –

С целевой структурой данных ситуация сложнее. Для своего предпоследнего пет проекта под похожие задачи я просто развернул базу данных (Postgre), и туда клал разное. Нужно ли на первом шаге такое решение? Не знаю, мне не нужно, мне и бинарной таблицы хватит. Но что туда класть? Очевидно, туда должны попасть: FQDN, IP, дистрибутив, версия дистрибутива, ядро сейчас, последние дата и время доступности, аптайм. Должно ли туда попадать предыдущее состояние объекта, и какие-то еще настройки? Не очень важно, всегда можно расширить схему данных, добавить к объекту еще пару свойств.

И вот тут самое время подумать. Что я хочу от системы, какую задачу она решает. И как хранит данные для этого, и как глубоко.
Какие технические данные хранить уже понятно, с чем сравнивать, в общем, тоже.

6.2 Еще раз про готовые решения – Spacewalk, Satellite, Foreman + katello, Rudder
Повторю из второй части

У Microsoft был Baseline Security Analyzer
У Microsoft есть Security Compliance Toolkit (SCT)
У Microsoft есть Azure Update Manager operation(AUM).

В опенсорсе был Spacewalk. Последний релиз - 2.10 / March 18, 2020
У RH был Satellite. Это Foreman + katello+ support. Foreman 3.16 and Katello 4.18
Ivanti Patch for Endpoint Manager ? Ага:

Release Date September 18, 2025  The U.S. Cybersecurity and Infrastructure Security Agency (CISA) has published an analysis of the malware deployed in attacks exploiting vulnerabilities affecting Ivanti Endpoint Manager Mobile (EPMM). The Cybersecurity and Infrastructure Security Agency (CISA) obtained two sets of malware from an organization compromised by cyber threat actors exploiting CVE-2025-4427 and CVE-2025-4428 in Ivanti Endpoint Manager Mobile (Ivanti EPMM). Each set contains loaders for malicious listeners that enable cyber threat actors to run arbitrary code on the compromised server. Malicious Listener for Ivanti Endpoint Mobile Management Systems

Rudder ? Ничего про него не знаю.

Вопрос в сложности развертывания, это совсем не WSUS с его далее – далее - готово – пропишите WSUS в GPO

6.3 Переходим к проектированию на минималках
Функциональные требования: что делает этот софт – понятно, структурирует информацию про то, что надо обновить. Но, кстати, в таком случае нужно еще поле «пометки для объекта, почему не обновлено», и это уже точно нужно вести в CMDB (Configuration Management Database).
Не функциональные требования: как он это хранит.
И дальше UI \ UX.

Для начала, нужен уникальный идентификатор объекта.
В Windows это Machine ID, в Linux /etc/machine-id. Кроме этого, скорее всего, у сервера будет уникальный MAC или, для Cloud init, MAC останется, но со своими особенностями.

Что касается «истории состояния», то можно долго думать, читать про всякие 36 нормальных форм, Кимбалла, Data Vaul и вот это все.

Или можно зарезервировать строки данных:
Состояние00 «состояние сейчас»
Состояние01 «состояние при предыдущем опросе, вне зависимости от даты»
Состояние24 «состояние сутки назад»
Состояние168 «состояние неделю назад»
Состояние720 «состояние месяц назад»
Это позволяет организовать простую логику «было – стало» и перемещать данные по цепочке и до заполнения таблицы или таблиц. Вторая и третья нормальные формы SQL, вот это все.

На этом этапе и начинается разделение между «держим в каждом объекте 5 лишних групп, зато это один простой массив» и «держим данные в связанных таблицах с одним первичным ключом, зато модно стильно SQL».
Или,  можно немного упороться, и сделать объект из 5 объектов, то есть 3 мерную таблицу.
Это, с одной стороны, штатный и понятный (мне) механизм, с другой снимает требование по заведению SQL.
Получаемый объект будет в формате:
Сервер.Состояние00.Параметр01
Сервер.Состояние01. Параметр01
и так далее.
Давайте пробовать.
То есть, с точки зрения «вспомнить как Python работает с модулем psycopg2 и СУБД» полезнее сделать с базой данных, с точки зрения скорости \ удобства сейчас – проще сделать класс и класс из классов. Так что перенесу задачу «по базе данных» на часть 7.
Пока писал текст, понял что задача «хранение данных в базе» все равно требует считывания данных в какой-то объект или группу объектов, как-то с этим всем все равно потом работать.
Переусложнение не нужно.

Логика первичного заполнения

В первый момент времени не заполнено ничего. Поэтому при каждом запуске придется выполнять пре-проверку.
Получить сегодняшнее число, считать Data00 и выбрать Data00.timestamp
Взять Data00.timestamp. Если Null, то заполнить текущим временем и данными. 
Можно прописать везде 01.01.1970 (Unix Epoch) при первом запуске и проверять, что там. Это гораздо проще сравнивать при следующих шагах.

Дальше в чем-то проще.
Взять текущую дату. Сравнить с датой в Data01. Если данным в Data01 больше 24 часов, то переместить их в Data24. Ну или как-то так. Можно наоборот – посмотреть данные в Состояние720 и  Состояние168, сравнить с текущей отметкой времени, переместить.
На этом месте я понял, что было два пути:
1. Более правильный в сложных системах: планировать еще пару дней, нарисовать схему движения данных, итд. Возможно, сделать схему более гибкой.
2. Начать писать код, и поправить все что нужно, по мере необходимости. В том числе, расширить схему объекта, если надо.

6.4 Начинаем писать код или Powershell класс в классе.Часть 1
Почему Powershell, а не питон ? Да потому, что часть из этого кода пишется для людей, которые Powershell читать и использовать еще могут, а питон уже сложно, сложно ничего не понятно.

В таких статьях всегда есть соблазн «просто взять и скопипастить уже готовое» или «взять и сделать через AI». AI я использую, но не очень люблю. Даже не смотря на то, что Copilot очень нравится и коллегам, и мне.
Поэтому будет, как обычно, много примеров «неправильно» или «непонятно».
Всегда есть соблазн написать сразу итоговое «хорошо». На мой взгляд, надо писать и пример «вот так плохо, потому что».

Как я писал раньше, вот так, разумеется, работать будет:

Class AnsibleFacts01{
[string]$IsSUCCESS
[string]$FQDN
[string]$IP
[string]$Ansible_kernel_version
[string]$Comment}

$NewHost1 = [AnsibleFacts01]::new()
$NewHost1.Comment = "123"
$NewHost1

И даже вот так система сработает без ошибок:
Class AnsibleFactsForData{

[AnsibleFacts01]$Data00
[AnsibleFacts01]$Data01}
$NewHost2 = [AnsibleFactsForData]::new()

Но уже на этапе
$NewHost2.Data00.Comment = "123"
система скажет
The property 'Comment' cannot be found on this object.

Почему? Потому. Overloading constructors, вот это все по руководству Petri PowerShell Classes – Your Ultimate Guide

Поэтому что? Поэтому есть три пути. Webcam, дальше вы знаете.

Путь первый. Конструктор и инициализация.

Для начала перепишу первый класс, а точнее скопирую пример из Using other classes with a class in Powershell

class SomeOtherClass {
[string] $Status
[string] $Reason

SomeOtherClass () { }
SomeOtherClass ([string] $Status, [string] $Reason) {
$this.Status = $Status
$this.Reason = $Reason  }}

class SomeClass {
[string] $Server
[string] $File
[SomeOtherClass] $OtherClass
SomeMasterClass () { }
SomeMasterClass ([string] $Server, [string] $File, [SomeOtherClass] $Class) {
$this.Server  = $Server
$this.File  = $File
$this.OtherClass = $Class}}

Но к такому примеру нужна инициализация: (там же)

$testing = [SomeClass]@{
Server = 'Server01'
File  = 'SomeFile'
OtherClass = [SomeOtherClass]@{
Status = 'OK!'
Reason = 'Idk'  }}


В моем примере (выше) это будет выглядеть как:


Class AnsibleFactsForData01{
[AnsibleFacts01]$Data00
[AnsibleFacts01]$Data01}

$NewHost1 = [AnsibleFactsForData01]::new()
$NewHost1.Data00 = [AnsibleFacts01]@{Comment = '456'}

Посмотрю что получилось:
$NewHost1.Data00
Поменяю значение и еще раз посмотрю что получилось:
$NewHost1.Data00.Comment = '6'
$NewHost1.Data00

Вот такая вот история. Хотите, не хотите, а будьте добры инициализировать, а после этого уже как хотите.

Путь второй, тоже не очень

Class AnsibleFactsForData02{
[AnsibleFacts01]$Data00
[AnsibleFacts01]$Data01
# AnsibleFactsForData02 () { } Ввиду тупости, я не понимаю зачем эта строка, поэтому ее закомментировал.
AnsibleFactsForData02 () {
$this.Data00 =  [AnsibleFacts01]::new()}}

$NewHost02 = [AnsibleFactsForData02]::new()
$NewHost02.Data00.Comment = '12'

Проверим что вышло:
$NewHost02.Data00

Выглядит, что все работает.
Теперь проверим:
$NewHost02.Data01.Comment = '34'

И, конечно, так не работает.
Потому что внутри AnsibleFactsForData02 я потрогал только  $this.Data00, и не потрогал $this.Data01

Раз я его не потрогал, то под него не выделилась память, и все такое. Но у меня есть оправдание, когда в школе люди учили  typedef struct, constructor и прочие ~className (Destructors), я прогуливал.

Тут должен быть третий путь, но я его не придумал.
Но в моем примере можно вместо класса с классами внутри использовать простой массив классов, только придется запомнить, что [0] это сейчас, [1] это в прошлый раз, итд.

Осталось записать это в файл.

6.5 Продолжаем писать код или Powershell класс в классе. Часть 2

Упрощаем и отрезаем.  Получаем:

Class Ans_F{ # AnsibleFacts
[string]$IsSUCCESS
[string]$FQDN
[string]$IP
[string]$Ansible_kernel_version
[string]$Comment}

Class A4D { #AnsibleFactsForData
[Ans_F]$D00
[Ans_F]$D01
[Ans_F]$D24 # «состояние сутки назад»
[Ans_F]$D168 # «состояние неделю назад»
[Ans_F]$D720 # «состояние месяц назад»
# AnsibleFactsForData02 () { } не понимаю зачем эта строка, поэтому закомментировал.
A4D () {
$this.D00 =  [Ans_F]::new()
$this.D01 =  [Ans_F]::new()
$this.D24 =  [Ans_F]::new()
$this.D168 =  [Ans_F]::new()
$this.D720 =  [Ans_F]::new() }}


$NewHost02 = [A4D]::new()
$NewHost02.D00.Comment = '12'
$NewHost02.D01.Comment = '34'
$NewHost02.D00

$NewHost03 = [A4D]::new()
$NewHost03.D168.Comment = '56'

$HostList = @()
$HostList += $NewHost02
$HostList += $NewHost03
$ScriptPath = $PSScriptRoot
$OutFileName = 'Ansible2.xml'
$OutFullName = $ScriptPath + "\" + $OutFileName
Export-Clixml -Path $OutFullName -InputObject $HostList

$HostListExport = Import-Clixml -Path $OutFullName
$HostListExport[1].D168.Comment

Есть минус, про Select при выборе формата – можно забыть.

Литература
machine-id(5) — Linux manual page
Cloud init Network configuration
MS about_Classes

stackoverflow Using Classes within an class
Petri PowerShell Classes – Your Ultimate Guide
How and where to properly define classes and enums in your PowerShell modules
Powershell v5 Classes & Concepts

Показать полностью
[моё] Windows IT Другой мир Linux Linux и Windows Powershell Microsoft Программа Программирование Текст Длиннопост
0
frozensnoow

Дамы и госппода...⁠⁠

2 месяца назад

Без лишних предисловий. Понадобилось протестировать некоторые возможности PowerShell. Был неприятно удивлен, что таких базовых вещей нет "из коробки". Скачал архив с оффициального сайта Microsoft Learn, но где-то был пунктик, что ПО хоть и собственность Майков, но разрабатывается не ими (но ими подписано). Внутрненний шиз настоял проверить Касперским, решил ещё и на VirusTotal закинуть. Результат убил...

Пруф:

https://learn.microsoft.com/ru-ru/sysinternals/downloads/pst...

https://www.virustotal.com/gui/file/a9ca77dfe03ce15004157727...

Дамы и госппода...
Windows Microsoft Программа Powershell IT юмор IT Негатив
10
12
DmitriitheFals
Лига Сисадминов
Серия Кудахтеры: Ansible

Ansible для детского сада. Часть 5. Приделываем костыли⁠⁠

2 месяца назад

У меня постоянное ощущение того, что я описываю не велосипед с костылями, а велосипед, который давно изобретен, на котором все катались лет 15 назад, если не 20. Что-то типа «введение в линукс и все вокруг для 10 класса». Что на информатике учат.

Для лиги лени: много примеров, как делать не надо, и как точно не работает

Ansible для детского сада в скольки то частях. Часть 1.Про все сразу
Ansible для детского сада в скольки то частях. Часть 2. Костылируем жалкое подобие WSUS - Linux Server Update Services (LSUS)
Ansible для детского сада. Часть 3. Настраиваем подобие безопасности и все остальное
Подготовка Git

Ansible для детского сада. Часть 4. Первичная настройка конечного клиента
4.1 Теоретически все просто
4.2 Сначала готовим открытую часть сертификата без пароля через Putty в Windows и еще раз вспоминаем что генерирует Putty в Windows, а что нужно в ssh
4.3 Детский скрипт, и как не надо делать
4.4 Отлаживаем SSH, снова и опять
4.5 Проблемы с переносом строки и не только
4.6 Проверяем, что получилось
4.7 Почти переходим к второму Ansible плейбуку
4.8 Воюем с пробелами в Anisble и восстанавливаем пример из первой статьи
4.9 Возвращаемся к основной задаче

Ansible для детского сада в скольки то частях. Часть 5. Приделываем костыли
5.1 Теоретическое обоснование костылей, или «зачем».
5.2 Выбор dataflow
5.3 Собираем Ansible facts без плейбука
5.4 Разбираем полученную выгрузку

Ansible для детского сада в скольки то частях. Часть 5. Приделываем костыли

5.1 Теоретическое обоснование костылей, или «зачем».

С какого-то возраста появился вопрос: «Зачем?» Вот раньше тебе звонил приятель, например, говорил: «Слушай, я познакомился с двумя девушками, у них отдельная квартира в Отрадном, я выпить купил. Поехали!» И ты сразу ехал. Если бы тебя спросили: «А зачем?», ты бы сказал: «Ну как, зачем? Ты че, дурак? Две девушки, отдельная квартира! Посидим, выпьем, ну...» А сейчас...

Перед тем, как идти дальше, необходимо принять решение про архитектуру Linux Server Update Services (LSUS) на первом этапе. Поскольку сейчас я хочу только собирать и показывать статистику в нужном мне виде, с нужной детализацией. Часть информации я могу получать, не изобретая новую систему учета, а взяв имеющуюся, и переформатировав отчет из нее. Но насколько это будет сложно и долго? Нужен ли мне будет настоящий разработчик для такой задачи, потому что разработчик сделает ее быстрее, но сделает ли так, как мне надо? Учитывая, что я сам не знаю, как мне надо, значит, остается только попробовать сделать.

5.2 Выбор dataflow
Про что это? В результате обработки (входных данных) я получу (обработанные входные данные). Затем мне надо понять:
Где я буду обрабатывать сырые данные, на хосте с ansible или сделаю файл «как есть», положу его в общую папку (или как-то еще ?), заберу с хоста с Windows и там обработаю. Мне все равно, под что писать простой обработчик, под Windows или под Linux, и на чем писать – могу на баш (много секса, мало смысла), могу на питоне, могу на powershell. При малых объемах нет принципиальной разницы, обработается ли файл на 100 – 1.000 – 10.000 хостов за минуту, или за две.
Куда я помещу обработанные входные данные, в csv, xlsx, xml, или в web\html.
Если в web, то на каком веб-сервере? Апач, нжинкс, IIS, или даже MiniWeb и Small HTTP Server.
Нужно ли хранить исторические данные ?

Все это, и даже больше, я писал во второй части –

С целевой структурой данных ситуация сложнее. Для своего предпоследнего пет проекта под похожие задачи я просто развернул базу данных (Postgre), и туда клал разное. Нужно ли на первом шаге такое решение? Не знаю, мне не нужно, мне и бинарной таблицы хватит. Но что туда класть? Очевидно, туда должны попасть: FQDN, IP, дистрибутив, версия дистрибутива, ядро сейчас, последние дата и время доступности, аптайм. Должно ли туда попадать предыдущее состояние объекта, и какие-то еще настройки? Не очень важно, всегда можно расширить схему данных, добавить к объекту еще пару свойств.

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

5.3 Собираем Ansible facts без плейбука

Во второй части факты собирались одной командой,
ansible proxmox -m setup -a "filter=ansible_uptime_seconds" --ask-pass
В предыдущей (4-й) части я остановился на выполнении плейбука

ansible-playbook report23.yml --inventory  /home/user/second_inventory.ini --private-key  /home/ansible1/.ssh/ansible_key

Нужно ли делать плейбук именно для сбора фактов? Получается, что нет. Достаточно еще раз прочитать про ключи к ansible, и сделать:
[-i INVENTORY] [--list-hosts] [-l SUBSET] [--flush-cache]
[--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER]

То есть выполнить все в одну команду:

ansible all --module-name setup --inventory  /home/user/second_inventory.ini --private-key  /home/ansible1/.ssh/ansible_key

не забывайте про all, даже если указываете --inventory  /home/user/second_inventory.ini.

на выводе вы получите текст ужасающей длины, в формате с {}, [], и еще чем-то. 150 килобайт на мои 3 (три) тестовые виртуальные машины.

Из этого огромного массива представляет интерес:

FQDN, IP, дистрибутив, версия дистрибутива, ядро сейчас, последние дата и время доступности, аптайм. То есть, в нужный мне объект должны попасть:
Удачность соединения: 192.168.1111.2222 | SUCCESS => {
FQDN: "ansible_fqdn"
Hostname: "ansible_hostname"
IP: "ansible_all_ipv4_addresses"
IPv6: "ansible_all_ipv6_addresses":
тип: "ansible_board_name": "Virtual Machine",
Текущие сессии: "SSH_CONNECTION":
Текущий пользователь "USER": "ansible1",. С этим параметром надо поработать, а то есть любители забыть закрыть сессию.
MAC "macaddress": ". Нужен, но не для сетевых настроек, а для сверки, не сделал ли кто-то, случайно, клонирование с совпадающим MAC адресом. Бывает и такое легаси.
"ansible_kernel": "6.1.0-40-amd64",
"ansible_kernel_version": "#1 SMP PREEMPT_DYNAMIC Debian 6.1.153-1 (2025-09-20)",
"ansible_lsb": {
"codename": "bookworm",
"description": "Debian GNU/Linux 12 (bookworm)",
"id": "Debian",
"major_release": "12",
"release": "12"

Все вместе выглядит или как начало поиска готового решения «как свернуть xml в набор объектов», или как задача первого (для начинающих) уровня сложности с AlgoMap.io  \ Codility \ LeetCode \ итд, свертывание xml в объект со свойствами.  Не взяв xml.etree.ElementTree, а все сам, все руками. Дело не сложное, но надо вспоминать лаго алгоритм

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

Поэтому сделаю быстро, грязно, на powershell под windows, и так делать, вообще говоря, не нужно.

Еще придется не забыть сразу сделать выгрузку с примером ошибки недоступности хоста, и что-то с этим делать.

5.4 Разбираем полученную выгрузку

Поскольку все сделано в непревзойденном стиле «давайте не будем спрашивать нейросеть», то не удивляйтесь, что написано не просто плохо, а отвратительно плохо. Ирония не в том, могу ли я сделать задачу «сверните xml в массив вложенных объектов», как на интервью для джуна, а в том, хочу ли я потом искать, в какой путь это свернулось.

Поэтому вот вам еще один образец, как делать плохо и неправильно. Еще и неполный образец. Еще и на Powershell. Короче, сплошной позор.

# Ansible facts parser

Write-Host "Start 01 ================="

$Version = "AFP001"

$ScriptPath = $PSScriptRoot

$DataFromFile001 = Get-Content ($ScriptPath + "\" + "resultv01.txt")

Write-Host 'Read from file total' $DataFromFile001.count

Write-Host 'Read from file first' $DataFromFile001[0]

Write-Host 'Read from file last' $DataFromFile001[$DataFromFile001.count -1]

$SplitStartMark = '| SUCCESS => {'


Write-Host "Start 02 ================="

for ($Mark = 0; $Mark -lt $DataFromFile001.count; $Mark++){

if ($DataFromFile001[$Mark] -like "*$SplitStartMark") {Write-Host "Mark" $Mark ';' $DataFromFile001[$Mark]

}}


Class Split{

[int]$Position

[string]$String

}


Write-Host "Start 03 ================="

$SplitStartMarkPosition = @()


for ($Mark = 0; $Mark -lt $DataFromFile001.count; $Mark++){

if ($DataFromFile001[$Mark] -like "*$SplitStartMark") {

Write-Host "Mark" $Mark ';' $DataFromFile001[$Mark]

$NewHost = [Split]::new()

$NewHost.Position = $Mark

$NewHost.String = $DataFromFile001[$Mark]

$SplitStartMarkPosition += $NewHost

Remove-Variable NewHost

}}

Write-Host "Total" $SplitStartMarkPosition.Count


Write-Host "Start 04 ================="

Class AnsibleFacts01{

[string]$IsSUCCESS

[string]$FQDN

[string]$IP

[string]$ansible_kernel_version}



$NewHost1 = [AnsibleFacts01]::new()

$NewHost1.IsSUCCESS = $DataFromFile001[0]

for ($Mark = 0; $Mark -lt $SplitStartMarkPosition[1].Position; $Mark++){


if ($DataFromFile001[$Mark] -like '*ansible_fqdn*') {$NewHost1.FQDN = $DataFromFile001[$Mark]}

if ($DataFromFile001[$Mark] -like '*ansible_all_ipv4_addresses*') {$NewHost1.IP = $DataFromFile001[$Mark+1]}

if ($DataFromFile001[$Mark] -like '*ansible_kernel_version*') {$NewHost1.ansible_kernel_version = $DataFromFile001[$Mark]}

}


$NewHost1 | fl


Write-Host "Start 05 ================="

$NewHost2 = [AnsibleFacts01]::new()

$NewHost2.IsSUCCESS = $DataFromFile001[$SplitStartMarkPosition[1].Position] -replace "[^a-z][^A-Z]" -replace "{",""

for ($Mark = $SplitStartMarkPosition[1].Position; $Mark -lt $SplitStartMarkPosition[2].Position; $Mark++){

if ($DataFromFile001[$Mark] -like '*ansible_fqdn*') {$NewHost2.FQDN =  $DataFromFile001[$Mark] -replace '"ansible_fqdn":',"" -replace " ", "" -replace ",","" -replace '"',""}

if ($DataFromFile001[$Mark] -like '*ansible_all_ipv4_addresses*') {$NewHost2.IP = ($DataFromFile001[$Mark+1] -replace '"',"").TrimStart()}

$kv = ''

if ($DataFromFile001[$Mark] -like '*ansible_kernel_version*') {$NewHost2.ansible_kernel_version = ($DataFromFile001[$Mark] -replace '"ansible_kernel_version":', ""  -replace "," -replace '"',"").TrimStart()}

}


$NewHost2 | fl

Что делать дальше – понятно. Тут и обработка ошибок, и нормальное формирование объекта, и что делать, если хост не отвечает, и сравнение состояния «как есть» и «как надо».

Заключение
На написание 5 заметок ушло где-то 10-15 дней, по часу в день. Не каждый день. Хотя один выходной я потратил, с обеда до ужина.
На запуск такого костыля «чтобы посмотреть, что там в простой инфраструктуре», зная как, и куда смотреть, ушло бы примерно 3 рабочих дня для 1 джуна. Даже если в инфраструктуре вообще ничего нет. Остальные работы, доведение выгрузки до читаемого вида, сбор образцов, итд, заняли бы еще пару дней с кофе.
Поэтому, если где-то нет такой выгрузки, то я не знаю, чем там занимается и отдел ИТ, и отдел имитации безопасности.

Литература
ahuffman / ansible-sudoers
Ansible docs: ansible
Microsoft: Windows PowerShell - Build User-Friendly XML Interfaces with Windows PowerShell
Microsoft:  Add-Member Module: Microsoft.PowerShell.Utility Module
Microsoft:  Everything you wanted to know about PSCustomObject
Microsoft:  about_Regular_Expressions

Показать полностью
[моё] Windows IT Опыт Linux Ansible Powershell Программирование Microsoft Программа Текст Длиннопост
2
9
apech.zzz
Лига Сисадминов

Странное с логон скриптом (иногда не работает - в 2% случаев примерно)⁠⁠

2 месяца назад

Логон скрипт на powershell содержит следующyю строчку:
`Invoke-RestMethod -Method Post -Uri $uri -Body $data -ContentType 'application/json' -UseDefaultCredentials -TimeoutSec 10`

$uri это просто айпишник, $data это просто джейсон

Именно эта строчка иногда зависает по таймауту в 10 секунд и вылетает в catch блок.
Все остальные строки скрипта отрабатывают нормально. Если бы это не работало в 100% случаев то было бы гораздо проще, но это происходит в 2-3% случаев, без какого либо паттерна (по пользователям или по компьютерам). К серверу который этот запрос принимает ничего не доходит.

Есть подозрение что одна из подсистем безопасности: анти-вирус или smartscreen или AMSI, блокирует запрос опираясь на какие-то эвристики - например может посчитать передачу NTLM credentials по не зашифрованному каналу в логон скрипте кражой кредсов. Это могло бы объяснить не постоянную природу блокировок запроса.

Что было рассмотрено/сделано:
- Фаервол - был всегда отключен и фаервол бы блокировал всегда а не иногда
- Сайт был добавлен в Trusted Sites - и это не помогло
- Прокси или DNS - прокси отсутствует (WPAD отключен), DNS не участвует поскольку uri это айпи адрес
- Сервер нагружен и не может 10 секунд прийти в себя - Сервер не нагружен к нему вообще ничего не дошло даже
- Компьютеры и Сервер находятся все в одном домене, в одном L3 сегменте, пинг 1 мс
- Пробовал включить логи WinHTTP, WinInet, Powershell в режиме Analytic, Debug - по ним особо ничего не поймешь даже когда все отрабатывает
- Стоит Eset Antivirus - в антивирусе нет никаких логов что он что-то заблокировал
- Procmon и прочие утилиты глубинного анализа не расматриваю потому что я узнаю пост-фактум о проблеме, не могу это воспроизвести по желанию.

Как можно добраться до первопричины? Спасибо
П.С.
Есть еще логофф скрипт который содержит такую же строчку и он с той же периодичностью не отрабатывает.

Показать полностью
Компьютерная помощь Windows Баг Powershell Active Directory Текст
14
7
hypo69
hypo69
Лига Сисадминов
Серия Философия PowerShell

А давайте встроим ии в powershell. Начало работы с MS AI Shell в PowerShell⁠⁠

2 месяца назад

В прошлом посте А давайте встроим ии в powershell. Часть вторая. Поисковик спецификаций мы научились работать с gemini-cli. Сегодня я познакомлю вас с инструментом от Microsoft.

AI Shell — инструмент от Microsoft, созданный для упрощения работы с PowerShell. Он интегрируется прямо в командную строку и использует языковые модели Microsoft (Phi, Copilot) на базе Azure AI, чтобы помогать находить команды, исправлять ошибки. и понимать вывод.

Установите модуль AI Shell из PowerShell Gallery.
Install-PSResource -Name AIShell -Preview

Запуск оболочки ИИ

Используйте Start-AIShell команду в модуле AI Shell , чтобы открыть расширенный интерфейс в Терминале Windows. При запуске AI Shell появится запрос на выбор агента.

Использование ai Shell

Прежде чем использовать агент Azure OpenAI, необходимо создать конфигурацию, содержащую конечную точку, ключи API и системный запрос. Запустите AI Shell, выберите агент и запустите /agent config. В открываемом файле конфигурации JSON необходимо указать конечную точку, имя развертывания, версию модели и ключ API. Вы можете настроить свойство системного запроса, чтобы лучше заземлить модель в конкретных вариантах использования, включенная по умолчанию для эксперта PowerShell. Кроме того, если вы хотите использовать OpenAI, вы можете настроить агент только с ключом API из OpenAI в закомментированных примерах в JSON-файле.

Агент Azure предназначен для непосредственного подключения Copilot в Azure к командной строке. Она предоставляет помощь по командам Azure CLI и Azure PowerShell. Чтобы использовать этот агент, необходимо войти в Azure с помощью команды az login из Azure CLI.

Использование AI Shell для взаимодействия с агентами

Используйте эти примеры запросов с каждым агентом.

Агент Azure OpenAI

  • «Как создать текстовый файл helloworld в PowerShell?»

  • «Какова разница между параметром и параметром в PowerShell?»

  • Как получить первые 10 самых интенсивных процессов ЦП на компьютере?

Copilot в агенте Azure

  • «Как создать новую группу ресурсов с помощью Azure CLI?»

  • «Как вывести список учетных записей хранения, которые у меня есть в Azure PowerShell?»

  • «Что такое Application Insights?»

  • «Как создать веб-приложение с помощью Azure CLI?»

Ниже приведена краткая демонстрация, показывающая агент Azure в действии:

Переключение агентов

Вы можете переключаться между агентами с помощью синтаксиса @ в сообщениях чата. Например

Вы также можете использовать команду чата для переключения агентов. Например, чтобы переключиться на агент openai-gpt, используйте /agent use openai-gpt.

Команды чата

По умолчанию aish предоставляет базовый набор команд чата, используемых для взаимодействия с моделью ИИ. Чтобы получить список команд, используйте команду /help в сеансе чата.

Вставка кода

При чате с агентом можно использовать команду /code post для автоматического вставки кода из ответа в рабочую оболочку. Это самый простой способ быстро получить код, который необходимо запустить в оболочке. Вы также можете использовать горячий ключ CTRL+d, CTRL+d для вставки кода в рабочую оболочку.

Ключевые привязки для команд

AI Shell имеет ключевые привязки для команды /code. В настоящее время привязки ключей жестко закодируются, но пользовательские привязки ключей будут поддерживаться в будущем выпуске.

Кроме того, можно легко переключаться между панелями, используя следующие сочетания клавиш.

Устранение ошибок

При возникновении ошибки в рабочем терминале можно использовать командлет Resolve-Error для отправки этой ошибки в открытое окно оболочки ИИ для разрешения. Эта команда запрашивает модель ИИ, чтобы устранить ошибку.

Вызов оболочки ИИ

Командлет Invoke-AIShell можно использовать для отправки запросов текущему агенту в окне открытого окна оболочки ИИ. Эта команда позволяет взаимодействовать с моделью ИИ из рабочего терминала.


Серия «Философия PowerShell»

Полезно? Подпишись.
Понравилось — ставь «+»
Задавай вопросы в комментариях 👇👇👇
Удачи! 🚀

Показать полностью 9
[моё] Powershell Системное администрирование Искусственный интеллект Openai Microsoft Azure Гайд Гифка Длиннопост
0
16
DmitriitheFals
Лига Сисадминов
Серия Кудахтеры: powershell

Вспоминаем Powershell в нескольких частях. Часть 4. Параллельное исполнение: Powershell jobs⁠⁠

3 месяца назад

Для ЛЛ: серия пометок по костылям

Конечная цель серии постов: написать свой очень маленький и очень кривой 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.2 Настраиваем удаленный доступ
Часть 2.3 Ловим исключения
Часть 2.4 Проблема слишком больших прав
Часть 2.5 Разрешение удаленного подключения
Часть 2.6 Параллельная обработка задач, -parallel,  powershell jobs, Runspaces
Часть 2.7 И, наконец, получим первый список
Часть 2.8 Итого

Часть 3. Обрабатываем, что получилось
Часть 3.1 Немного про общую логику
Часть 3.2 В предыдущих сериях
Часть 3.3 Обновление списка обновлений
Часть 3.4 Обрабатываем оба списка сразу – список обновлений и список с сервера
Часть 3.5 Осталось только выгрузить в Excel
Часть 3.6 Отладка и наладка
Часть 3.7 Альтернативы?


Часть 4. Параллельное исполнение: Powershell jobs
Часть 4.1 Почему Powershell jobs
Часть 4.2 Руководство
Часть 4.3 Переходим к примерам Powershell jobs
Часть 4.4 Переходим к практике Powershell jobs

Часть 4. Параллельное исполнение: Powershell jobs

Часть 4.1 Почему Powershell jobs

У Powershell есть несколько вариантов параллельного исполнения кода.
Первый и наиболее известный, это Foreach-Parallel
Второй - Start-Job и Start-ThreadJob

В чем минус Job ? Это параллельное исполнение скрипта, из результатов которого еще и надо задачу получить. Плюс, точнее минус, этому процессу сложно отдавать какой-то объект для исполнения, у него непривычная схема того, что ему можно отдать на вход. То, что в руководстве описано как «Example 10: Use the ArgumentList parameter to specify an array»

В чем плюс? Сохраняется читаемость, в моем случае. Я ж не настоящий программист.

Часть 4.2 Руководство
В руководстве написано крайне .. плохо -
Start-Job -ScriptBlock
и дальше пишите себе что хотите.
но ScriptBlock это крайне, крайне неудобно, если не читать описание:

$a = { Get-Service BITS }
Invoke-Command -ScriptBlock $a

То есть, скриптблок можно описать почти как функцию

Like functions, script blocks can include the dynamicparam, begin, process, and end keywords

только есть нюансы.

Часть 4.3 Переходим к примерам Powershell jobs

Пример


$PfadZurSpeicherdatenbank = $PSScriptRoot
$Skriptversion = "12"
$Block1 =
{Get-ChildItem}

Start-Job -ScriptBlock $Block1 -Name JobExample01
Start-Job -ScriptBlock $Block1 -Name JobExample01 # это повтор строки и так надо для примера
Get-Job
Get-Job -Name JobExample01
Receive-Job -Name JobExample01

Обратите внимание на параметры  State и HasMoreData
Get-Job | Select Id, Name, PSJobTypeName, State, HasMoreData 
Get-Job | Select Id, Name, PSJobTypeName, State, HasMoreData | format-table

Сделайте
$Data2 = Receive-Job -Name JobExample01
$Data2

Обратите внимание.
Я запросил итоги задачи «-Name JobExample01». Таких задач в списке должно быть две,
и в переменную попали оба вывода, от двух задач с разными ID и одинаковыми именами. ID уникален, имя – нет, зато имя можно генерировать.

Теперь сделайте все что выше в виде одного скрипта, и удивитесь – в вывод $Data2 не попало ничего. Хотя задачи в списке есть. Но вывод из задачи со статусом Completed и HasMoreData = False вы уже получили, а вывод из задачи, которая еще выполняется (Running), хотя данные из нее еще не получали, но HasMoreData  =True.

Удалим все задачи.

Get-Job | Remove-Job

Чтобы перейти дальше, сделаем еще один пример из руководства:

$a ={ param($p1, $p2)
"p1: $p1"
"p2: $p2"}

&$a -p2 "First" -p1 "Second"

И примеры не из руководства: пример 1

$Job02 = {
param ($Out500001)
write-host "JB1" $Out500001}

Start-Job -ScriptBlock $Job02 -ArgumentList "ABC123"
Start-Sleep 5; Get-Job ;
Get-Job | Receive-Job
Get-Job | Remove-Job

И примеры не из руководства: пример 2

$Job03 = {
param ($Out500001)
foreach ($Job03data in $Out500001){
write-host "JB3" $Job03data}}

$Job03Array = (1,2,22)
Start-Job -ScriptBlock $Job03 -ArgumentList $Job03Array
Start-Sleep 5;
Get-Job | Receive-Job

И примеры не из руководства: пример 3

$Job04 = {
param ($Out500001)
foreach ($Job03data in $Out500001){
write-host "JB4" $Job03data}}

$Job03Array = (1,2,22)
Start-Job -ScriptBlock $Job04 -ArgumentList  (,$Job03Array)
Start-Sleep 5;
Get-Job | Receive-Job

И примеры не из руководства: пример 4

$Job05 = {
param ($Input01, $Input02)
write-host "JB5-1 " $Input01
write-host "JB5-2 " $Input02}

Start-Job -ScriptBlock $Job05 -ArgumentList ("A123", "B456")
Start-Sleep 5;
Get-Job | Receive-Job

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

Часть 4.4 Переходим к практике Powershell jobs

И теперь делаем все сразу!

$PfadZurSpeicherdatenbank = $PSScriptRoot
$Skriptversion = "12"
$MeineErsteSicherungsdatei = $PfadZurSpeicherdatenbank + "\" + "nur-eine-datei-part12.xml"
$Fehlermeldung01 =  "Achtung, da ist etwas schiefgelaufen"

if (Test-Path $MeineErsteSicherungsdatei){$NewKeinArray = Import-Clixml -Path $MeineErsteSicherungsdatei}
else {Write-Host $Fehlermeldung01}

$MeineErsteLogin = $PfadZurSpeicherdatenbank + "\" + "dieparole.txt"
$DasPasswordFileExist  = Test-Path -Path $MeineErsteLogin
if ($DasPasswordFileExist -eq $false) {$DieParole = Get-Credential
Export-Clixml -Path $MeineErsteLogin -InputObject $DieParole}
else {$DieParole = Import-Clixml $MeineErsteLogin}

$MeineServerliste = @("192.168.122.250","192.168.122.251")
# $DataRemote1 = Get-HotFix -ComputerName $MeineServerliste[0] -Credential $DieParole

$Rn = Get-Random -Minimum 1 -Maximum 200
$NameRn = "JobExample12" + $Rn
$Block2 = {
param ($ServerAsParam, $CredentialsAsParam)
$DataInBlockRemote1 = Get-HotFix -ComputerName $ServerAsParam -Credential $CredentialsAsParam
Return $DataInBlockRemote1}

Start-Job -ScriptBlock $Block2 -ArgumentList ($MeineServerliste[0], $DieParole)  -Name $NameRn
Start-Sleep 5;
$DataInBlock = Get-Job -Name $NameRn| Receive-Job

Заключение

На этом как бы все. Все необходимые элементы для своего личного костыля, если он вам действительно нужен, у вас есть.

Литература
Как использовать циклы While и Foreach в Powershell Foreach на примерах
Running ForEach in parallel on Windows Powershell 5 (and older)
about_Foreach
about_Foreach-Parallel
Optimize performance using parallel execution
Работа с фоновыми процессами через Jobs в Powershell
Named Arguments for PowerShell Functions: Best Practices
PowerShell background jobs unlock scripting performance
about_Script_Blocks
PowerShell Tip –> Passing array as an argument to a Job/ ScriptBlock
Возврат значения из powershell invoke-command агенту SQL-Server

Показать полностью
[моё] Windows Microsoft Wsus Powershell IT Текст Длиннопост
0
18
DmitriitheFals
Лига Сисадминов
Серия Кудахтеры: powershell

Вспоминаем Powershell в нескольких частях. Часть 3. Обрабатываем, что получилось⁠⁠

3 месяца назад

Для ЛЛ: серия пометок по костылям

Вместо предисловия.
Недавно от бабки в поликлинике узнала, что творог опасен. «У знакомой внук дураком сделался через него. Его творогом кормили, от кальция родничок рано зарос, а мозг продолжал расти, и теперь он в ынторнэтах сидит, кнопки нажимает».
Тут много таких, творогом покалеченных

Конечная цель серии постов: написать свой очень маленький и очень кривой 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.2 Настраиваем удаленный доступ
Часть 2.3 Ловим исключения
Часть 2.4 Проблема слишком больших прав
Часть 2.5 Разрешение удаленного подключения
Часть 2.6 Параллельная обработка задач, -parallel,  powershell jobs, Runspaces
Часть 2.7 И, наконец, получим первый список
Часть 2.8 Итого

Часть 3. Обрабатываем, что получилось
Часть 3.1 Немного про общую логику
Часть 3.2 В предыдущих сериях
Часть 3.3 Обновление списка обновлений
Часть 3.4 Обрабатываем оба списка сразу – список обновлений и список с сервера
Часть 3.5 Осталось только выгрузить в Excel
Часть 3.6 Отладка и наладка
Часть 3.7 Альтернативы?

Часть 3. Обрабатываем, что получилось

Часть 3.1 Немного про общую логику
Есть школьная логика, когда люди считают, что «нам нужен список всех обновлений, чтобы понять, какое обновление установлено! 111
Есть логика «ближе к Agile», когда нам не важно, какое обновление установлено, а важно, установлено ли последнее обновление, максимум предпоследнее.
В чем разница? В случае «школьной логики» последние лет 50 наверное, может больше, я в школе был травмирован абсолютно угашенной на голову преподавательницей химии, которой надо было не решение, правильное или неправильное, а соблюдение ее личной методологии решения. Абсолютно дурная бабка была.

Логика в моем случае в том, чтобы сначала получить MVP, minimum viable product, получить данные «как есть», и уже потом развивать код, добавляя в выгрузку, или в справку нужные мне данные.
Проблемы написать парсер Windows update нет никакой, может уже даже кем-то написан. Но мне не нужен полный список для решения моей частной задачи.
Задача в первом приближении написана не оптимально с точки зрения кода, объемов данных итд. Но опять же, мне не нужно решать глобальную задачу и делать комбайн с вертикальным взлетом, мне траву во дворе скосить, и скосить «сейчас».

Про это будет еще много отсылок в тексте.

Использование функций.
Использование функций дело, безусловно, полезное и правильное, с точки зрения читаемости кода. Проблема с Powershell в том, что в нем обработка ошибок в функции весьма странная и неудобная с непривычки. Поэтому функции я, конечно, использую, но в этом примере их будет меньше, чем стоило бы.
Например, получение списка обновлений NewKeinArray можно было спокойно вынести в функцию с параметром, или без.

Чистка кода от старого и закомментированного кода.
Для читаемости кода, конечно, было бы неплохо вычищать старый код.
Для прослеживания логики роста кода, чтобы спустя месяц было понятно, что было сделано и почему так было сделано, закомментированный код можно оставлять. Оба варианта сгодятся. Поскольку это учебная статья, то закомментированный код будет оставлен, для примеров и чтобы на него ссылаться.

Часть 3.2 В предыдущих сериях

В первой серии мы получили:
1) Файл nur-eine-datei.xml  c массивом( System.Array) из класса MeineErsteKlasse и генератор (mainefirstclass4pikabu .ps1) для создания этого файла.
Почему эта функция вынесена? Потому что генерация – это очень простой механизм, и его имеет смысл сделать отдельно. Можно ли сделать эту задачу как функцию в основном скрипте? Можно, но зачем? Это простая генерация файла со списком. Ниже попробую пояснить, почему именно так удобно именно мне.
2) Файл dieparole.txt с логином и паролем для удаленного сервера. Так делать не надо, хранение логинов и паролей в тексте – плохая практика. Нормальные люди разворачивают Vault.
3) Некорректно настроенный, так делать не надо, но для демонстрации сойдет, сервер с Windows. WinRM надо грамотно настраивать для безопасной работы!
4) Выгруженный список обновлений с этого сервера.
5) И код из части 2.

Что сделано не очень удобно, и, может, не очень правильно? Файл nur-eine-datei.xml  и оба скрипта должны лежать в одной папке, и называться одинаково в обоих исполняемых файлах. Можно было сделать запуск с параметром «путь к файлу», но, на мой взгляд, это только усложнит использование.

Первым делом переформируем список серверов для проверки.
В примере (2) есть строка

$MeineServerliste = @("192.168.211.150","192.168.211.151")

Первый сервер из нее доступен, второй – не существует.
В примере (2) есть еще одна ошибка, но я ее исправлю потом.
В достаточно большой инфраструктуре мы, зачастую, не знаем – доступен ли сервер, не доступен, но нам нужна общая картина – всего, из них доступно, из них не доступно.
Можно оптимизировать задачу как «сделать только список что доступно и что на них», можно оптимизировать задачу «все числится, из них не доступно». Это влияет на исполняемую логику в коде. Мне удобнее видеть ситуацию в виде общей таблицы.

Часть 3.3 Обновление списка обновлений
Перепишем первый скрипт, формирующий список обновлений, в следующем виде:

Class Updates{
[string]$OS
[string]$UpdateType
[string]$KB
[string]$KBDate
[string]$Other}

<#Для какого продукта он предназначен: Microsoft Server Operating System
Для какой версии продукта он предназначен: 24H2 (это Windows server 2025)
Номер: KB article numbers: 5063878
Дата выхода: 8/12/2025 #>
$Skriptversion = "12 from 05.09.2025"

$Ar2 = @()
$UPD =[Updates]::new()
$UPD.OS = "Server 2025 24H2" ; $UPD.UpdateType = "OS" ; $UPD.KB = "KB5063878"  ; $UPD.KBDate = "12.08.2025" ; $Ar2 += $UPD ;
# $MeinErstklassigesBeispiel | Format-Table –AutoSize
$PfadZurSpeicherdatenbank = $PSScriptRoot
$MeineErsteSicherungsdatei = $PfadZurSpeicherdatenbank + "\" + "nur-eine-datei-part12.xml"
Export-Clixml -Path $MeineErsteSicherungsdatei -InputObject $Ar2

# notepad $MeineErsteSicherungsdatei
# $NewKeinArray = Import-Clixml -Path $MeineErsteSicherungsdatei
# $NewKeinArray

Зачем? Во первых, нам не нужны проверки «через блокнот», сделанные для демонстрации «что там внутри». Во вторых, чтобы строка
$UPD.OS = "Server 2025 24H2" ; $UPD.UpdateType = "OS"
помещалась на экран.

Зачем так ?

Допустим, вы по каким-то причинам не перешли с сервера 2012R2 на сервер 2025, и вам нужно следить не только за тем, чтобы было или не было обновление на сервере 2025, но и за 2012.
При этом, поскольку подписки на расширенные обновления для 2012R2 у вас нет, то последнее обновление у вас будет от  10 октября 2023 года.
2023-10 Security Monthly Quality Rollup for Windows Server 2012 R2 for x64-based Systems (KB5031419)
Хотя, если бы вам на самом деле была нужна безопасность, то вы бы оформили подписку на обновления, и получали
2023-11 Security Monthly Quality Rollup for Windows Server 2012 R2 for x64-based Systems (KB5032249)
2023-12 Security Monthly Quality Rollup for Windows Server 2012 R2 for x64-based Systems (KB5033420)

И так далее, вплоть до
2025-08 Security Monthly Quality Rollup for Windows Server 2012 R2 for x64-based Systems (KB5063950)
2025-08 Security Monthly Quality Rollup for Windows Server 2012 for x64-based Systems (KB5063906)

В таком случае достаточно дописать одну строку в код:
$UPD.OS = "Server 2012 R200" ; $UPD.UpdateType = "OS" ; $UPD.KB = "KB5031419"  ; $UPD.KBDate = "10.2023" ; $Ar2 += $UPD ;

Читаемость сохраняется, думать не надо.

Да, конечно «правильнее в вакууме» было бы один раз взять и потратить два дня и распарсить весь список обновлений, или поискать готовый список, вдруг кто-то найдет.
Для рабочей задачи, которую я решаю, достаточно ручного добавления одной строки. Раз в месяц, может быть два раза в месяц, в случае выхода внепланового обновления.
В коде выше не специально, но была допущена ошибка. Найти ее и устранить предлагается самостоятельно.

Часть 3.4 Обрабатываем оба списка сразу – список обновлений и список с сервера

В переменной $DataRemote1 есть массив обновлений, а в $MeineServerliste[0] – имя сервера. Окей, и что с этим делать? Очевидно, создать новый класс, но сначала сделать то, чего делать нельзя.

Вспоминаем Powershell в нескольких частях. Часть 3. Обрабатываем, что получилось

Мне, не знаю как вам, не нужно обрабатывать весь список обновлений. Обновления в Windows последних (2016, 19, 22, 25) бывают:
Обновление стека обслуживания, например servicing stack update (KB5063666)
Кумулятивное плановое обновление, например 2025-08 Cumulative Update for Microsoft server operating system version 24H2 for x64-based Systems (KB5063878) (26100.4946)
Внеплановое обновление
Обновление dotnet, например
2025-07 Cumulative Update for .NET Framework 3.5 and 4.8.1 for Microsoft server operating system version 24H2 for arm64 (KB5056579)
Какие-то еще внеплановые обновление, типа обновления Edge и чего то там еще. Всякая мелочь.
Так нужно ли обрабатывать все 10-20-50 обновлений в списке установленных? Конечно, нет.
Поэтому:


$DataRemote2 = $DataRemote1 | Sort-Object -Property InstalledOn -Descending | Select-Object -First 4

Вот теперь заводим новый класс!

Class CurrentState{
[string]$Name
[string]$IP
[string]$IsActive
[string]$CurrentUpdateKB
[string]$CurrentUpdateKBDate
[string]$Other
[string]$LastInstalledKBFotTroubleshooting}

Remove-Variable TotalList -ErrorAction SilentlyContinue
$TotalList = @()

foreach ($ThisUpdate in $DataRemote2) {
$ThisServer = [CurrentState]::new()
$LastInstalledKBFotTroubleshooting = ""
foreach ($ThisUpdate2 in $DataRemote2){
$LastInstalledKBFotTroubleshooting = $LastInstalledKBFotTroubleshooting + $ThisUpdate2.HotFixID +'.'}

$ThisServer.LastInstalledKBFotTroubleshooting = $LastInstalledKBFotTroubleshooting

foreach ($BaseOfUpdate in $NewKeinArray) { 
$ThisServer.IP = $MeineServerliste[0]
Write-Host "This |"  $ThisUpdate.HotFixID " Base " $BaseOfUpdate.KB
if ($ThisUpdate.HotFixID -eq $BaseOfUpdate.KB) {
$ThisServer.CurrentUpdateKB = $ThisUpdate.HotFixID
$ThisServer.CurrentUpdateKBDate = $BaseOfUpdate.KBDate
$TotalList += $ThisServer
#break
}}

Remove-Variable LastInstalledKBFotTroubleshooting
Remove-Variable ThisServer  }

Часть 3.5 Осталось только выгрузить в Excel

В Powershell «из коробки» нет выгрузки в Excel. Есть txt, csv, xml. Внешний модуль для Excel, конечно, есть, но использовать его просто не хочется.
Однако, если вы сделаете

$CSVfile1 = $PfadZurSpeicherdatenbank + "\" + "MyExport1.csv"
Export-Csv -InputObject $TotalList -Path $CSVfile1
notepad $CSVfile1

То получите совсем не то, чего хотели, а что-то про #TYPE System.Object[]
Это совсем, совсем не то, что вам надо. Для решения этой проблемы есть несколько вариантов, самый читаемый, на мой взгляд,

$CSVfile2 = $PfadZurSpeicherdatenbank + "\" + "MyExport2.csv"
$CSVfile3 = $PfadZurSpeicherdatenbank + "\" + "MyExport3.csv"
$TotalList | Select * | Export-Csv -Path $CSVfile2 -Delimiter ";"
$TotalList | Select Ip, LastInstalledKBFotTroubleshooting | Export-Csv -Path $CSVfile3 -Delimiter ";"
notepad $CSVfile2
notepad $CSVfile3

Часть 3.6 Отладка и наладка

Что же делать, как же быть, если у вас поле CurrentUpdateKB – пустое? Не оказалось у вас установленного последнего обновления?
На мой взгляд, решение очевидно, нужно идти и ставить свежее обновление.


Но, если у вас другое мнение, то
Поле LastInstalledKBFotTroubleshooting у вас есть, Microsoft Update catalog доступен, дальше надо пояснять?

Часть 3.7 Альтернативы?

Пока обсуждал черновик с коллегами, выяснил что можно было решить эту задачу, инвентаризации, и попроще. Или иначе.
Можно было сделать, через, например, групповую политику, разовую задачу по выгрузке того, что мне нужно, в общую папку, в сотню – две файлов с разными именами. Потом уже гораздо проще решить задачу выборки из файлов.
Можно было выдернуть через Get-SilData, тоже вариант.
Можно было запросить SQL базу на WSUS, если она хоть как-то жива.  Там очень простой запрос.

Показать полностью 1
[моё] IT Windows Программирование Powershell Wsus Microsoft Длиннопост
0
Посты не найдены
О нас
О Пикабу Контакты Реклама Сообщить об ошибке Сообщить о нарушении законодательства Отзывы и предложения Новости Пикабу Мобильное приложение RSS
Информация
Помощь Кодекс Пикабу Команда Пикабу Конфиденциальность Правила соцсети О рекомендациях О компании
Наши проекты
Блоги Работа Промокоды Игры Курсы
Партнёры
Промокоды Биг Гик Промокоды Lamoda Промокоды Мвидео Промокоды Яндекс Маркет Промокоды Пятерочка Промокоды Aroma Butik Промокоды Яндекс Путешествия Промокоды Яндекс Еда Постила Футбол сегодня
На информационном ресурсе Pikabu.ru применяются рекомендательные технологии