Мониторинг изменений групповой политики Active Directory через git
В этой статье мы рассмотрим подход как просто, эффективно и, самое главное, бесплатно отслеживать изменения групповой политики (GPO) Active Directory.
Если вы не единственный системный администратор в компании, своевременно ли вы узнаете, что кто-то из коллег изменил групповую политику? Обычно утром кто-то звонит и спрашивает - "А кто-то что-то менял в политике? У меня не работает/не подключается.."
Хорошо когда для мониторинга есть отдельный продукт, а если нет? Использование репозитория git поможет легко и наглядно следить за изменениями объектов.
TL;DR
Идея: регулярно экспортировать GPO в xml и загружать на сервер git
Результат: бесплатный мониторинг изменений политики с минимальными трудозатратами
В исходном виде объекты GPO не очень подходят для добавления в репозиторий. Составные части политики представляют собой набор разнородных файлов - от бинарных до относительно понятных XML. Это обусловлено тем, что обработка политики не монолитна, а настройки применяются множеством policy extensions.
Но что если использовать командлет Get-GPOReport -ReportType Xml? На выходе вы получите один легко читаемый XML файл со всеми параметрами политики.
Для реализации задуманного нам потребуется сервер git и репозиторий для GPO. Если у вас ещё нет сервера git, самое простое - развернуть Gitea Releases · go-gitea/gitea. Это легкий, функциональный, мультиплатформенный сервер, состоящий из одного бинарного файла. Для перехода на новую версию Gitea достаточно скопировать один единственный бинарник поверх старого.
В профиле пользователя, под которым будет запускаться скрипт, необходимо сохранить SSH ключи для сервера GIT и проверить работоспособность.
Как настроить в Gitea с использованием встроенного сервера SSH?
Добавьте открытый ключ SSH для пользователя и внесите следующие настройки в app.ini
DISABLE_SSH = false
START_SSH_SERVER = true
BUILTIN_SSH_SERVER_USER = git
SSH_LISTEN_PORT = 3022
SSH_PORT = 3022
Если не задать BUILTIN_SSH_SERVER_USER, то для Gitea в Windows именем пользователя будет учетная запись, под которой запущен сервер. В Linux - git. Имя необходимой учетной записи можно найти в логе
2026/09/29 10:14:27 modules/ssh/ssh.go:227:publicKeyHandler() [W] Invalid SSH username git - must use my-git-server for all git operations via ssh
Добавьте хост Gitea в конфигурацию пользователяC:\users\my-report-user\.ssh\config
Host my-git-server HostName git01.example.test User git IdentityFile ~/.ssh/id_git
Для запуска скрипта достаточно непривилегированного пользователя, так как объекты GPO в каноничной реализации вендора доступны на чтение всем аутентифицированным пользователям.
В качестве контроллера домена рекомендую выбрать контроллер с ролью PDC, ведь именно на нём по умолчанию происходит изменение GPO.
Примерный скрипт. Он написан в эпоху до-LLM, проверьте и адаптируйте его любимым агентом.
# Каталог репозитория
# предпочтительно сохранять с PDC
$ADDC = "dc01.example.com"
$gitpath = "C:\Scripts\Save-GPOReportToGit\git\ADGPO"
$logfile = "C:\Scripts\Save-GPOReportToGit\Save-GPOReportToGit.log"
# Описание коммита
$gitcommit = (Get-Date).toString("yyyy-MM-dd")
Start-Transcript $logfile
# Получаем все объекты GPO в домене
try {
$gpos = Get-GPO -All -Server $ADDC -ErrorAction Stop | Sort-Object DisplayName
}
catch {
Write-Host $_ -ForegroundColor Red
Stop-Transcript
exit 1
}
# очищаем предыдущие сохраненные GPO
if ($gpos) { Remove-Item "$gitpath\*.xml" -Force }
# Экспортируем настройки GPO в XML файлы
foreach ($gpo in $gpos) {
Write-host $gpo.DisplayName
$report = Get-GPOReport -ReportType Xml -Guid $gpo.id -Server $ADDC
# Удаляем строки с тегом <ReadTime> (время запуска командлета экспорта),
# Без удаления тега файл в репозитории будет меняться каждую выгрузку
$report -replace ".*<ReadTime>.*<\/ReadTime>\r\n", $null | Out-File -FilePath "$gitpath\$($gpo.DisplayName).xml" -Encoding utf8 -Force
}
cd $gitpath
# Подавление ошибок. Если отсутствуют измененные файлы, git push выводит "nothing to commit, working tree clean" в stderr
$ErrorActionPreference = "SilentlyContinue"
$gitaction = @(
& git "status" 2>&1
& git "add", "-A" 2>&1
& git "commit", "-m", ""$gitcommit"" 2>&1
& git "push", "-u", "origin", "main" 2>&1
)
$gitaction
$ErrorActionPreference = "Continue"
$Body = [string]($gitaction -join "`r`n")
$message = @{
UseSsl = $true
Encoding = 'UTF8'
SmtpServer = 'exchange.example.test'
From = 'gpo-report@example.test'
To = "admin@example.test"
Subject = "ADGPO git log"
Body = $Body
}
Send-MailMessage @message
Stop-TranscriptДобавьте его в Task Scheduler.
Что же мы получаем в итоге?
В вашем репозитории будет храниться набор xml-файлов, где каждый файл соответствует одной политике

На первый взгляд может показаться, что содержимое файлов не очень-то человекочитаемое (хотя кто сейчас доверяет читать человекам?). Но на самом деле, разобраться в изменении очень легко:
Политика привязана к новом OU

Добавлено новое подключение к принтеру

Добавлена новая политика аудита

Изменена политика безопасности

Что в итоге? Вы скажете очередной велосипед и наколенная поделка. Так и есть, но сколько пользы может принести такой маленький сервис.
Статья получилась сжатой потому что её цель - поделиться простым подходом, вокруг которого можно сделать обвязку любой сложности.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.