← на главную
13 заметок с тегом

PowerShell

Сервис isDayOff для нужд автоматизации

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

Я очень люблю автоматизацию, особенно — автоматический контроль за соблюдением правил и договоренностей в системах. Человеческий фактор невозможно полностью исключить, зато можно заставить дотошных и не устающих роботов контролировать, что человек сделал всё правильно. Однако, здесь кроется одна проблема — человеки, в отличие от роботов, уходят на выходные и государственные праздники. Согласно Первому закону робототехники, робот не может причинить вред человеку или своим бездействием допустить, чтобы человеку был причинён вред. А что может быть противней, чем тикет на исправление некритической проблемы, прилетевший в выходные? Да, можно запрограммировать, чтобы тикеты не прилетали в субботы и воскресенья — но что делать с праздниками и переносами выходных?

isDayOff простой как автомат Калашникова, и легко встраивается в скрипты и пайплайны автоматизации. В простейшем виде через https://isdayoff.ru/today можно узнать, является ли текущий день рабочим, ну а дополнительные параметры к запросу могут дать информацию о любой дате в прошлом и будущем (в разумных пределах) и даже о праздниках в соседних странах (поддерживаются Белоруссия, Казахстан и Украина).

База сервиса активно поддерживается и приводится в соответствие законам, когда принимаются решения о переносах праздников и выходных. Чтобы не потерять функционал при возможном отключении сервиса (а в дивные новые времена обо всём начинаешь думать в разрезе «а что если забанят»), я обычно стараюсь в проектах использовать локальную базу на год вперед, сдампленную с сайта, и обновляющуюся ежемесячно — заодно, локальная копия базы снижает нагрузку на сервис, зачем зря напрягать бесплатное отличное решение.

В целом всё просто и понятно. Например, в виде без кеширования запрос обычно посылаю через подготовленную функцию, с логикой обработки ситуации когда сервис недоступен

С учетом простоты решения, его легко встраивать и в других ситуациях, когда требуется контролировать рабочий статус даты — уведомления, расписание резервного копирования, подсчёт количества рабочих дней до наступления дедлайна перезагрузки по обновлениям системы, и так далее.

Слава роботам!

 1   2 дн   PowerShell   КЭНК

Забрать своё из облаков: обновление вКачатора

Допилил небольшое, но важное дополнение для скрипта обогащения дампов профиля ВКонтакте. Эксплуатация предыдущей версии выявила существенный недостаток: видео с YouTube, импортированные в ВК, в разных разделах сайта фигурируют с разными ID (и разными URL). Выходит странненькое — по этим разным ссылкам открывается один и тот же объект (страницца) ВК, с теми же комментариями, лайками, и прочими атрибутами соцсети, и конечно же встроенный в объект ролик YouTube там тоже один и тот же, но ссылки на этот объект разные. И например, добавленное на стену видео, и то же видео, посланное в диалоге, будут иметь разные адреса. Поэтому старая версия скачивала, и складывала в папку видео несколько раз, что расходовало лишнее место (а у меня в избранные как-то попала даже девятичасовая прямая трансляция выхода в открытый космос с МКС).

Идеально было бы научить скрипт сразу узнавать такие дубликаты по адресам, и не скачивать повторы вовсе, но как это сделать я придумать не смог. Зато можно скачать через yt-dlp оригинал с ютуба, и по его метаданным распознать дубль, сравнив с метаданными уже скачанных видео. Так и поступил — теперь скрипт сохраняет в простой json информацию по всем уже скачанным файлам, и при закачке дубля не сохраняет его на диск, заменяя ссылки в дампе на уже скачанный экземпляр. На моем дампе это значительно сократило объём выгрузки.

Обновлённая версия уже на гитхабе: https://github.com/alexbatishchev/kenk-vk-enricher

Powershell и странненькое с TimeSpan

Авторы Powershell, с одной стороны, многое в своём творении придумали системно и логично. С другой стороны, постоянно натыкаешься на странности, объяснения которым в области логики не найти.

Любимый пример — класс TimeSpan, временной промежуток, отрезок времени между двумя датами. У объектов этого класса есть несколько свойств, отражающих заданный объектом промежуток времени в разных единицах измерения. И в перечне этих свойств неочевидная логика авторов языка проявляется в полной красе.

Вот свойства Hours, Minutes, Seconds, Milliseconds. Интуитивно думаешь, что это — значение промежутка времени в часах, минутах, секундах, и миллисекундах. Довольно быстро наступаешь на эти грабли, и узнаёшь, что это кое-что другое, а именно количество часов в рамках дня, минут в рамках часа и тому подобное. То есть, если промежуток времени у вас в 1 день и 1 час, то Hours — не 25, а 1. А если между датами прошло 2 часа и 10 минут, то свойство Minutes будет не 2*60+10, а просто 10. Зачем это надо? Ну, наверное для чего-то может пригодиться, хотя я ни разу за много лет эти свойства не использовал. Зато, сколько ошибок в скриптах из-за неверного их понимания я встречал на стековерфлоу и в прочих местах в интернетах!

