Я думаю, каждый системный администратор задавался вопросом автоматизации учёта электронных подписей в своей организации. Потому что вопросы «Какие у нас есть электронные подписи?», «На каких компьютерах они установлены?», «Когда они заканчиваются?» и т.д. возникают регулярно.
Иногда на них отвечает юридический отдел, иногда их адресуют нам, системным администраторам. А кто в вашей организации ведёт учёт электронных подписей? Расскажите об этом в комментариях, будет интересно почитать.
Начнём с постановки задачи. Здесь, лучше всего, задачу разбить на подзадачи. И для каждой подзадачи использовать какой-то универсальный инструмент. Хорошо бы уже кем-то созданный, но если такого инструмента нету, то можно и самому попрограммировать. Когда дело доходит до программирования, я стараюсь смотреть на задачу шире. И программируя, делаю инструмент универсальнее, чтобы потом его можно было применить и для других схожих задач. Как говориться «универсальное празднует победу над любым частным». И так, наши задачи:
Нам нужен инструмент, который будет доставлять наш код (скрипт) на компьютер, исполнять его и возвращать результат его работы обратно. Результатом работы может быть просто код возврата, но в нашем случае результатом будут файлы сертификатов. Т.к. лучше забирать открытые части электронных подписей (сертификаты) целиком и потом с ними работать.
Нам нужно приложение (скрипт), которое будет из указанных сертификатов получать нужную нам информацию.
И вероятно нам потребуется третий инструмент, который будет агрегировать эту полученную информацию в таблицу, с которой более удобно работать.
Приступим к реализации поставленных задач.
Выполнение кода на удалённых компьютерах
К счастью, эта задача весьма распространённая. И существует множество инструментов для решения такой задачи. Я расскажу о тех, которые мне нравятся больше всего. А вы напишите о своих любимых инструментах, которые решают такие задачи, в комментариях.
1. Logon скрипт в Group Policy Object
В групповых политиках (GPO) Active Directory есть возможность указать скрипт, который будет срабатывать при входе, выходе пользователя или при включении, выключении компьютера. В нашем случае подойдёт событие входа пользователя.
Плюсы:
Выполняется по событию, т.е. как бы параллельно на нескольких компьютерах.
Сразу в нужном контексте, в контексте пользователя с сертификатами.
Минусы:
Нельзя выполнить скрипт по желанию, нужно ждать наступления события.
Нужно тонко настраивать права на папку с результатами работы скрипта.
Если компьютер на удалёнке, то можно никогда не получить результат.
2. Инсталляционный пакет в Kaspersky Security Center
Если у вас используется Kaspersky Security Center, то вы можете в нём создать инсталляционный пакет. В него вложить свой скрипт и выполнить его на нужной выборке компьютеров.
Плюсы:
Выполняется параллельно на нескольких компьютерах.
Можно выполнить скрипт по желанию, запустив задачу вручную.
Удобный и приятный интерфейс.
Минусы:
Выполняется не в контексте пользователя (об этом чуть позже).
Нужно самому думать, как собирать результаты выполнения.
3. Командлет Invoke-Command в PowerShell
Можно воспользоваться командлетом Invoke-Command в PowerShell, который позволяет выполнить нужный нам код на удалённых компьютерах. В чистом виде командлет Invoke-Command
не очень интересен, т.к. он не имеет каких-либо преимуществ над описанными выше вариантами. Но если с ним поработать, сделать обвязку, добавить параллельное исполнение и другие полезные опции, то получается не плохой вариант.
Так собственно и появился скрипт Invoke-TaskCommand.ps1
, который вы можете найти в моём репозитории на GitHub. Скрипт выполняет команду -Command
на списке удалённых компьютеров -ComputerName
в контексте заданной учётной записи -AccountSID
. При этом скрипт может доставить на удалённый компьютер вспомогательные файлы из папки -InputPath
и вернуть обратно в другую папку -OutputPath
файлы, как результат работы команды. Так же есть WMI фильтры -IncludeWQL
и -ExcludeWQL
, в которых можно написать WQL запросы. С помощью них можно гибко исключать не нужные нам компьютеры из списка и не делать лишнюю работу по доставке вспомогательных файлов на эти компьютеры. В скрипте задействован PowerShell модуль ThreadJob
что распараллеливает обход компьютеров в 16 потоков. И благодаря этому пробежка по 1000 компьютеров занимает не 1,5 часа, а 15 - 20 минут. Нужная нам команда выглядит следующим образом:
$ComputerNames = Get-Content -Path '..\Data\List\Computer\All.txt' -Encoding 'Unicode';
$Command = 'powershell.exe -Command Get-ChildItem -Path CERT:\CurrentUser\My | ForEach-Object { Export-Certificate -Cert $PSItem -FilePath ($PSItem.Thumbprint + .cer);};';
.\Invoke-TaskCommand.ps1 -TaskName "Export Certificate" -Command $Command -ComputerName $ComputerNames -AccountSID "S-1-5-32-545" -OutputPath $ExportLocation;
Мы просто подключаемся к удалённому компьютеру и извлекаем все сертификаты (открытые части) электронных подписей и доставляем их в папку на наш компьютер. Отдельно стоит обсудить -AccountSID
. Нюанс заключается в том, что когда мы подключаемся к удалённому компьютеру, то мы работаем в контексте своей учётной записи, из-под которой мы запускаем скрипт. Но нужные нам сертификаты находятся не в хранилище нашего пользователя, а в хранилище пользователя, который сейчас работает за компьютером. Так как же нам туда попасть, не зная логина и пароля?
Я знаю только один способ. Это на лету в скрипте создать задачу в Планировщике заданий, указать в ней, что она исполняется от имени нужного нам пользователя или группы и запустить её. И если пользователь залогинен в системе, то команда будет запущена в контексте этого пользователя. В нашем случае мы используем так называемый хорошо известный SID Пользователи
. Кстати, если вы знаете ещё какие-то способы, как перейти в контекст другого пользователя, не зная его пароля, то расскажите об этом в комментариях, мне будет интересно почитать.
Так же стоит упомянуть, что список компьютеров для обхода мы не будем создавать вручную, мы просто выгрузим его из Active Directory. В данном случае, я использую другой мой скрипт env.search.min.js
, про который я рассказывал в другой статье Скрипт так же опубликован на GitHub.
cscript /nologo /u env.search.min.js ldap {ABCD1234-111B-14DC-ABAC-4578F1145541} search= noalign > All.txt
Получение данных из сертификата электронной подписи
И так, мы получили файлы сертификатов, которые аккуратно сложены по папочкам с именами компьютеров. Теперь нам нужно их переименовать в удобный нам вид и получить из них данные. Для этого я написал скрипт Get-CertificateData.ps1
, который вы то же можете найти в моём репозитории на GitHub.
Он принимает на вход сертификат и возвращает на выходе PSCustomObject
с наиболее интересными нам атрибутами. Из интересного стоит отметить OID с идентификатором 1.2.643.2.2.49.2
его присутствие в сертификате означает наличие встроенной лицензии КриптоПРО. А чтобы переименовать файл, просто воспользуемся атрибутом CER-NAME
возвращаемого объекта, он как раз создан для этой задачи.
$Certificate = Get-PfxCertificate -FilePath $File.FullName;
$CertificateName = .\Get-CertificateData.ps1 -Certificate $Certificate -DataKey "CER-NAME" -Expanded -FixExpire;
Rename-Item -Path $File.FullName -NewName ($CertificateName + $File.Extension);
Агрегируем информацию из сертификатов в таблицу
В этой задачи ничего сложного нет, мы вообще её выполним одной строкой, просто передавая объекты по конвейеру в PowerShell. Сначала получим файлы сертификатов из папок. Затем из них создадим стандартные PfxCertificate
объекты. Их направим в наш скрипт Get-CertificateData.ps1
и получим PSCustomObject
объекты с нашими атрибутами. Их сконвертируем в CSV
строки и направим в результирующий файл.
Get-ChildItem -Path $Folder.FullName -File | Get-PfxCertificate | .\Get-CertificateData.ps1 -DataKey "NET-HOST" -DataValue $ComputerName -FixExpire | ConvertTo-Csv -Delimiter "`t" -UseQuotes "Never" | Out-File -FilePath "Report.csv" -Encoding "Unicode";
Из интересного отмечу командлет Out-GridView в PowerShell. Он позволяет достаточно удобно представлять табличные данные в графическом виде. Воспользуемся им для отображения данных.
Import-Csv -Path "Report.csv" -Encoding "Unicode" -Delimiter "`t" | Out-GridView -Wait -Title "Реестр сертификатов";
Заключение
Как видите, задача автоматизации учёта электронных подписей не такая и сложная. Комбинируя разные скрипты, мы как из кубиков строим решение нужной нам задачи.
Вы можете начать с малого, просто создайте несколько папок, например Архив
и Действующие
. Положите в них файлы сертификатов. Рядом с папками создайте ярлычок Отчёт
со следующей командой:
powershell.exe -WindowStyle Hidden -ExecutionPolicy Bypass -File Show-Certificates.ps1 -Rename
Скачайте в эту папку скрипт Get-CertificateData.ps1
из моего репозитории на GitHub. И ещё добавьте скрипт Show-Certificates.ps1
, код которого приведён ниже. И так, уже сейчас, вы сможете легко и просто строить отчёты по своим электронным подписям.
Спасибо за внимание, надеюсь данная статья будет вам полезна. Делитесь своим мнением в комментариях.
<#
.DESCRIPTION
Отображает отчёт по реестру сертификатов.
.PARAMETER Rename
Переименовать сертефикаты перед построением отчёта.
.NOTES
Версия: 0.1.0
Автор: @ViPiC
#>
[CmdletBinding()]
Param (
[switch]$Rename
);
$Items = @();
$Folders = Get-ChildItem -Directory;
foreach ($Folder in $Folders) {
$Files = Get-ChildItem -Path $Folder.FullName -Filter "*.cer" -File -Recurse;
foreach ($File in $Files) {
$Certificate = Get-PfxCertificate -FilePath $File.FullName;
$Items += .\Get-CertificateData.ps1 -Certificate $Certificate -DataKey "CER-CATEGORY" -DataValue $Folder.BaseName -FixExpire;
if ($Rename) {
$CertificateName = .\Get-CertificateData.ps1 -Certificate $Certificate -DataKey "CER-NAME" -Expanded -FixExpire;
if ($File.BaseName -ne $CertificateName) { Rename-Item -Path $File.FullName -NewName ($CertificateName + $File.Extension); };
};
};
};
$Items | Out-GridView -Wait -Title "Реестр электронных подписей";
ASD2003ru
А почему не получить список компов из AD с помощью PS? Зачем там какой то js?
ASD2003ru
Еще на счет прав, посмотрите это, возможно поможет
https://stackoverflow.com/questions/42581334/elevate-without-prompt-verb-runas-start-process
ViPiC Автор
Спасибо за информацию. Но я чуть-чуть про другую задачу. Нужен не обход User Account Control (UAC), а возможность получить данные в контексте другого пользователя, не зная его пароль. Пока такую возможность я нашёл только через Планировщик заданий.
ViPiC Автор
Да, можно и с помощью PowerShell. ????
С использованием модуля
Active Directory
(нужно будет его доустановить).Или можно воспользоваться уже имеющимся объектом
DirectorySearcher
.JScript тут больше использовался для примера, что можно одну и ту же задачу решить разными способами. Просто скрипт
env.search.min.js
был под рукой, я подумал «а почему бы и нет...», т.к. нужную задачу он может решить.А в целом, да, лучше использовать одну технологию. ????