{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Лайвлупинг, медиапродакшн и все эти ваши компьютеры: заметки с тегом PowerShell",
    "_rss_description": "Алексей Батищев. Заметки обо всём, что происходит со мной и окружающим миром",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": "",
    "_itunes_explicit": "",
    "home_page_url": "https:\/\/batishchev.ru\/blog\/tags\/powershell\/",
    "feed_url": "https:\/\/batishchev.ru\/blog\/tags\/powershell\/json\/",
    "icon": "https:\/\/batishchev.ru\/blog\/pictures\/userpic\/userpic@2x.jpg?1604346823",
    "authors": [
        {
            "name": "Алексей Батищев",
            "url": "https:\/\/batishchev.ru\/blog\/",
            "avatar": "https:\/\/batishchev.ru\/blog\/pictures\/userpic\/userpic@2x.jpg?1604346823"
        }
    ],
    "items": [
        {
            "id": "3821",
            "url": "https:\/\/batishchev.ru\/blog\/all\/kirillicheskiy-rezident-peredayot-iz-klodlyandii\/",
            "title": "Кириллический резидент передаёт из Клодляндии",
            "content_html": "<p>Как уже в курсе любимый читатель, мы живем в эпоху искусственного интеллекта и агентской разработки. ИИшечки пишут код, код работает, все счастливы. Но есть одна проблема — всё около-иишное как правило живёт и мыслится в окружении macOS\/Linux и в контексте в первую очередь питона. А что делать, если ты хочешь использовать иишку для разработки на павершелле и использовать Клода в среде Виндоуз? Ответ по умолчанию — страдать.<\/p>\n<p>Чтобы не было проблем с кириллицей, скрипты нужно хранить в UTF-16 LE с BOM — так их одинаково однозначно опознают что PowerShell 5.1, что pwsh 7+, что тестовые редакторы под Windows, что git\/gitlab, и все живут дружно. А вот Claude Code с его встроенными инструментами `Edit` и `Write` живёт только в своей реальности UTF-8 и плевать хотел, в какой кодировке был файл. А поэтому и читать-редактировать старые наработки по умолчанию не может, и новое пишет сломанное.<\/p>\n<p>Проблема <a href=\"https:\/\/github.com\/anthropics\/claude-code\/issues\/7134\">старая<\/a> и <a href=\"https:\/\/github.com\/anthropics\/claude-code\/issues\/28316\">известная<\/a>, но как ’это часто бывает с корнер кейсами, проблемы индейцев шерифа не волнуют — ни фикса, ни какой-либо настройки для клода не существует и, скорее всего, <a href=\"https:\/\/github.com\/anthropics\/claude-code\/issues\/62862\">не предвидится<\/a>. ИЧСХ, проблема тут не только кириллическая, у японцев например ровно та же беда, только с Shift_JIS вместо UTF-16. Но кому какое дело до этих ваших туземных особенностей?<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/2026-07-11-2.png\" width=\"1342.2818791946\" height=\"800\" alt=\"\" \/>\n<div class=\"e2-text-caption\">карта мира по мнению программистов (гипотеза)<\/div>\n<\/div>\n<p>Сразу как только я наступил на эти грабли, родился обходной маневр: инструкцией в CLAUDE.md агенту было сказано для редактирования PowerShell скриптов делать построчную замену вызовом того же PowerShell. И это в целом работало, но сильно замедляло (и часто ломало) процесс — решение было кустарным, хрупким, и разрешение спрашивалось на каждый чих. Агент регулярно забывал инструкции, а чтобы вспомнить сначала бегло бежал по садовому инвентарю, отнимая моё время, нервные клетки, и тратя драгоценные токены.<\/p>\n<p>Сегодня, устав от очередной порчи скрипта при небольшом изменении, я отправил агента в рисёрч с требованием раз и навсегда решить проблему в корне. Клод обнаружил в интернетах братьев-японцев и других потерпевших, но главное — придумал использовать хуки, которые прозрачно конвертируют файл туда-обратно при редактировании встроенными инструментами. Я затестил и это работает. Щас расскажу.<\/p>\n<h2>Доктор Крюк, или как я перестал страдать и полюбил хуки<\/h2>\n<p>У Claude Code есть `PreToolUse`\/`PostToolUse`\/`Stop` hooks — команды, которые выполняются автоматически вокруг вызовов инструментов. Идея простая: пусть файл на диске «в покое» всегда лежит в UTF-16 LE, а хуки на лету превращают его в UTF-8 непосредственно перед тем, как его коснётся Read\/Edit\/Write, и обратно — сразу после. Модель вообще не должна догадываться, что файл когда-то был не в UTF-8.<\/p>\n<p>Настройки хуков в  ~\/.claude\/settings.json:<\/p>\n<pre class=\"e2-text-code\"><code class=\"json\">&quot;hooks&quot;: {\n  &quot;PreToolUse&quot;: [\n    {\n      &quot;matcher&quot;: &quot;Read|Edit&quot;,\n      &quot;hooks&quot;: [{\n        &quot;type&quot;: &quot;command&quot;,\n        &quot;command&quot;: &quot;C:\\\\Program Files\\\\PowerShell\\\\7\\\\pwsh.exe&quot;,\n        &quot;args&quot;: [&quot;-NoProfile&quot;, &quot;-File&quot;, &quot;C:\\\\Users\\\\[USER]\\\\.claude\\\\hooks\\\\ps1-pre-encoding.ps1&quot;]\n      }]\n    }\n  ],\n  &quot;PostToolUse&quot;: [\n    {\n      &quot;matcher&quot;: &quot;Edit|Write&quot;,\n      &quot;hooks&quot;: [{\n        &quot;type&quot;: &quot;command&quot;,\n        &quot;command&quot;: &quot;C:\\\\Program Files\\\\PowerShell\\\\7\\\\pwsh.exe&quot;,\n        &quot;args&quot;: [&quot;-NoProfile&quot;, &quot;-File&quot;, &quot;C:\\\\Users\\\\[USER]\\\\.claude\\\\hooks\\\\ps1-post-encoding.ps1&quot;]\n      }]\n    }\n  ],\n  &quot;Stop&quot;: [\n    {\n      &quot;hooks&quot;: [{\n        &quot;type&quot;: &quot;command&quot;,\n        &quot;command&quot;: &quot;C:\\\\Program Files\\\\PowerShell\\\\7\\\\pwsh.exe&quot;,\n        &quot;args&quot;: [&quot;-NoProfile&quot;, &quot;-File&quot;, &quot;C:\\\\Users\\\\[USER]\\\\.claude\\\\hooks\\\\ps1-restore-all.ps1&quot;]\n      }]\n    }\n  ]\n}<\/code><\/pre><p>pre-encoding.ps1 (перед Read\/Edit — если увидел BOM UTF-16 LE, конвертирует в UTF-8 и запоминает путь):<\/p>\n<pre class=\"e2-text-code\"><code class=\"powershell\">$ErrorActionPreference = 'Stop'\n$stateFile = &quot;C:\\Users\\[USER]\\.claude\\hooks\\ps1-utf16-state.json&quot;\n$scopeRoot = &quot;[ВАШ ПУТЬ]&quot;\n\ntry {\n    $inputJson = [Console]::In.ReadToEnd()\n    $data = $inputJson | ConvertFrom-Json\n    $filePath = $data.tool_input.file_path\n\n    if (-not $filePath) { exit 0 }\n    if ($filePath -notmatch '\\.ps1$') { exit 0 }\n    if (-not $filePath.StartsWith($scopeRoot, [System.StringComparison]::OrdinalIgnoreCase)) { exit 0 }\n    if (-not (Test-Path -LiteralPath $filePath -PathType Leaf)) { exit 0 }\n\n    $bytes = [System.IO.File]::ReadAllBytes($filePath)\n    if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) {\n        $content = [System.IO.File]::ReadAllText($filePath, [System.Text.Encoding]::Unicode)\n        [System.IO.File]::WriteAllText($filePath, $content, (New-Object System.Text.UTF8Encoding($false)))\n\n        $state = @()\n        if (Test-Path -LiteralPath $stateFile) {\n            $raw = Get-Content -LiteralPath $stateFile -Raw -ErrorAction SilentlyContinue\n            if ($raw) { $state = @($raw | ConvertFrom-Json) }\n        }\n        if ($state -notcontains $filePath) { $state += $filePath }\n        ($state | ConvertTo-Json) | Set-Content -LiteralPath $stateFile -Encoding utf8\n    }\n} catch {\n    exit 0\n}\nexit 0<\/code><\/pre><p>post-encoding.ps1 (после Edit\/Write — конвертирует обратно в UTF-16 LE, но только файлы из стейта):<\/p>\n<pre class=\"e2-text-code\"><code class=\"powershell\">$ErrorActionPreference = 'Stop'\n$stateFile = &quot;C:\\Users\\[USER]\\.claude\\hooks\\ps1-utf16-state.json&quot;\n\ntry {\n    $inputJson = [Console]::In.ReadToEnd()\n    $data = $inputJson | ConvertFrom-Json\n    $filePath = $data.tool_input.file_path\n\n    if (-not $filePath) { exit 0 }\n    if ($filePath -notmatch '\\.ps1$') { exit 0 }\n    if (-not (Test-Path -LiteralPath $stateFile)) { exit 0 }\n\n    $raw = Get-Content -LiteralPath $stateFile -Raw -ErrorAction SilentlyContinue\n    if (-not $raw) { exit 0 }\n    $state = @($raw | ConvertFrom-Json)\n    if ($state -notcontains $filePath) { exit 0 }\n    if (-not (Test-Path -LiteralPath $filePath -PathType Leaf)) { exit 0 }\n\n    $content = [System.IO.File]::ReadAllText($filePath, [System.Text.Encoding]::UTF8)\n    [System.IO.File]::WriteAllText($filePath, $content, [System.Text.Encoding]::Unicode)\n\n    $state = @($state | Where-Object { $_ -ne $filePath })\n    ($state | ConvertTo-Json) | Set-Content -LiteralPath $stateFile -Encoding utf8\n} catch {\n    exit 0\n}\nexit 0<\/code><\/pre><p>restore-all.ps1 (Stop-хук — подчищает в конце хода всё, что осталось не восстановленным после одиночного Read без последующего Edit):<\/p>\n<pre class=\"e2-text-code\"><code class=\"powershell\">$ErrorActionPreference = 'Stop'\n$stateFile = &quot;C:\\Users\\[USER]\\.claude\\hooks\\ps1-utf16-state.json&quot;\n\ntry {\n    [Console]::In.ReadToEnd() | Out-Null\n\n    if (-not (Test-Path -LiteralPath $stateFile)) { exit 0 }\n    $raw = Get-Content -LiteralPath $stateFile -Raw -ErrorAction SilentlyContinue\n    if (-not $raw) { exit 0 }\n    $state = @($raw | ConvertFrom-Json)\n\n    foreach ($filePath in $state) {\n        if (-not (Test-Path -LiteralPath $filePath -PathType Leaf)) { continue }\n        $bytes = [System.IO.File]::ReadAllBytes($filePath)\n        $isUtf16Le = $bytes.Length -ge 2 -and $bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE\n        if (-not $isUtf16Le) {\n            $content = [System.IO.File]::ReadAllText($filePath, [System.Text.Encoding]::UTF8)\n            [System.IO.File]::WriteAllText($filePath, $content, [System.Text.Encoding]::Unicode)\n        }\n    }\n\n    Set-Content -LiteralPath $stateFile -Value &quot;[]&quot; -Encoding utf8\n} catch {\n    exit 0\n}\nexit 0<\/code><\/pre><p>Собственно, делать эти настройки руками не нужно — просто скопипастите текст заметки в чат своему Клоду и попросите настроить так же.<\/p>\n<h2>Доклад окончен<\/h2>\n<p>Скрипты на диске и в git теперь всегда лежат в UTF-16 LE с BOM — ровно так, как его и ждёт PowerShell. Пока файла касается Claude Code — он на долю секунды «мигает» в UTF-8 и обратно, а модель работает через свои обычные беззаботные Edit\/Write. Роботы работают, человек не напрягается.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/2026-07-11-image-9.png\" width=\"1000\" height=\"798\" alt=\"\" \/>\n<\/div>\n<p>Важная тонкость — в скрипты зашита проверка на них самих, чтобы создавая-редактируя их Клод не попадал в бесконечную кодировочную петлю.<\/p>\n<p>Пойду, завайбкожу ещё что-нибудь.<\/p>\n<p>Слава роботам! КЭНК!<\/p>\n",
            "summary": "Как уже в курсе любимый читатель, мы живем в эпоху искусственного интеллекта и агентской разработки. ИИшечки пишут код, код работает, все счастливы",
            "date_published": "2026-07-12T20:42:19+03:00",
            "date_modified": "2026-07-12T20:36:13+03:00",
            "tags": [
                "PowerShell",
                "TG",
                "ИИ",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/2026-07-11.png",
            "_date_published_rfc2822": "Sun, 12 Jul 2026 20:42:19 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "3821",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/2026-07-11.png",
                    "https:\/\/batishchev.ru\/blog\/pictures\/2026-07-11-1.png",
                    "https:\/\/batishchev.ru\/blog\/pictures\/2026-07-11-2.png",
                    "https:\/\/batishchev.ru\/blog\/pictures\/2026-07-11-image-9.png"
                ]
            }
        },
        {
            "id": "3793",
            "url": "https:\/\/batishchev.ru\/blog\/all\/novy-reliz-vkachatora\/",
            "title": "Новый релиз ВКачатора",
            "content_html": "<p>Спустя <a href=\"https:\/\/batishchev.ru\/blog\/all\/zabrat-svoyo-iz-oblakov-obnovlenie-vkachatora\/\">три года<\/a> подготовил и выпустил новый релиз ВКачатора — допилил много мелочей, до которых в прошлый раз не доходили руки, благо теперь Клод позволяет реализовывать идеи быстро и технологично. ЧуднО видеть код, на который я в своё время потратил уйму времени, и то как играючи его сейчас колбасит ИИшка<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/2026-05-18-image-8.png\" width=\"914.75142624287\" height=\"800\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Приятные мелочи — аватары отправителей и бейджик «processed» на обработанных страницах<\/div>\n<\/div>\n<p>Формат выгрузки за прошедшие годы не поменялся, а вот содержимое профиля заметно поредело: уж не знаю с чем связано, может самизнаетечто повлияло, но много видосов и фоток теперь удалены или скрыты авторами. Ну, такие времена.<\/p>\n<p>При разработке в паре с Клодом пришлось преодолеть новые технологические сложности — оказалось что питоново-юниксовые по происхождению нейросети нативно плохо могут в редактирование powershell-скриптов с кириллицей под виндой. Но в итоге решение придумалось, и работа по впиливанию фич заняла пару вечеров ленивой фоновой постановки задач и контроля результатов. В основном время потратилось на скачивание медиа, ну заодно и свой дамп обновил на актуальный.<\/p>\n<p>Публичную репу решил пересоздать, но адрес оставил прежний: <a href=\"https:\/\/github.com\/alexbatishchev\/kenk-vk-enricher\">https:\/\/github.com\/alexbatishchev\/kenk-vk-enricher<\/a><\/p>\n<p>КЭНК! Слава роботам!<\/p>\n",
            "summary": "Спустя три года подготовил и выпустил новый релиз ВКачатора — допилил много мелочей, до которых в прошлый раз не доходили руки, благо теперь Клод позволяет реализовывать идеи быстро и технологично",
            "date_published": "2026-05-22T20:03:01+03:00",
            "date_modified": "2026-05-22T20:02:55+03:00",
            "tags": [
                "PowerShell",
                "TG",
                "ВКачатор",
                "Забрать своё из облаков",
                "ИИ",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/2026-05-18-image-8.png",
            "_date_published_rfc2822": "Fri, 22 May 2026 20:03:01 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "3793",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/2026-05-18-image-8.png"
                ]
            }
        },
        {
            "id": "1104",
            "url": "https:\/\/batishchev.ru\/blog\/all\/exchangedocsaver-esche-odna-istoriya-pro-lyudey-i-robotov\/",
            "title": "ExchangeDocSaver: еще одна история про людей и роботов",
            "content_html": "<p>Несколько лет назад, за кружкой крепкого чая у мангала, мой старинный друг пожаловался на одну из обязанностей на работе: при общении с контрагентами по электронной почте у них возникают артефакты этого общения — счета и прочие документы — которые нужно из почтовых сообщений сохранять на сетевой диск. Причем в компании исторически сложился процесс документооборота, когда эти файлы должны попасть в свое место в иерархии сетевого диска, где за них уже неистово хватаются другие отделы, а иерархия эта не самая простая (хотя будущее место документа определяется по номеру контракта однозначно, по схеме «ну это все знают»).<\/p>\n<p>В общем, выступает мой друг таким вот высокоинтеллектуальным сортировщиком и раскладывальщиком файликов, в фоне во время других (гораздо более сложных и изящных) задач по заключению договоров, преодолению препонов и прочих зарабатываний мильёнов. Ну натурально вот: придумал как привезти из стран заморских жирафа по частям, и чтобы по документам это была канарейка (задача безусловно творческая), а потом не забывай в течение пары месяцев доки по этому проекту из последующей переписки «правой кнопкой мыши — сохранить как — найти папку — блин где же она — а вот — сохранить»<\/p>\n<p>А что — говорю ему я, потягивая чай у мангала — задачка-то похоже автоматизируется. Можно научить роботов пырить в почтовый ящик по Exchange Web Services (EWS) Managed API, находить непрочитанные письма, понимать какие из них содержат нужные документы (а какие — нет), а также к какому контракту они относятся, ну а по номеру контракта и место на сетевом диске найти можно. Контракт конечно может быть в письме и вложениях непонятно где упомянут, но раз человек справляется с поиском — то и робота настропалить на это дело сможем.<\/p>\n<p>Естественно, согласно всем заветам планирования процессов разработки, реализация алгоритма заняла в три раза больше времени, чем задумывалось. Естественно, так как исходные письма посылают человеки, ошибающиеся и ненадёжные, и не все 100% сообщений оформляются как надо, часть писем (довольно малая) алгоритмом пропускается. Но в целом, за несколько дней рьяного <a href=\"https:\/\/batishchev.ru\/blog\/tags\/kenk\/\">кэнк-программинга<\/a> с использованием наработанных ранее библиотек и с применением худших регулярок ever, был выпущен в прод робот, который начал 24 на 7 делать работу за человека. Робот, который не устаёт, не болеет и не обедает, который днём и ночью мгновенно реагирует на письма от контрагентов изо всех часовых поясов, который всегда кладёт файлы туда, куда надо, и позволяет человеку сфокусироваться на действительно сложных вещах.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/exchangedocsaver-esche-odna-istoriya-pro-lyudey-i-robotov.png\" width=\"526\" height=\"242\" alt=\"\" \/>\n<\/div>\n<p>На днях, после полутора лет успешной эксплуатации, комплекс впервые потребовал доработки из-за смены формата номера контракта на предприятии. Я дополнил алгоритм детектирования ID контракта новым шаблоном, попутно поправил пару замеченных косяков (и чуть выиграл в производительности), выкатил обновление — и клиент снова доволен, надеюсь что на следующие Х лет.<\/p>\n<p>Детали реализации, код, ФИО счастливчика и название компании — под NDA, по очевидным причинам. Могу лишь сказать что при внимании к деталям и некотором опыте автоматизации под винду и Exchange, можно в таком направлении реализовать практически что угодно. Если вы ежедневно тратите время на работу с почтой, не решаемую обычным функционалом правил и другой автоматизации в почтовом клиенте — возможно, пришла пора переложить это на наших электрических братьев. Как-нибудь расскажу потом про конфеденциальную пересылку алертов из почты в телегу, тоже полезная штука.<\/p>\n<p>Кожаные заняты делом, кремнивые — рутиной. Обожаю такое.<\/p>\n<p>КЭНК! Слава роботам!<\/p>\n",
            "summary": "Несколько лет назад, за кружкой крепкого чая у мангала, мой старинный друг пожаловался на одну из обязанностей на работе",
            "date_published": "2024-12-05T12:27:42+03:00",
            "date_modified": "2024-12-09T13:17:05+03:00",
            "tags": [
                "EWS",
                "PowerShell",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/exchangedocsaver-esche-odna-istoriya-pro-lyudey-i-robotov.png",
            "_date_published_rfc2822": "Thu, 05 Dec 2024 12:27:42 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "1104",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/exchangedocsaver-esche-odna-istoriya-pro-lyudey-i-robotov.png"
                ]
            }
        },
        {
            "id": "1083",
            "url": "https:\/\/batishchev.ru\/blog\/all\/zapusk-processov-kaspersky-network-agent-v-64-bit-okruzhenii\/",
            "title": "Запуск процессов через Kaspersky Network Agent в 64-bit окружении",
            "content_html": "<p>Через задачу типа «Удалённая установка программы» на windows-клиентах, покрытых Kaspersky Network Agent, удобно запускать инсталляторы или скрипты, выполняющие на хосте необходимые администратору настройки. Тут можно решать множество проблем — от умной деинсталляции или переустановки софта, до настройки параметров ОС и приложений.<\/p>\n<p>Однако, здесь кроется одна засада — агент работает от имени SYSTEM, но запускает нагрузку в 32-битном окружении. В плане powershell из-за этого могут быть недоступны часть ресурсов ОС типа веток реестра и всплывать прочие нюансы.<\/p>\n<p>К счастью, великий стаковерфлоу уже больше 10 лет хранит в себе рецепт на этот случай. Он часто пригождается, поэтому положу его и сюда. Просто добавьте <s>простой советский<\/s> блок кода в начало вашего скрипта, и он будет автоматически перезапущен со всеми параметрами в 64-битном окружении.<\/p>\n<pre class=\"e2-text-code\"><code class=\"powershell\">\n#############################################################################\n#If Powershell is running the 32-bit version on a 64-bit machine, we \n#need to force powershell to run in 64-bit mode .\n#############################################################################\nif ($env:PROCESSOR_ARCHITEW6432 -eq \"AMD64\") {\n    if ($myInvocation.Line) {\n        &\"$env:WINDIR\\sysnative\\windowspowershell\\v1.0\\powershell.exe\" -NonInteractive -NoProfile $myInvocation.Line\n    }else{\n        &\"$env:WINDIR\\sysnative\\windowspowershell\\v1.0\\powershell.exe\" -NonInteractive -NoProfile -file \"$($myInvocation.InvocationName)\" $args\n    }\nexit $lastexitcode\n}\n\nwrite-host \"Main script body\"\n\n#############################################################################\n#End\n#############################################################################\n<\/code>\n<\/pre>\n<h2>Ссылочки на исходники<\/h2>\n<ul>\n<li><a href=\"https:\/\/stackoverflow.com\/questions\/19055924\/how-to-launch-64-bit-powershell-from-32-bit-cmd-exe\">https:\/\/stackoverflow.com\/questions\/19055924\/how-to-launch-64-bit-powershell-from-32-bit-cmd-exe<\/a><\/li>\n<li><a href=\"http:\/\/cosmonautdreams.com\/2013\/09\/03\/Getting-Powershell-to-run-in-64-bit.html\">http:\/\/cosmonautdreams.com\/2013\/09\/03\/Getting-Powershell-to-run-in-64-bit.html<\/a><\/li>\n<\/ul>\n",
            "summary": "Через задачу типа «Удалённая установка программы» на windows-клиентах, покрытых Kaspersky Network Agent, удобно запускать инсталляторы или скрипты, выполняющие на хосте необходимые администратору настройки",
            "date_published": "2024-10-02T15:19:08+03:00",
            "date_modified": "2024-11-25T20:13:00+03:00",
            "tags": [
                "PowerShell",
                "безопационная информасность",
                "все эти ваши компьютеры"
            ],
            "_date_published_rfc2822": "Wed, 02 Oct 2024 15:19:08 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "1083",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "1049",
            "url": "https:\/\/batishchev.ru\/blog\/all\/otklyuchaem-perezagruzku-windows-pri-obnovleniyah\/",
            "title": "Отключаем перезагрузку Windows при обновлениях",
            "content_html": "<p>В прошлый раз я рассказывал, как <a href=\"https:\/\/batishchev.ru\/blog\/saga-o-perezagruzkah-ili-smekalka-protiv-vlasti-korporaciy\/\">победил самопроизвольную перезагрузку винды<\/a> в производственной среде. Но дома проблема так же актуальна — бесит когда смотришь с утра, что посчиталось в монтажке с новым концертом любимой группы, например, а на тебя в ответ смотрит свежеперезагруженный комп.<\/p>\n<p>Итак, kenk-shift-active-hours или Бесконечный откладыватель авто-перезагрузки Windows при обновлениях<\/p>\n<ul>\n<li>скрипт задаёт в качестве начала активных часов текущий час, а в качестве конца — время на 18 часов позже (это максимальная возможная длительность)<\/li>\n<li>в комплекте идёт инсталлер, который копирует скрипт в профиль пользователя и создает задачу в планировщике, стартующую скрипт автоматически каждые полчаса<\/li>\n<li>в итоге, система корректно сама ходит за апдейтами и устанавливает их, а также сигнализирует о необходимости перезагрузки для завершения обновления, но никогда не перезагружается сама<\/li>\n<\/ul>\n<p>Отмечу отдельно что для домашнего использования такое (потенциально) бесконечное откладывание ребута приемлемо, я достаточно ответственен чтобы в короткий (но удобный мне) срок перезагрузить тачку.<\/p>\n<p>Скрипт на гитхабе: <a href=\"https:\/\/github.com\/alexbatishchev\/kenk-shift-active-hours\">https:\/\/github.com\/alexbatishchev\/kenk-shift-active-hours<\/a><\/p>\n<p>КЭНК!<br \/>\nСлава роботам!<\/p>\n",
            "summary": "В прошлый раз я рассказывал, как победил самопроизвольную перезагрузку винды в производственной среде",
            "date_published": "2024-06-26T16:29:18+03:00",
            "date_modified": "2024-06-26T16:29:16+03:00",
            "tags": [
                "PowerShell",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "_date_published_rfc2822": "Wed, 26 Jun 2024 16:29:18 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "1049",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "1046",
            "url": "https:\/\/batishchev.ru\/blog\/all\/saga-o-perezagruzkah-ili-smekalka-protiv-vlasti-korporaciy\/",
            "title": "Сага о перезагрузках, или смекалка против власти корпораций",
            "content_html": "<p>Сегодняшний рассказ — на мои любимые темы: как заставить роботов работать за людей, и как победить неумолимые корпорации с помощью их же инструментов. А ещё это реальный эксклюзив и ноу-хау, до которого (кажется) ещё никто не задумывался. Устраивайтесь поудобнее.<\/p>\n<p>Предыстория такова: первой большой задачей на нынешнем проекте у меня было внедрить процесс обновления операционок на рабочих местах. Главная проблема тут в <a href=\"https:\/\/bureau.ru\/bb\/soviet\/20150505\/\">бесценности пользовательских данных<\/a> и в том, как в борьбе за безопасность Microsoft перешла грань. Начиная с какого-то момента, штатными средствами и политиками Windows стало невозможно обеспечить обязательную, но бережную установку обновлений системы для клиентских ОС. Да, появились более наглядные нотификации, возможность задавать дедлайны, но в итоге, все варианты сводились к двум сценариям — либо апдейты не будут гарантированно установлены, либо автообновление будет работать, но комп может быть перезагружен в вообще говоря неудобное клиенту время. Самый отстой тут — перезагрузки по ночам или в другие моменты, когда комп что-то делает без активного участия человека — тут администраторы, программисты и прочие рендерщики видео по три часа в фоне начинают беситься, вспоминая потерянное на таких ребутах время и данные.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/wufb-update-deadline-warning.png\" width=\"345\" height=\"144\" alt=\"\" \/>\n<\/div>\n<p>Собственно, рабочую задачу я решил через отключение всех автоматических политик Microsoft и реализации собственного решения — агента, который работает на хостах, по удобному предприятию и сотрудникам расписанию ставит обновления, назначает и следит за сроками установки, адекватно напоминает о необходимости перезагрузки и вообще решает задачу бережно и результативно. Ключевая фишка — умные дедлайны, когда на установку обновлений пользователю отводится некоторое количество рабочих дней, а принудительная перезагрузка (если до неё дойдёт) не происходит пока пользователя нет у компа, и он не может сохранить свои данные. Ну а попутно появился инструмент инвентаризации и управления клиенсткими машинами. Когда-нибудь расскажу об этом отдельно, кодовое имя проекта «Светофор».<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/2024-06-14-3.png\" width=\"364\" height=\"599\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Уведомление, которым Светофор достаёт даже самого упорного пользователя<\/div>\n<\/div>\n<p>Однако, с Windows 11 оставалась одна загвоздка — штатными средствами полностью запретить винде перезагружаться по собственному желанию, при включенной авто-установке апдейтов, не получилось. Были найдены и протестированы совсем уж некрасивые варианты типа модификации системных файлов и запрета самой винде их менять на уровне файловых прав, но это было грязно и неудобно для внедрения. До поры таких клиентов было немного, ситуация позволяла терпеть, однако недавно я сам перешёл на Windows 11, миграция в компании тоже стартовала, и проблема начала разрастаться.<\/p>\n<p>Я провёл очередной рисёрч на тему (оказалось что ничего за годы не изменилось), после чего сделал ещё один заход на проблему в КЭНК-парадигме, и тут в ночи перезагрузочного кошмара забрезжил-таки рассвет.<\/p>\n<p>Следим за руками: винда штатно смотрит на заданный в настройках Период Активности (Active Hours), и не ребутает компы во время него. Так отчего бы нам автоматически не сдвигать его постоянно так, чтобы период активности не заканчивался никогда?<\/p>\n<p>Быстрая проверка показала что соответствующие параметры хранятся в реестре и доступны на запись непривилегированным пользователям, и что система реально их регулярно перечитывает. А если параметры сдвигать вперёд постоянно, то неуправляемого саморебута после установки обновлений не случается совсем.<\/p>\n<div class=\"e2-text-picture\">\n<div class=\"fotorama\" data-width=\"1655\" data-ratio=\"2.4701492537313\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/2024-06-14-1.png\" width=\"1655\" height=\"670\" alt=\"\" \/>\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/2024-06-14-2.png\" width=\"1655\" height=\"670\" alt=\"\" \/>\n<\/div>\n<div class=\"e2-text-caption\">вот они красавчики в реестре и в гуе<\/div>\n<\/div>\n<p>Дальше — дело техники, добавил в Светофор небольшой модуль, он сдвигает Active Hours на компах пользователей, а перезагрузкой управляет сам.<\/p>\n<p>Компьютеры работают, человек кайфует, корпорации щёлкнуты по носу, ситуация под нашим контролем!<\/p>\n<p>А вот о том, как это может быть полезно простым домашним юзерам — расскажу в следующий раз.<\/p>\n<p>КЭНК!<br \/>\nСлава роботам!<\/p>\n",
            "summary": "Сегодняшний рассказ — на мои любимые темы: как заставить роботов работать за людей, и как победить неумолимые корпорации с помощью их же инструментов",
            "date_published": "2024-06-18T00:21:45+03:00",
            "date_modified": "2025-10-15T00:12:30+03:00",
            "tags": [
                "PowerShell",
                "безопационная информасность",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/wufb-update-deadline-warning.png",
            "_date_published_rfc2822": "Tue, 18 Jun 2024 00:21:45 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "1046",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "jquery\/jquery.js",
                    "fotorama\/fotorama.css",
                    "fotorama\/fotorama.js"
                ],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/wufb-update-deadline-warning.png",
                    "https:\/\/batishchev.ru\/blog\/pictures\/2024-06-14-3.png",
                    "https:\/\/batishchev.ru\/blog\/pictures\/2024-06-14-1.png",
                    "https:\/\/batishchev.ru\/blog\/pictures\/2024-06-14-2.png"
                ]
            }
        },
        {
            "id": "1044",
            "url": "https:\/\/batishchev.ru\/blog\/all\/robot-lesnik-i-yolka\/",
            "title": "Робот-лесник и ёлка",
            "content_html": "<p>Сегодня расскажу про суровое, простое и полезное как топор в лесу кэнк-поделие, на разработку и запуск которого в пром ушло меньше часа времени.<\/p>\n<p>Вот ELK-стек, в который собираются некоторые данные. Конечно, мы следим за хостами фермы через мониторинг. Но хотелось бы и смотреть и за состоянием самого сервиса, и — главное — вовремя узнавать если что-то пошло не так.<\/p>\n<p>Выбираем сервак для размещения робота-лесника (в моём случае под виндой ибо фигачим быстро и грязно на павершеле). Пишем скрипт, в котором:<\/p>\n<ul>\n<li>читаем список FQDN нод нашей ёлки из конфига скрипта<\/li>\n<li>проходим по списку, проверяя доступность хостов по сети (через Test-NetConnection -port 9200). Если какая-то нода не пингуется или не отвечает по 9200 — алертим админу<\/li>\n<li>если есть хоть одна живая нода — запрашиваем у неё статус через API «<a href=\"https:\/\/cluster.com\/_cluster\/health?pretty\">https:\/\/cluster.com\/_cluster\/health?pretty<\/a>». В полученном json пырим в «status», если он не «green» — запрашиваем более подробную диагностику через «<a href=\"https:\/\/cluster.com\/_nodes\/process?pretty\">https:\/\/cluster.com\/_nodes\/process?pretty<\/a>» и тоже всё алертим админу.<\/li>\n<\/ul>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/2024-06-10-health.png\" width=\"862\" height=\"301\" alt=\"\" \/>\n<div class=\"e2-text-caption\">типовой результат запроса health<\/div>\n<\/div>\n<ul>\n<li>куда алертим? Ну лично мне удобней получать такое в почту и в специальный аварийный чят в телеге.<\/li>\n<li>повторяем проверку (дёргаем скрипт планировщиком на сервере с нужной периодичностью)<\/li>\n<\/ul>\n<p>Итого, при проблемах с сервисом имеем своевременные оповещения, машины трудятся а человеки отдыхают.<\/p>\n<p>Думал оформить свой скриптец в виде готового продукта, но в целом тула вышла специфичная под мои требования и легко воспроизводимая в нужном виде под требования чужие, так что ограничусь общим алгоритмом и описанием идеи.<\/p>\n<p>КЭНК!<br \/>\nСлава роботам!<\/p>\n",
            "summary": "Сегодня расскажу про суровое, простое и полезное как топор в лесу кэнк-поделие, на разработку и запуск которого в пром ушло меньше часа времени",
            "date_published": "2024-06-11T21:25:10+03:00",
            "date_modified": "2024-10-02T15:27:10+03:00",
            "tags": [
                "PowerShell",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/image-1.png",
            "_date_published_rfc2822": "Tue, 11 Jun 2024 21:25:10 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "1044",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/image-1.png",
                    "https:\/\/batishchev.ru\/blog\/pictures\/2024-06-10-health.png"
                ]
            }
        },
        {
            "id": "1008",
            "url": "https:\/\/batishchev.ru\/blog\/all\/kenk-obnovlenie-generatora-fonov-dlya-rabochego-stola\/",
            "title": "КЭНК: обновление генератора фонов для рабочего стола",
            "content_html": "<p>В последнее время всё чаще сталкиваюсь с необходимостью использовать в powershell вызовы системного API для реализации функционала, под который нет готовых командлетов. Разбираясь с решением очередной проблемы этим методом, вспомнил про <a href=\"\/blog\/all\/generator-kartinok-dlya-fona-rabochego-stola-serverov\/\">генератор фонов для RDP<\/a>, который я когда-то пилил, и в котором до идеала не хватало авто-назначения сгенерённого фона, потому что такой функции я тогда не нашел. Ну думаю, через системное API уж точно кто-то сообразил как сделать — напомню, там у меня получилось задать картинку и параметры через реестр, а вот форсировать обновление без перезагрузки я не смог.<\/p>\n<p>Погуглил в эту сторону, нашел пару реализованных вариантов (<a href=\"https:\/\/getps.dev\/blog\/change-desktop-wallpaper-with-powershell\/\">1<\/a> и <a href=\"https:\/\/www.joseespitia.com\/2017\/09\/15\/set-wallpaper-powershell-function\/\">2<\/a>), и скопипиздил в скрипт код, так что теперь генерятор работает без ручного труда совершенно.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/kenk-bgimage-2023-12-31.png\" width=\"969.33638443936\" height=\"800\" alt=\"\" \/>\n<\/div>\n<p><a href=\"https:\/\/github.com\/alexbatishchev\/kenk-bgimage\">Код на гитхабе<\/a>. Слава роботам!<\/p>\n",
            "summary": "В последнее время всё чаще сталкиваюсь с необходимостью использовать в powershell вызовы системного API для реализации функционала, под который нет готовых командлетов",
            "date_published": "2023-12-31T11:15:12+03:00",
            "date_modified": "2024-10-02T15:27:02+03:00",
            "tags": [
                "PowerShell",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/kenk-bgimage-2023-12-31.png",
            "_date_published_rfc2822": "Sun, 31 Dec 2023 11:15:12 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "1008",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/kenk-bgimage-2023-12-31.png"
                ]
            }
        },
        {
            "id": "988",
            "url": "https:\/\/batishchev.ru\/blog\/all\/servis-isdayoff-dlya-nuzhd-avtomatizacii\/",
            "title": "Сервис isDayOff для нужд автоматизации",
            "content_html": "<p>Несколько лет использую в работе сервис <a href=\"https:\/\/www.isdayoff.ru\/\">isDayOff<\/a>, который позволяет проверить дату на принадлежность к нерабочему дню, согласно официальным указам и распоряжениям.<\/p>\n<p>Я очень люблю автоматизацию, особенно — автоматический контроль за соблюдением правил и договоренностей в системах. Человеческий фактор невозможно полностью исключить, зато можно заставить дотошных и не устающих роботов контролировать, что человек сделал всё правильно. Однако, здесь кроется одна проблема — человеки, в отличие от роботов, уходят на выходные и государственные праздники. Согласно Первому закону робототехники, робот не может причинить вред человеку или своим бездействием допустить, чтобы человеку был причинён вред. А что может быть противней, чем тикет на исправление некритической проблемы, прилетевший в выходные? Да, можно запрограммировать, чтобы тикеты не прилетали в субботы и воскресенья — но что делать с праздниками и переносами выходных?<\/p>\n<p>isDayOff  простой как автомат Калашникова, и легко встраивается в скрипты и пайплайны автоматизации. В простейшем виде через <a href=\"https:\/\/isdayoff.ru\/today\">https:\/\/isdayoff.ru\/today<\/a> можно узнать, является ли текущий день рабочим, ну а дополнительные параметры к запросу могут дать информацию о любой дате в прошлом и будущем (в разумных пределах) и даже о праздниках в соседних странах (поддерживаются Белоруссия, Казахстан и Украина).<\/p>\n<p>База сервиса активно поддерживается и приводится в соответствие законам, когда принимаются решения о переносах праздников и выходных. Чтобы не потерять функционал при возможном отключении сервиса (а в дивные новые времена обо всём начинаешь думать в разрезе «а что если забанят»), я обычно стараюсь в проектах использовать локальную базу на год вперед, сдампленную с сайта, и обновляющуюся ежемесячно — заодно, локальная копия базы снижает нагрузку на сервис, зачем зря напрягать бесплатное отличное решение.<\/p>\n<p>В целом всё просто и понятно. Например, в виде без кеширования запрос обычно посылаю через подготовленную функцию, с логикой обработки ситуации когда сервис недоступен<\/p>\n<script src=\"https:\/\/gist.github.com\/alexbatishchev\/976d9cf2e33759a579086efa6ee999fc.js\"><\/script>\n<p>С учетом простоты решения, его легко встраивать и в других ситуациях, когда требуется контролировать рабочий статус даты — уведомления, расписание резервного копирования, подсчёт количества рабочих дней до наступления дедлайна перезагрузки по обновлениям системы, и так далее.<\/p>\n<p>Слава роботам!<\/p>\n",
            "summary": "Несколько лет использую в работе сервис isDayOff, который позволяет проверить дату на принадлежность к нерабочему дню, согласно официальным указам и распоряжениям",
            "date_published": "2023-06-07T23:37:28+03:00",
            "date_modified": "2024-10-02T15:26:38+03:00",
            "tags": [
                "PowerShell",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "_date_published_rfc2822": "Wed, 07 Jun 2023 23:37:28 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "988",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "987",
            "url": "https:\/\/batishchev.ru\/blog\/all\/zabrat-svoyo-iz-oblakov-obnovlenie-vkachatora\/",
            "title": "Забрать своё из облаков: обновление вКачатора",
            "content_html": "<p>Допилил небольшое, но важное дополнение для <a href=\"https:\/\/batishchev.ru\/blog\/all\/zabrat-svoyo-iz-oblakov-kenk-vk-enricher\/\">скрипта обогащения дампов профиля ВКонтакте<\/a>. Эксплуатация предыдущей версии выявила существенный недостаток: видео с YouTube, импортированные в ВК, в разных разделах сайта фигурируют с разными ID (и разными URL). Выходит странненькое — по этим разным ссылкам открывается один и тот же объект (страницца) ВК, с теми же комментариями, лайками, и прочими атрибутами соцсети, и конечно же встроенный в объект ролик YouTube там тоже один и тот же, но ссылки на этот объект разные. И например, добавленное на стену видео, и то же видео, посланное в диалоге, будут иметь разные адреса. Поэтому старая версия скачивала, и складывала в папку видео несколько раз, что расходовало лишнее место (а у меня в избранные как-то попала даже девятичасовая прямая трансляция выхода в открытый космос с МКС).<\/p>\n<p>Идеально было бы научить скрипт сразу узнавать такие дубликаты по адресам, и не скачивать повторы вовсе, но как это сделать я придумать не смог. Зато можно скачать через yt-dlp оригинал с ютуба, и по его метаданным распознать дубль, сравнив с метаданными уже скачанных видео. Так и поступил — теперь скрипт сохраняет в простой json информацию по всем уже скачанным файлам, и при закачке дубля не сохраняет его на диск, заменяя ссылки в дампе на уже скачанный экземпляр. На моем дампе это значительно сократило объём выгрузки.<\/p>\n<p>Обновлённая версия уже на гитхабе: <a href=\"https:\/\/github.com\/alexbatishchev\/kenk-vk-enricher\">https:\/\/github.com\/alexbatishchev\/kenk-vk-enricher<\/a><\/p>\n",
            "summary": "Допилил небольшое, но важное дополнение для скрипта обогащения дампов профиля ВКонтакте. Эксплуатация предыдущей версии выявила существенный недостаток",
            "date_published": "2023-06-01T14:52:34+03:00",
            "date_modified": "2023-06-07T23:38:25+03:00",
            "tags": [
                "PowerShell",
                "ВКачатор",
                "Забрать своё из облаков",
                "КЭНК"
            ],
            "_date_published_rfc2822": "Thu, 01 Jun 2023 14:52:34 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "987",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "985",
            "url": "https:\/\/batishchev.ru\/blog\/all\/powershell-i-strannenkoe-s-timespan\/",
            "title": "Powershell и странненькое с TimeSpan",
            "content_html": "<p>Авторы Powershell, с одной стороны, многое в своём творении придумали системно и логично. С другой стороны, постоянно натыкаешься на странности, объяснения которым в области логики не найти.<\/p>\n<p>Любимый пример — класс TimeSpan, временной промежуток, отрезок времени между двумя датами. У объектов этого класса есть несколько свойств, отражающих заданный объектом промежуток времени в разных единицах измерения. И в перечне этих свойств неочевидная логика авторов языка проявляется в полной красе.<\/p>\n<p>Вот свойства Hours, Minutes, Seconds, Milliseconds. Интуитивно думаешь, что это — значение промежутка времени в часах, минутах, секундах, и миллисекундах. Довольно быстро наступаешь на эти грабли, и узнаёшь, что это кое-что другое, а именно количество часов в рамках дня, минут в рамках часа и тому подобное. То есть, если промежуток времени у вас в 1 день и 1 час, то Hours — не 25, а 1. А если между датами прошло 2 часа и 10 минут, то свойство Minutes будет не 2*60+10, а просто 10. Зачем это надо? Ну, наверное для чего-то может пригодиться, хотя я ни разу за много лет эти свойства не использовал. Зато, сколько ошибок в скриптах из-за неверного их понимания я встречал на стековерфлоу и в прочих местах в интернетах!<\/p>\n<p>Окей, столкнувшись с этим (или прочитав заранее в документации, что вряд ли), ты спустя какое-то время познаешь TotalHours, TotalMinutes, TotalSeconds и TotalMilliseconds, с той самой очевидной логикой «полное количество часов между датами» и так далее. Если между моментами времени прошло два с половиной часа, то это будет 2.5 TotalHours, 150 TotalMinutes и 9000 TotalSeconds. Ура, теперь-то всё понятно, можем смело фигачить!<\/p>\n<p>И вот в этот момент, к полному сил и умиротворённому программисту, из-за угла подходят в кепках и адидасе братюни Days и TotalDays, и объясняют, что понятий он не знает, и вообще зря на раён зашел. Ибо Days — это в в натуре полное количество дней (а не как можно было бы по аналогии предполагать, количество дней в рамках года). А TotalDays — это да, это полное количество дней, дробь (типа, аккуратно посчитанное, вкуриваешь?). А Days — грубо посчитанное. Но полное. Почему? Короч, так надо. Кстати, дай позвонить!<\/p>\n<p>И вот, сидишь, смотришь на это, и думаешь — а оно зачем вообще так?? Потом вздыхаешь, материшься, сверяешься  с документацией ещё раз, пишешь в коде правильное.<\/p>\n<p>Может показаться, что этот пост написан с целью излучить в пространство бессильную злобу — но на деле, это просто справочник. Я буду ходить сюда каждый раз, когда буду юзать TimeSpan, потому что запоминать подобное — просто портить себе мозг.<\/p>\n<blockquote>\n<p>Дорогой Вася! Если тебе надо посчитать промежуток времени, юзай TotalDays, TotalHours, TotalMinutes, TotalSeconds и TotalMilliseconds, помни что они — вещественные, и означают то, что тебе нужно. А про другие свойства TimeSpan забудь!<\/p>\n<\/blockquote>\n<p>А для вас — картинка, иллюстрирующая всю дичь TimeSpan<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/ps-timespan.png\" width=\"652\" height=\"649\" alt=\"\" \/>\n<\/div>\n<p>Слава роботам!<\/p>\n",
            "summary": "Авторы Powershell, с одной стороны, многое в своём творении придумали системно и логично. С другой стороны, постоянно натыкаешься на странности, объяснения которым в области логики не найти...",
            "date_published": "2023-05-17T22:29:53+03:00",
            "date_modified": "2024-10-02T15:26:26+03:00",
            "tags": [
                "PowerShell",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/ps-timespan.png",
            "_date_published_rfc2822": "Wed, 17 May 2023 22:29:53 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "985",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/ps-timespan.png"
                ]
            }
        },
        {
            "id": "981",
            "url": "https:\/\/batishchev.ru\/blog\/all\/arraylist-i-proizvoditelnost-massivov-v-powershell\/",
            "title": "ArrayList и производительность массивов в Powershell",
            "content_html": "<p>Powershell — язык весьма великодушный к программистам, почти всё в нём делается легко, интуитивно, и не требует особой подготовки и продумывания от автора кода. Однако, при выходе на объемные задачи начинают выстреливать некоторые вещи, которые для удобства изначально выполнены неэффективно.<\/p>\n<p>По одной из задач мне требовалось обрабатывать большие объемы данных (сотни тысяч и миллионы строк таблиц). На тестовых множествах всё работало хорошо, но на прод данных скрипт начинал работать непозволительно долго. Я провел профилирование и выяснил, что с ростом количества данных всё больше времени (с нелинейным ростом) начинает занимать операция добавления элемента в архив.<\/p>\n<p>$array = $array + $newElement — что может быть интуитивней? Оказалось, массивы в Powerhsell это имутабельные объекты, и поэтому предыдущий код фактически создает новый неизменяемый объект из всех элементов предыдущего массива и одного нового. Конечно, на больших объемах массивов такая операция будет занимать всё больше времени, и нелинейный рост вполне объясним. Этой неэффективности лишен специальный тип данных ArrayList — это тот же массив, разве что элементы добавлять самым очевидным способом через «плюс» в него нельзя.<\/p>\n<p>Вот код, на котором я проверил время работы цикла из добавления N случайных строк к массивам в умолчальном варианте и варианте ArrayList<\/p>\n<script src=\"https:\/\/gist.github.com\/alexbatishchev\/a870321637f19fce59879015860bb50e.js\"><\/script>\n<p>На 10 тысячах операций результаты примерно похожи — отличаются в десятки процентов. Но уже на сотне тысяч разница — на порядок. При этом время работы через ArrayList растет линейно вместе с количеством циклов, а у классических массивов — экспоненциально<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/photo_2023-02-07_17-28-08.jpg\" width=\"889\" height=\"446\" alt=\"\" \/>\n<\/div>\n<p>Вот такие тонкости вскрываются спустя годы работы с языком. С другой стороны, это хорошо характеризует его в положительном плане — сколько за это времени гигабайт csvшек и джейсонов было перелопачено без этих ваших ArrayList?!<\/p>\n",
            "summary": "Powershell — язык весьма великодушный к программистам, почти всё в нём делается легко, интуитивно, и не требует особой подготовки и продумывания от автора кода",
            "date_published": "2023-02-07T16:51:56+03:00",
            "date_modified": "2024-10-02T15:26:17+03:00",
            "tags": [
                "PowerShell",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/photo_2023-02-07_17-28-08.jpg",
            "_date_published_rfc2822": "Tue, 07 Feb 2023 16:51:56 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "981",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/photo_2023-02-07_17-28-08.jpg"
                ]
            }
        },
        {
            "id": "979",
            "url": "https:\/\/batishchev.ru\/blog\/all\/zabrat-svoyo-iz-oblakov-kenk-vk-enricher-1-4\/",
            "title": "Забрать своё из облаков: kenk-vk-enricher 1.4",
            "content_html": "<p>Допилил скрипт <a href=\"https:\/\/batishchev.ru\/blog\/all\/zabrat-svoyo-iz-oblakov-kenk-vk-enricher\/\">обогащения дампа Вконтакте<\/a>. Теперь скрипт качает видео в разделах Видеозаписи, Стена и Сообщения — закачка идет через  <a href=\"https:\/\/github.com\/yt-dlp\/yt-dlp\">yt-dlp<\/a>, перед использованием желательно обновить его до свежей версии, и залогиниться в ВК в одном из бразуеров на машине, тогда yt-dlp сможет использовать куки и больше видео будет доступно для скачивания. Также скачиваются аттачменты типа «файл» на стене и в сообщениях (те, что доступны по прямым ссылкам).<\/p>\n<p>Сейчас актуальной версией скрипта мой личный профиль выкачивается на почти 200 гб, сказываются видео файлы в переписке и на стене — часто репостились интересные чужие видосы, и всё вместе занимает прилично места. Ну да больше-не меньше.<\/p>\n<p>Скрипт на гитхабе: <a href=\"https:\/\/github.com\/alexbatishchev\/kenk-vk-enricher\"><a href=\"https:\/\/github.com\/alexbatishchev\/kenk-vk-enricher\">https:\/\/github.com\/alexbatishchev\/kenk-vk-enricher<\/a><\/a><\/p>\n<p>Слава роботам!<\/p>\n",
            "summary": "Допилил скрипт обогащения дампа Вконтакте. Теперь скрипт качает видео в разделах Видеозаписи, Стена и Сообщения — закачка идет через yt-dlp, перед использованием желательно обновить его до свежей версии",
            "date_published": "2023-01-11T23:19:20+03:00",
            "date_modified": "2023-05-30T19:05:41+03:00",
            "tags": [
                "PowerShell",
                "ВКачатор",
                "Забрать своё из облаков",
                "КЭНК"
            ],
            "_date_published_rfc2822": "Wed, 11 Jan 2023 23:19:20 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "979",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "975",
            "url": "https:\/\/batishchev.ru\/blog\/all\/zabrat-svoyo-iz-oblakov-kenk-vk-enricher\/",
            "title": "Забрать своё из облаков:  kenk-vk-enricher",
            "content_html": "<p>Причесал и опубликовал <a href=\"https:\/\/github.com\/alexbatishchev\/kenk-vk-enricher\">скрипт<\/a>, докачивающий в дамп официальной выгрузки из ВКонтакте картинки в переписку (сообщения) и фотоальбомы. Фотки выкачиваются и складываются заодно внутрь дампа в папки с именами, соответствующими оригинальным альбомам, а если они были опубликованы с подписью (как например часто было при параллельной публикации в ИГ) — подпись сохраняется в отдельный текстовой файл рядом.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/kenk-vk-enricher.png\" width=\"971\" height=\"631\" alt=\"\" \/>\n<\/div>\n<p>В дампе переписке  все файлы даются прямыми ссылками. А вот в дампе стены картинки прописаны ссылками вида <a href=\"https:\/\/vk.com\/photoXXXXXXXXX_XXXXXXXXX\">https:\/\/vk.com\/photoXXXXXXXXX_XXXXXXXXX<\/a> — но тут был придуман хитрый ход, немного исправляющий ситуацию. Так как среди фотоальбомов есть «Фотографии на моей стене», то если сдампить их и из кода страницы выдернуть и прямые ссылки на файлы, и ссылки photoXXXXXXXXX_XXXXXXXXX (которые там есть), то можно закешировать это соответствие и подставить потом известные картинки в код выгрузки стены. К сожалению, так можно обойти только картинки, и только картинки ваши — репосты от других пользователей или групп так и останутся со ссылками на данные в серверах ВК. Как до них добраться без URL оригинальных файлов непонятно — с парсерами картинок ВК в интернете такая же беда как и с видео. Хотя жаль, стену со своими публикациями хотелось бы содрать в максимально полном виде, включая и репосты.<\/p>\n<p>За недолгое время с прошлой публикации yt-dlp успел разучиться качать видео из вк, и вновь научился этому в свежем апдейте — похоже что война апишников с реверс-инженерами идёт денно и нощно. С учетом этого, выкачку видео пока думаю не реализовывать.<\/p>\n<p>Забавное наблюдение — в дампе стены есть уже удалённые вами сообщения (с пометкой «Запись удалена»). Так приятно что заботливые товарищи всё хранят даже после удаления (евпочя).<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/kenk-vk-enricher2.png\" width=\"645\" height=\"468\" alt=\"\" \/>\n<\/div>\n<p>КЭНК! Слава роботам!<\/p>\n",
            "summary": "Причесал и опубликовал скрипт, докачивающий в дамп официальной выгрузки из ВКонтакте картинки в переписку",
            "date_published": "2023-01-05T22:34:03+03:00",
            "date_modified": "2023-05-30T19:05:28+03:00",
            "tags": [
                "PowerShell",
                "ВКачатор",
                "Забрать своё из облаков",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/kenk-vk-enricher.png",
            "_date_published_rfc2822": "Thu, 05 Jan 2023 22:34:03 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "975",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/kenk-vk-enricher.png",
                    "https:\/\/batishchev.ru\/blog\/pictures\/kenk-vk-enricher2.png"
                ]
            }
        },
        {
            "id": "971",
            "url": "https:\/\/batishchev.ru\/blog\/all\/kenk-bezopasno-hranim-sekrety-dlya-skriptov-powershell\/",
            "title": "КЭНК: безопасно храним секреты для скриптов PowerShell",
            "content_html": "<p>Часто из скриптов PowerShell нужно обращаться к системам, требующим аутентификации — например, для парсинга данных о хостах из корпоративной системы мониторинга, или для выгрузки данных об уязвимостях из веб-портала системы обнаружения уязвимостей. Также нередко в этих случаях используются учетные записи с расширенными полномочиями во внешних системах, но в целом это не принципиально — любые секреты хочется хранить так, чтобы до них было невозможно добраться злоумышленнику.<\/p>\n<p>Понятно, что харкодить креды в источниках или держать их в конфигурационных файлах скрипта — дело пропащее. Даже если зарезать на уровне файловой системы доступ только для учетной записи, от которой должен стартовать скрипт, остаётся возможность администратору сервера эти права изменить и данные прочитать. Неаккуратненько  выходит ©.<\/p>\n<p>К счастью, в Windows есть магическая штука на этот случай — Secure Strings — волшебство которых в данном случае заключается в том, что они работают с учетом контекста учетной записи, от которой запущены. Поэтому, если задать пароль ($pw = Read-Host -AsSecureString)  прогнать его через ConvertFrom-SecureString  ($pw | ConvertFrom-SecureString) и результат записать в файл, то на выходе будет чудесная буквенно-цифровая белиберда. А обратно эту белиберду можно превратить в пароль  (Get-Content .\\password.txt | ConvertFrom-SecureString), но только вот пароль правильным получится только если это преобразование работает от той же учетной записи, под которой шло прямое кодирование.<\/p>\n<p>При запуске скрипта на этом компьютере но от другой учетной записи, при запуске скрипта на другой машине, при смене пароля учетной записи — всегда расшифровка будет завершаться с ошибкой. Да, это создаёт неудобства при смене пароля сервисной учетной записи, от которой стартуют скрипты, и ключевую информацию нужно будет перегенерить — но зато спрятанные таким образом секреты точно завязаны на сохранность пароля от учетной записи и не могут быть прочитаны никем кроме неё.<\/p>\n<p>В своих проектах я использую свою маленькую библиотеку, позволяющую запросить и сохранить данные в ключевой файл в формате JSON, и читать данные из него в скриптах. Но в целом подход прозрачен и его можно реализовывать так как удобно<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/IMAGE-2022-11-03-00:14:55.jpg\" width=\"690\" height=\"218\" alt=\"\" \/>\n<\/div>\n<p>В интернетах пишут, что в свежих версиях павершелла появились интеграции с системами хранения паролей, но до этого мои руки пока не дошли — привычное работает, роботы трудятся, люди отдыхают<\/p>\n<p>Пример кода, иллюстрирующий подход:<\/p>\n<script src=\"https:\/\/gist.github.com\/alexbatishchev\/44be2d64097386e190468ec782d60697.js\"><\/script>\n<p>Ссылки по теме:<\/p>\n<p><a href=\"https:\/\/www.techtarget.com\/searchitoperations\/tutorial\/How-to-secure-passwords-with-PowerShell\">https:\/\/www.techtarget.com\/searchitoperations\/tutorial\/How-to-secure-passwords-with-PowerShell<\/a><br \/>\n<a href=\"https:\/\/www.travisgan.com\/2015\/06\/powershell-password-encryption.html\">https:\/\/www.travisgan.com\/2015\/06\/powershell-password-encryption.html<\/a><\/p>\n<p>Слава Роботам! КЭНК!<\/p>\n",
            "summary": "Часто из скриптов PowerShell нужно обращаться к системам, требующим аутентификации — например, для парсинга данных о хостах из корпоративной системы мониторинга",
            "date_published": "2022-11-02T23:19:24+03:00",
            "date_modified": "2024-10-02T15:26:09+03:00",
            "tags": [
                "PowerShell",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "_date_published_rfc2822": "Wed, 02 Nov 2022 23:19:24 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "971",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "955",
            "url": "https:\/\/batishchev.ru\/blog\/all\/tihoe-udalenie-obnovleniya-windows-po-nomeru-kb\/",
            "title": "КЭНК: тихое удаление обновления Windows по номеру KB",
            "content_html": "<p>Задача: тихо удалить с хоста обновление Windows по номеру KB.<\/p>\n<p>Какое-то время проблема легко решалась через wusa.exe \/uninstall \/kb:XXXXXX \/quiet, но теперь в Windows 10 команда с ключом quiet просто игнорируется, а без ключа — задает много вопросов пользователю, что ожидаемо, но не подходит для решения задачи.<\/p>\n<p>В интернетах быстро гуглится <a href=\"https:\/\/social.technet.microsoft.com\/Forums\/windows\/en-US\/f6594e00-2400-4276-85a1-fb06485b53e6\/issues-with-wusaexe-and-windows-10-enterprise?forum=win10itprogeneral\">способ<\/a>, который хорош, но не универсален. Способ рассчитывает на то что KB будет упомянута в имени пакета для DISM, а это бывает не всегда — в примере ниже у двух последних обновлений номера KB в имени пакета нет.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/Screenshot-2021-03-15-110629.png\" width=\"690\" height=\"278\" alt=\"\" \/>\n<\/div>\n<p>Ситуацию усложняет то, что в разных локалях ОС команда dism выдает информацию на разных языках, да к тому же не структурированным объектом — а строкой. К счастью, из строки все же можно выцепить имя пакета, а по нему — запросить подробную информацию (тоже строкой), где номер KB есть (судя по моим тестам) всегда:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/screen20210315116.png\" width=\"930\" height=\"657\" alt=\"\" \/>\n<\/div>\n<p>Итоговое решение задачи такое:<\/p>\n<ul>\n<li>смотрим список всех установленных обновлений и выдергиваем имена пакетов<\/li>\n<li>по каждому пакету смотрим расширенное описание и ищем в нём искомый номер KB<\/li>\n<li>если в описании найден нужный номер KB — пакет по его имени отправляется на деинсталляцию через DISM.exe \/Online \/Remove-Package \/PackageName:$sFoundPackageName \/quiet \/norestart<\/li>\n<\/ul>\n<p>Короткий сниппет, иллюстрирующий подход:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">$sKBNumber = &quot;4578968&quot;\n$aUpdts = dism \/online \/get-packages | ? {$_.Contains(&quot;Package_for&quot;)} | %{($_.Split(&quot;:&quot;))[1].Trim()}\nforeach ($sUpdate in $aUpdts) {\n\t$sInfo = (dism \/online \/get-packageinfo \/packagename:$sUpdate) -join(&quot;, &quot;)\n\tif ($sInfo.Contains($sKBNumber)) {\n\t\twrite-host &quot;Found package $sUpdate for KB number $sKBNumber&quot;\n\t\t# uncomment below to uninstall package\n\t\t# DISM.exe \/Online \/Remove-Package \/PackageName:$sUpdate \/quiet \/norestart\n\t}\n}<\/code><\/pre><p>КЭНК! Слава роботам!<\/p>\n",
            "summary": "Задача: тихо удалить с хоста обновление Windows по номеру KB",
            "date_published": "2021-03-15T13:29:36+03:00",
            "date_modified": "2025-04-14T12:23:44+03:00",
            "tags": [
                "PowerShell",
                "WSUS",
                "безопационная информасность",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/Screenshot-2021-03-15-110629.png",
            "_date_published_rfc2822": "Mon, 15 Mar 2021 13:29:36 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "955",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/Screenshot-2021-03-15-110629.png",
                    "https:\/\/batishchev.ru\/blog\/pictures\/screen20210315116.png"
                ]
            }
        },
        {
            "id": "74",
            "url": "https:\/\/batishchev.ru\/blog\/all\/kenk-sortiruem-i-filtruem-kanaly-iptv\/",
            "title": "КЭНК: сортируем и фильтруем каналы IPTV",
            "content_html": "<p>Решил подарить маме на новый год IPTV от широко известного в узких кругах провайдера. Этот сервис за небольшую плату предоставляет плейлисты с каналами, и главная суть услуги — то что списки каналов обновляются, протухшие источники заменяются новыми, клиент не бегает по интернетам в поисках собранных энтузизястами плейлистов сомнительного качества, и не остаётся вдруг без любимого НТВ под ёлочкой.<\/p>\n<p>Главный недостаток сервиса в том, что встроенная система управления каналами примитивна: можно только включать или исключать каналы целыми категорями, по тематикам или по странам. Нет возможности задания порядка каналов, нет возможности индивидуальной фильтрации. Но так как мама — человек старой закалки, ей во-первых нужно чтобы каналы были По Порядку, усвоенному со времен телевизора Темп, а во-вторых, этого вашего супер-изобилия ей не надо, а моя тайная мечта тут — пересадить её с ток-шоу на видео природы.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/televisortemp.jpg\" width=\"512\" height=\"417\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Телевизор Темп. Ровно такая же модель стала причиной больших перемен в семье моих родителей в начале 1980-х<\/div>\n<\/div>\n<p>При этом вручную колбасить плейлист от провайдера дело муторное, а с учётом протухания ссылок еще и потенциально часто повторяемое: сам провайдер предлагает в плеер забивать ссылку на динамически обновляемый плейлист, и тогда там всё свежо и отлично, а вот если плейлист забить просто в виде текста — тут уже никакой магии волшебства, и со временем окно в дивный мир превратится в тыкву.<\/p>\n<p>По итогу размышлений принимаю решение реализовать компромиссный вариант. По мере протухания каналов и жалоб клиента, буду скачивать и обновлять плейлист, фильровать и обновлять в настройках плеера. Но максимально всё это автоматизирую. На выходе — плейлист с центральными каналами в HD качестве и правильном порядке (Первый, Россия и тому подобное), дополненный избранными каналами про природу, путешествия, и хорошее кино. Под рукой винда — значит фигачим на павершелле.<\/p>\n<p>Первая итерация — скрипт, умеющий взять плейлист, и отфильтровать и отсортировать его по заданному правилу (простой json файл).  В дальнейшем, если потребуется, можно прикрутить в него скачивание провайдерского плейлиста (тривиально) и закачивание в плеер (тут будет непросто разобраться в формате HTTP запроса). Но пока так. Быстро, зло, бесплатно, работает.<\/p>\n<p>Страница на гитхабе <a href=\"https:\/\/github.com\/alexbatishchev\/kenk-iptv-playlister\">https:\/\/github.com\/alexbatishchev\/kenk-iptv-playlister<\/a><\/p>\n<p>КЭНК!<br \/>\nСлава роботам!<\/p>\n",
            "summary": "Решил подарить маме на новый год IPTV от широко известного в узких кругах провайдера. Этот сервис за небольшую плату предоставляет плейлисты с каналами",
            "date_published": "2020-12-24T13:46:13+03:00",
            "date_modified": "2020-12-24T14:49:33+03:00",
            "tags": [
                "PowerShell",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/televisortemp.jpg",
            "_date_published_rfc2822": "Thu, 24 Dec 2020 13:46:13 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "74",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/televisortemp.jpg"
                ]
            }
        },
        {
            "id": "73",
            "url": "https:\/\/batishchev.ru\/blog\/all\/kenk-certutil-check\/",
            "title": "КЭНК: контролируем сроки действия сертификатов",
            "content_html": "<p>Сегодняшняя КЭНК-история короткая и почти без кода, потому что универсальный скрипт предложить сложно, а главную ценность составляет идея.<\/p>\n<p>Итак, проблема: в некоей системе используются сертификаты пользователей. Система (и её клиентская часть) сама по себе никаких средств контроля и мониторинга сертификатов не содержит, и задача контроля срока и необходимости заблаговременного заказа, организации установки сертификатов на устройства полностью лежит на группе поддержки. Необходимо максимально исключить человеческий фактор и заставить трудиться роботов на ниве контроля сроков.<\/p>\n<p>Решение. Выгружать или как-то ещё получать доступ к сертификатам в работе система не даёт, но мы можем договориться с группой поддержки, что они будут хранить сертификаты в отдельной папке с ограниченным доступом, и работать с ней при любом обслуживании клиентов — убирать оттуда ушедшие из работы сертификаты, класть вновь выпущенные и использованные в настройке. После этого остальное дело техники — по расписанию дампим сертификаты, находим в них данные о сроке окончания, начинаем присылать предупредительные письма группе поддержки заранее. Тут кстати родилась универсальная формула, позволяющая не попасть на праздники и прочие выходные  — предупреждения высылаются за 14, 5, и 3 дня до истечения срока действия сертификата.<\/p>\n<p>Главный технический ингредиент — договориться с certutil, которая в разных версиях по разному выдает дампы.<br \/>\nВ моем конкретном случае просто парсится дата окончания через<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">$data = certutil -dump $file | select-string -pattern &quot;NotAfter:&quot;<\/code><\/pre><p>В итоге, письма рассылаются, сроки не продалбываются, клиенты довольны, человеки не держат в голове лишней информации<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/kenk-p7ber2-1.png\" width=\"639\" height=\"400\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Пример уведомления о скором сроке окончания действия сертификата<\/div>\n<\/div>\n<p>КЭНК!<br \/>\nСлава Роботам!<\/p>\n",
            "summary": "Сегодняшняя КЭНК-история короткая и почти без кода, потому что универсальный скрипт предложить сложно, а главную ценность составляет идея",
            "date_published": "2020-12-16T12:47:29+03:00",
            "date_modified": "2024-10-02T15:25:38+03:00",
            "tags": [
                "PowerShell",
                "Windows Server",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/kenk-p7ber2-1.png",
            "_date_published_rfc2822": "Wed, 16 Dec 2020 12:47:29 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "73",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/kenk-p7ber2-1.png"
                ]
            }
        },
        {
            "id": "71",
            "url": "https:\/\/batishchev.ru\/blog\/all\/kenk-wsus-carer\/",
            "title": "КЭНК: сиделка для WSUS и её приключения на планете апдейтов",
            "content_html": "<p>Хорошо настроенный <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows-server\/administration\/windows-server-update-services\/get-started\/windows-server-update-services-wsus\">WSUS<\/a> работает как часы: ходит себе в интернеты за обновлениями, раздает их клиентам, и много хлеба не просит. Есть только несколько моментов: во-первых по привычке со старых версий я обычно применяю регулярную принудительный пинок, форсирующий штатную  очистку базы от устаревших и ненужных объектов (честно говоря, не знаю есть ли проблема сейчас — но готово решение есть, почему бы не запускать —  хуже не будет, а времени роботов не жалко).<\/p>\n<p>Во-вторых, штатные средства WSUS не дают фильтровать апдейты по целевым аппаратным платформам. В итоге KB для неиспользующихся классов железа грузят базу, а руками читать описания и отклонять всё выпущенное, например, для Itanium  — ну такое.<\/p>\n<p>Последний важный момент, больше относящийся не к технологии, а к процессам и менеджменту — как построить систему одобрения обновлений так, чтобы не положить одним прекрасным ночером пару тысяч хостов кривым апдейтом (за который MS через несколько дней будет извиняться, но нас это уже не спасёт). И как при этом не оставлять системы не обновлёнными надолго, по забывчивости например. Здесь очень хочется исключить из процесса человека, оставив за кожаным мешком только задачу быстрого контроля ключевых параметров.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/2783768632_beeb811d33_c.jpg\" width=\"800\" height=\"600\" alt=\"\" \/>\n<div class=\"e2-text-caption\">Трент Резнор сказал, что BSOD тут — часть инсталляции, но мы то Всё Понимаем. Фото -<a href=\"https:\/\/www.flickr.com\/photos\/ltrandazzo\/2783768632\/\">ltrandazzo<\/a><\/div>\n<\/div>\n<p>На уровне процессов последняя задача решается выделением тестовой группы хостов, потеря которых некритична (=которых не жалко), но которые при этом активно используются (=о сбое быстро станет известно). На эти хосты обновления одобряются сразу средствами WSUS, а по прошествии выбранного времени и при отсутствии выявленных проблем — обновления раскатываются на остальные. За это определенное заранее время хорошо бы ещё держать руку на пульсе с помощью комьюнити и тематических ресурсов — благо новости о очередном KB, превращающим комплюктеры в тыкву, разносится народным гневом как лесной пожар.<\/p>\n<p>Ну а в части исключения человеческого фактора из решения — нужен робот-сиделка, что будет следить за рутиной вместо людей.<\/p>\n<h2>Прибежали в хату дети, притащили новый скрипт<\/h2>\n<p>Зовём на помощь кэнк-мена, благо у актуальных версий WSUS есть API, которое можно дёргать из PowerShell. Пара вечеров — и имеем скрипт, умеющий:<\/p>\n<ul>\n<li>перемещать в целевую группу компы по шаблонам в имени (ну так, для порядка)<\/li>\n<li>отклонять по ключевым словам апдейты, которые точно не нужны<\/li>\n<li>искать апдейты, которые были автоматически одобрены на тестовую группу больше чем заданное время назад, и аппрувить их на все машины<\/li>\n<\/ul>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/kenk-wsus-carer@2x.png\" width=\"500\" height=\"260\" alt=\"\" \/>\n<\/div>\n<p>Настраиваем конфиг, добавляем скрипт в планировщик, отдаем рутину машинам. Админу остаётся только посматривать на отчёты в почте, да вовремя реагировать на сигналы от группы эксплуатации и на статьи в этих ваших хабрахабрах и тридэньюсах.<\/p>\n<p>Скрипт на гитахабе <a href=\"https:\/\/github.com\/alexbatishchev\/kenk-wsus-carer\">https:\/\/github.com\/alexbatishchev\/kenk-wsus-carer<\/a><\/p>\n<p>КЭНК!<br \/>\nСлава роботам!<\/p>\n",
            "summary": "Хорошо настроенный WSUS работает как часы: ходит себе в интернеты за обновлениями, раздает их клиентам, и много хлеба не просит",
            "date_published": "2020-12-11T15:19:38+03:00",
            "date_modified": "2024-10-02T15:25:31+03:00",
            "tags": [
                "PowerShell",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/2783768632_beeb811d33_c.jpg",
            "_date_published_rfc2822": "Fri, 11 Dec 2020 15:19:38 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "71",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/2783768632_beeb811d33_c.jpg",
                    "https:\/\/batishchev.ru\/blog\/pictures\/kenk-wsus-carer@2x.png"
                ]
            }
        },
        {
            "id": "69",
            "url": "https:\/\/batishchev.ru\/blog\/all\/kenk-contacts-watcher\/",
            "title": "КЭНК: следитор за изменениями в контактах Exchange",
            "content_html": "<p>На нынешнем проекте сложилась практика использования ящиков в Exchange в качестве адресной книги сразу несколькими членами рабочей группы и\\или на нескольких устройствах одновременно. При этом регулярно возникала необходимость понять, когда было внесено то или иное изменение в адресную книгу ящика, а иногда — ещё и скопировать изменённые данные обратно без привлечения технических специалистов и механизмов резервного копирования. Ожидаемо, функционал требовался кастомный, а бюджет на получение дополнительного сервиса не рассчитан.<\/p>\n<h2>Заряжаем павершелломёт<\/h2>\n<p>Для целей автоматизации Exchange я часто использую Exchange Web Services (EWS) Managed API, вызывая его функции из PowerShell через <a href=\"https:\/\/www.microsoft.com\/en-us\/download\/details.aspx?id=42951\">библиотеку<\/a>. Его применение напрашивается и тут. Можно смотреть содержимое адресной книги, дампить интересуемые данные из ящика в текстовый файл, сравнивать результаты актуального дампа и предыдущего, и формировать отчёты об изменениях. Побочный результат — раз уж мы получаем изменения, можно хранить их историю и иметь возможность ретроспективы.<\/p>\n<p>Дальше — дело техники и деталей. Выгружаем поля в текстовый формат, схлопываем многоэлементные объекты в строки по формату как нам вздумается, исключаем те поля, за которыми следить не хотим. Приправляем наглядным представлением в виде HTML отчёта, выделяем цветом изменения и наносим прочую пользу клиентам сервиса. Даем возможность службе техподдержки ставить и снимать ящики с контроля добавлением в специальную доменную группу. Запускаем скрипт по планировщику с максимально возможной частотой. Роботы трудятся — а человеки пользуются результатом.<\/p>\n<div class=\"e2-text-picture\">\n<div class=\"fotorama\" data-width=\"720\" data-ratio=\"1.4574898785425\">\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/kenk-contacts-watcher-change-1.png\" width=\"720\" height=\"494\" alt=\"\" \/>\n<img src=\"https:\/\/batishchev.ru\/blog\/pictures\/kenk-contacts-watcher-deleted.png\" width=\"720\" height=\"494\" alt=\"\" \/>\n<\/div>\n<div class=\"e2-text-caption\">Примеры отчётов об изменении части контакта и удалении контакта из ящика<\/div>\n<\/div>\n<p>Сервис на базе этого скрипта успешно работает несколько лет. Служба техподдержки всегда может разрешить вопросы клиентов об изменениях в адресных книгах, некоторые клиенты пользуются отчётами для контроля работы в группе и оперативного отката изменений. Уникальный кастомный сервис достался заказчику в рамках общего контракта на обслуживание системы.  Проблемы, для решения которых раньше требовалась работа специалиста, решаются автоматически и часто без привлечения техподдержки вообще. Чистый КЭНК!<\/p>\n<p>Скрипт на гитхабе <a href=\"https:\/\/github.com\/alexbatishchev\/kenk-contacts-watcher\">https:\/\/github.com\/alexbatishchev\/kenk-contacts-watcher<\/a><\/p>\n<p>Слава Роботам!<\/p>\n",
            "summary": "На нынешнем проекте сложилась практика использования ящиков в Exchange в качестве адресной книги сразу несколькими членами рабочей группы и\\или на нескольких устройствах одновременно",
            "date_published": "2020-12-04T21:49:20+03:00",
            "date_modified": "2024-10-02T15:24:48+03:00",
            "tags": [
                "EWS",
                "PowerShell",
                "все эти ваши компьютеры",
                "КЭНК"
            ],
            "image": "https:\/\/batishchev.ru\/blog\/pictures\/kenk-contacts-watcher-change-1.png",
            "_date_published_rfc2822": "Fri, 04 Dec 2020 21:49:20 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "69",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "jquery\/jquery.js",
                    "fotorama\/fotorama.css",
                    "fotorama\/fotorama.js"
                ],
                "og_images": [
                    "https:\/\/batishchev.ru\/blog\/pictures\/kenk-contacts-watcher-change-1.png",
                    "https:\/\/batishchev.ru\/blog\/pictures\/kenk-contacts-watcher-deleted.png"
                ]
            }
        }
    ],
    "_e2_version": 4199,
    "_e2_ua_string": "Aegea 11.5 (v4199)"
}