Окей, столкнувшись с этим (или прочитав заранее в документации, что вряд ли), ты спустя какое-то время познаешь TotalHours, TotalMinutes, TotalSeconds и TotalMilliseconds, с той самой очевидной логикой «полное количество часов между датами» и так далее. Если между моментами времени прошло два с половиной часа, то это будет 2.5 TotalHours, 150 TotalMinutes и 9000 TotalSeconds. Ура, теперь-то всё понятно, можем смело фигачить!

И вот в этот момент, к полному сил и умиротворённому программисту, из-за угла подходят в кепках и адидасе братюни Days и TotalDays, и объясняют, что понятий он не знает, и вообще зря на раён зашел. Ибо Days — это в в натуре полное количество дней (а не как можно было бы по аналогии предполагать, количество дней в рамках года). А TotalDays — это да, это полное количество дней, дробь (типа, аккуратно посчитанное, вкуриваешь?). А Days — грубо посчитанное. Но полное. Почему? Короч, так надо. Кстати, дай позвонить!

И вот, сидишь, смотришь на это, и думаешь — а оно зачем вообще так?? Потом вздыхаешь, материшься, сверяешься с документацией ещё раз, пишешь в коде правильное.

Может показаться, что этот пост написан с целью излучить в пространство бессильную злобу — но на деле, это просто справочник. Я буду ходить сюда каждый раз, когда буду юзать TimeSpan, потому что запоминать подобное — просто портить себе мозг.

Дорогой Вася! Если тебе надо посчитать промежуток времени, юзай TotalDays, TotalHours, TotalMinutes, TotalSeconds и TotalMilliseconds, помни что они — вещественные, и означают то, что тебе нужно. А про другие свойства TimeSpan забудь!

А для вас — картинка, иллюстрирующая всю дичь TimeSpan

Слава роботам!

 7   23 дн   PowerShell   все эти ваши компьютеры

ArrayList и производительность массивов в Powershell

Powershell — язык весьма великодушный к программистам, почти всё в нём делается легко, интуитивно, и не требует особой подготовки и продумывания от автора кода. Однако, при выходе на объемные задачи начинают выстреливать некоторые вещи, которые для удобства изначально выполнены неэффективно.

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

$array = $array + $newElement — что может быть интуитивней? Оказалось, массивы в Powerhsell это имутабельные объекты, и поэтому предыдущий код фактически создает новый неизменяемый объект из всех элементов предыдущего массива и одного нового. Конечно, на больших объемах массивов такая операция будет занимать всё больше времени, и нелинейный рост вполне объясним. Этой неэффективности лишен специальный тип данных ArrayList — это тот же массив, разве что элементы добавлять самым очевидным способом через «плюс» в него нельзя.

Вот код, на котором я проверил время работы цикла из добавления N случайных строк к массивам в умолчальном варианте и варианте ArrayList

На 10 тысячах операций результаты примерно похожи — отличаются в десятки процентов. Но уже на сотне тысяч разница — на порядок. При этом время работы через ArrayList растет линейно вместе с количеством циклов, а у классических массивов — экспоненциально

Вот такие тонкости вскрываются спустя годы работы с языком. С другой стороны, это хорошо характеризует его в положительном плане — сколько за это времени гигабайт csvшек и джейсонов было перелопачено без этих ваших ArrayList?!

 297   4 мес   PowerShell

Забрать своё из облаков: kenk-vk-enricher 1.4

Допилил скрипт обогащения дампа Вконтакте. Теперь скрипт качает видео в разделах Видеозаписи, Стена и Сообщения — закачка идет через yt-dlp, перед использованием желательно обновить его до свежей версии, и залогиниться в ВК в одном из бразуеров на машине, тогда yt-dlp сможет использовать куки и больше видео будет доступно для скачивания. Также скачиваются аттачменты типа «файл» на стене и в сообщениях (те, что доступны по прямым ссылкам).

Сейчас актуальной версией скрипта мой личный профиль выкачивается на почти 200 гб, сказываются видео файлы в переписке и на стене — часто репостились интересные чужие видосы, и всё вместе занимает прилично места. Ну да больше-не меньше.

Скрипт на гитхабе: https://github.com/alexbatishchev/kenk-vk-enricher

Слава роботам!

Забрать своё из облаков: kenk-vk-enricher

