В этой статье мы рассмотрим подход как просто, эффективно и, самое главное, бесплатно отслеживать изменения групповой политики (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\configHost 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

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

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

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

Что в итоге? Вы скажете очередной велосипед и наколенная поделка. Так и есть, но сколько пользы может принести такой маленький сервис.
Статья получилась сжатой потому что её цель - поделиться простым подходом, вокруг которого можно сделать обвязку любой сложности.
mumische
В дополнение могу ещё посоветовать Netwrix Auditor (бесплатная редакция ещё существует) плюс ELK (или к чему душа больше лежит) с экспортом туда соответствующих событий из журналов.