Причесал и опубликовал скрипт, докачивающий в дамп официальной выгрузки из ВКонтакте картинки в переписку (сообщения) и фотоальбомы. Фотки выкачиваются и складываются заодно внутрь дампа в папки с именами, соответствующими оригинальным альбомам, а если они были опубликованы с подписью (как например часто было при параллельной публикации в ИГ) — подпись сохраняется в отдельный текстовой файл рядом.

В дампе переписке все файлы даются прямыми ссылками. А вот в дампе стены картинки прописаны ссылками вида https://vk.com/photoXXXXXXXXX_XXXXXXXXX — но тут был придуман хитрый ход, немного исправляющий ситуацию. Так как среди фотоальбомов есть «Фотографии на моей стене», то если сдампить их и из кода страницы выдернуть и прямые ссылки на файлы, и ссылки photoXXXXXXXXX_XXXXXXXXX (которые там есть), то можно закешировать это соответствие и подставить потом известные картинки в код выгрузки стены. К сожалению, так можно обойти только картинки, и только картинки ваши — репосты от других пользователей или групп так и останутся со ссылками на данные в серверах ВК. Как до них добраться без URL оригинальных файлов непонятно — с парсерами картинок ВК в интернете такая же беда как и с видео. Хотя жаль, стену со своими публикациями хотелось бы содрать в максимально полном виде, включая и репосты.

За недолгое время с прошлой публикации yt-dlp успел разучиться качать видео из вк, и вновь научился этому в свежем апдейте — похоже что война апишников с реверс-инженерами идёт денно и нощно. С учетом этого, выкачку видео пока думаю не реализовывать.

Забавное наблюдение — в дампе стены есть уже удалённые вами сообщения (с пометкой «Запись удалена»). Так приятно что заботливые товарищи всё хранят даже после удаления (евпочя).

КЭНК! Слава роботам!

КЭНК: безопасно храним секреты для скриптов PowerShell

Часто из скриптов PowerShell нужно обращаться к системам, требующим аутентификации — например, для парсинга данных о хостах из корпоративной системы мониторинга, или для выгрузки данных об уязвимостях из веб-портала системы обнаружения уязвимостей. Также нередко в этих случаях используются учетные записи с расширенными полномочиями во внешних системах, но в целом это не принципиально — любые секреты хочется хранить так, чтобы до них было невозможно добраться злоумышленнику.

Понятно, что харкодить креды в источниках или держать их в конфигурационных файлах скрипта — дело пропащее. Даже если зарезать на уровне файловой системы доступ только для учетной записи, от которой должен стартовать скрипт, остаётся возможность администратору сервера эти права изменить и данные прочитать. Неаккуратненько выходит ©.

К счастью, в Windows есть магическая штука на этот случай — Secure Strings — волшебство которых в данном случае заключается в том, что они работают с учетом контекста учетной записи, от которой запущены. Поэтому, если задать пароль ($pw = Read-Host -AsSecureString) прогнать его через ConvertFrom-SecureString ($pw | ConvertFrom-SecureString) и результат записать в файл, то на выходе будет чудесная буквенно-цифровая белиберда. А обратно эту белиберду можно превратить в пароль (Get-Content .\password.txt | ConvertFrom-SecureString), но только вот пароль правильным получится только если это преобразование работает от той же учетной записи, под которой шло прямое кодирование.

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

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

В интернетах пишут, что в свежих версиях павершелла появились интеграции с системами хранения паролей, но до этого мои руки пока не дошли — привычное работает, роботы трудятся, люди отдыхают

Пример кода, иллюстрирующий подход:

Ссылки по теме:

https://www.techtarget.com/searchitoperations/tutorial/How-to-secure-passwords-with-PowerShell
https://www.travisgan.com/2015/06/powershell-password-encryption.html

Слава Роботам! КЭНК!

 61   7 мес   PowerShell   КЭНК

КЭНК: тихое удаление обновления Windows по номеру KB

Задача: тихо удалить с хоста обновление Windows по номеру KB.

Какое-то время проблема легко решалась через wusa.exe /uninstall /kb:XXXXXX /quiet, но теперь в Windows 10 команда с ключом quiet просто игнорируется, а без ключа — задает много вопросов пользователю, что ожидаемо, но не подходит для решения задачи.

В интернетах быстро гуглится способ, который хорош, но не универсален. Способ рассчитывает на то что KB будет упомянута в имени пакета для DISM, а это бывает не всегда — в примере ниже у двух последних обновлений номера KB в имени пакета нет.

Ситуацию усложняет то, что в разных локалях ОС команда dism выдает информацию на разных языках, да к тому же не структурированным объектом — а строкой. К счастью, из строки все же можно выцепить имя пакета, а по нему — запросить подробную информацию (тоже строкой), где номер KB есть (судя по моим тестам) всегда:

Итоговое решение задачи такое:

  • смотрим список всех установленных обновлений и выдергиваем имена пакетов
  • по каждому пакету смотрим расширенное описание и ищем в нём искомый номер KB
  • если в описании найден нужный номер KB — пакет по его имени отправляется на деинсталляцию через DISM.exe /Online /Remove-Package /PackageName:$sFoundPackageName /quiet /norestart

Короткий сниппет, иллюстрирующий подход:

$sKBNumber = "4578968"
$aUpdts = dism /online /get-packages | ? {$_.Contains("Package_for")} | %{($_.Split(":"))[1].Trim()}
foreach ($sUpdate in $aUpdts) {
	$sInfo = (dism /online /get-packageinfo /packagename:$sUpdate) -join(", ")
	if ($sInfo.Contains($sKBNumber)) {
		write-host "Found package $sUpdate for KB number $sKBNumber"
		# uncomment below to uninstall package
		# DISM.exe /Online /Remove-Package /PackageName:$sUpdate /quiet /norestart
	}
}

КЭНК! Слава роботам!

 108   2021   PowerShell   WSUS   КЭНК

КЭНК: сортируем и фильтруем каналы IPTV

Решил подарить маме на новый год IPTV от широко известного в узких кругах провайдера. Этот сервис за небольшую плату предоставляет плейлисты с каналами, и главная суть услуги — то что списки каналов обновляются, протухшие источники заменяются новыми, клиент не бегает по интернетам в поисках собранных энтузизястами плейлистов сомнительного качества, и не остаётся вдруг без любимого НТВ под ёлочкой.

Главный недостаток сервиса в том, что встроенная система управления каналами примитивна: можно только включать или исключать каналы целыми категорями, по тематикам или по странам. Нет возможности задания порядка каналов, нет возможности индивидуальной фильтрации. Но так как мама — человек старой закалки, ей во-первых нужно чтобы каналы были По Порядку, усвоенному со времен телевизора Темп, а во-вторых, этого вашего супер-изобилия ей не надо, а моя тайная мечта тут — пересадить её с ток-шоу на видео природы.

Телевизор Темп. Ровно такая же модель стала причиной больших перемен в семье моих родителей в начале 1980-х

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

По итогу размышлений принимаю решение реализовать компромиссный вариант. По мере протухания каналов и жалоб клиента, буду скачивать и обновлять плейлист, фильровать и обновлять в настройках плеера. Но максимально всё это автоматизирую. На выходе — плейлист с центральными каналами в HD качестве и правильном порядке (Первый, Россия и тому подобное), дополненный избранными каналами про природу, путешествия, и хорошее кино. Под рукой винда — значит фигачим на павершелле.

Первая итерация — скрипт, умеющий взять плейлист, и отфильтровать и отсортировать его по заданному правилу (простой json файл). В дальнейшем, если потребуется, можно прикрутить в него скачивание провайдерского плейлиста (тривиально) и закачивание в плеер (тут будет непросто разобраться в формате HTTP запроса). Но пока так. Быстро, зло, бесплатно, работает.

Страница на гитхабе https://github.com/alexbatishchev/kenk-iptv-playlister

КЭНК!
Слава роботам!

 37   2020   PowerShell   КЭНК

КЭНК: контролируем сроки действия сертификатов

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

Итак, проблема: в некоей системе используются сертификаты пользователей. Система (и её клиентская часть) сама по себе никаких средств контроля и мониторинга сертификатов не содержит, и задача контроля срока и необходимости заблаговременного заказа, организации установки сертификатов на устройства полностью лежит на группе поддержки. Необходимо максимально исключить человеческий фактор и заставить трудиться роботов на ниве контроля сроков.

Решение. Выгружать или как-то ещё получать доступ к сертификатам в работе система не даёт, но мы можем договориться с группой поддержки, что они будут хранить сертификаты в отдельной папке с ограниченным доступом, и работать с ней при любом обслуживании клиентов — убирать оттуда ушедшие из работы сертификаты, класть вновь выпущенные и использованные в настройке. После этого остальное дело техники — по расписанию дампим сертификаты, находим в них данные о сроке окончания, начинаем присылать предупредительные письма группе поддержки заранее. Тут кстати родилась универсальная формула, позволяющая не попасть на праздники и прочие выходные  — предупреждения высылаются за 14, 5, и 3 дня до истечения срока действия сертификата.

Главный технический ингредиент — договориться с certutil, которая в разных версиях по разному выдает дампы.
В моем конкретном случае просто парсится дата окончания через

$data = certutil -dump $file | select-string -pattern "NotAfter:"

В итоге, письма рассылаются, сроки не продалбываются, клиенты довольны, человеки не держат в голове лишней информации

Пример уведомления о скором сроке окончания действия сертификата

КЭНК!
Слава Роботам!

 53   2020   PowerShell   Windows Server   КЭНК
Ранее Ctrl + ↓