Windows Server для самых маленьких. Часть 24: Как работают групповые политики?
Все части серии «Windows Server для самых маленьких»Групповая политика упоминалась почти в каждой части: в части 3 клиент скачивал её из SYSVOL при входе, в части 12 она должна была настраивать время на PDC, в части 20 её резервные копии входили в список обязательных, в части 23 ею предлагалось пополнять локальные группы. Пора разобрать её устройство: что такое объект политики на уровне каталога и файлов, как клиент решает, какие политики к нему относятся и в каком порядке, и как всем этим управлять из модуля GroupPolicy, — а в конце собрать ту самую политику для PDC, целиком командами.
Все команды ниже выполняются с рабочей станции администратора ws1 с RSAT (часть 15) в PowerShell 7. Домен — corp.example.com, контроллеры dc1 и dc2 в сайте Office, dc3 и dc4 в сайте Branch, dc1 — PDC. Модуль GroupPolicy не объявляет совместимость с PowerShell 7 и по умолчанию загружается через слой совместимости: объекты приходят десериализованными, и вложенные свойства вроде $_.Computer.DSVersion в вычисляемых колонках оказываются пустыми. Поэтому модуль загружаем напрямую:
PS C:\> Import-Module GroupPolicy -SkipEditionCheck
Из чего состоит политика
Объект групповой политики (GPO) живёт в двух местах одновременно, и это объясняет половину его странностей.
Контейнер в каталоге (GPC, Group Policy Container) — объект класса groupPolicyContainer с именем-GUID в CN=Policies,CN=System:
PS C:\> Get-ADObject 'CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=corp,DC=example,DC=com' -Properties displayName, versionNumber, gPCFileSysPath, gPCMachineExtensionNames, gPCUserExtensionNames, flags |
Format-List displayName, Name, versionNumber, flags, gPCFileSysPath, gPCMachineExtensionNames, gPCUserExtensionNames
displayName : Default Domain Policy
Name : {31B2F340-016D-11D2-945F-00C04FB984F9}
versionNumber : 76
flags : 0
gPCFileSysPath : \\corp.example.com\sysvol\corp.example.com\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}
gPCMachineExtensionNames : [{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{53D6AB1B-2488-11D1-A28C-00C04FB94F17}{D02B1F72-3407-48AE-BA88-E8213C6761F1}][{827D319E-6EAC-11D2-A4EA-00C04F79F83A}{803E14A0-B4FB-11D0-A0D0-00A0C90F574B}][{B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A}{53D6AB1B-2488-11D1-A28C-00C04FB94F17}]
gPCUserExtensionNames :
Имя, версия, путь к файлам, флаги и список расширений клиента (CSE, client-side extension), которые должны обработать эту политику. Каждая пара квадратных скобок — одно расширение: первым идёт GUID самого расширения, за ним один или несколько GUID компонентов редактора, которыми настройки записаны. Здесь три расширения: реестр {35378EAC-…} (административные шаблоны и политики открытых ключей), параметры безопасности {827D319E-…} и агент восстановления EFS {B1BE8D72-…}. Если расширения в списке нет, клиент не станет искать его настройки в файлах, даже если они там лежат. Пользовательской части у этой политики нет — gPCUserExtensionNames пуст.
flags — отключённые половины политики: 0 — включено всё, 1 — отключена пользовательская часть, 2 — компьютерная, 3 — обе. Модуль показывает то же свойством GpoStatus (AllSettingsEnabled, UserSettingsDisabled, ComputerSettingsDisabled, AllSettingsDisabled).
Папка в SYSVOL (GPT, Group Policy Template) — по пути из gPCFileSysPath:
\\corp.example.com\SYSVOL\corp.example.com\Policies\{GUID}\
GPT.INI [General] Version=…
GPO.cmt комментарий к политике (Unicode)
Machine\
Registry.pol настройки реестра для компьютера (административные шаблоны)
Microsoft\Windows NT\SecEdit\GptTmpl.inf параметры безопасности: пароли, Kerberos, права, аудит
Scripts\Startup\, Scripts\Shutdown\
Preferences\ предпочтения, по папке на тип: Drives, Registry, Groups, ScheduledTasks …
User\
Registry.pol
Scripts\Logon\, Scripts\Logoff\
Preferences\
Папки появляются, только когда в них что-то записано: у политики с одной настройкой реестра для компьютера есть лишь GPT.INI и Machine\Registry.pol. У двух политик, созданных вместе с доменом, папки называются MACHINE и USER заглавными — SYSVOL регистр не различает.
Версия — 32-битное число: старшие 16 бит — версия пользовательской части, младшие — компьютерной. Каждое сохранение части увеличивает её счётчик на единицу. В каталоге она лежит в versionNumber, в SYSVOL — в GPT.INI:
PS C:\> Get-ADObject -SearchBase 'CN=Policies,CN=System,DC=corp,DC=example,DC=com' -SearchScope OneLevel -Filter * -Properties displayName, versionNumber, flags |
Format-Table displayName, versionNumber, @{n='User'; e={$_.versionNumber -shr 16}}, @{n='Computer'; e={$_.versionNumber -band 0xFFFF}}, flags -AutoSize
displayName versionNumber User Computer flags
----------- ------------- ---- -------- -----
Default Domain Policy 76 0 76 0
Users - Intranet Zone 196608 3 0 0
Network - Prefer IPv4 8 0 8 0
Network - Prefer IPv6 65539 1 3 0
Network Discovery 74 0 74 0
Default Domain Controllers Policy 76 0 76 0
Remote Desktop 20 0 20 0
Time - No Hyper-V Sync 1 0 1 0
Workstations - Guest SMB 5 0 5 0
DC - PDC Time Source 10 0 10 0
196608 = 0x00030000: пользовательская часть сохранялась три раза, компьютерная — ни разу. 65539 = 0x00010003: один раз и три. Модуль показывает обе половины и версию в SYSVOL:
PS C:\> Get-GPO -All | Format-Table DisplayName, GpoStatus, @{n='User'; e={$_.User.DSVersion}}, @{n='Computer'; e={$_.Computer.DSVersion}}, @{n='Sysvol'; e={$_.Computer.SysvolVersion}}, @{n='WmiFilter'; e={$_.WmiFilter.Name}} -AutoSize
DisplayName GpoStatus User Computer Sysvol WmiFilter
----------- --------- ---- -------- ------ ---------
Default Domain Policy AllSettingsEnabled 0 76 76
Users - Intranet Zone AllSettingsEnabled 3 0 0
Network - Prefer IPv4 AllSettingsEnabled 0 8 8
Network - Prefer IPv6 AllSettingsEnabled 1 3 3
Network Discovery AllSettingsEnabled 0 74 74
Default Domain Controllers Policy AllSettingsEnabled 0 76 76
Remote Desktop AllSettingsEnabled 0 20 20
Time - No Hyper-V Sync AllSettingsEnabled 0 1 1
Workstations - Guest SMB AllSettingsEnabled 0 5 5
DC - PDC Time Source AllSettingsEnabled 0 10 10 PDC emulator
Контейнер реплицируется вместе с каталогом, а папка — DFSR вместе с SYSVOL (часть 10), и это два независимых механизма. Решение, изменилась ли политика, клиент принимает по контейнеру, а настройки читает из файлов. Если на контроллере, к которому обратился клиент, каталог уже обновился, а SYSVOL ещё нет, клиент получит прежние файлы или не найдёт новых — отсюда события 1058 на только что созданных политиках. Отчёт gpresult /h помечает такую политику «AD / SYSVOL Version Mismatch», а консоль GPMC показывает расхождения на вкладке состояния инфраструктуры.
Два объекта с фиксированными GUID созданы при установке домена, они одинаковы во всех доменах. Default Domain Policy по рекомендации Microsoft хранит только политику учётных записей: пароли, блокировку и Kerberos. Эти настройки действуют для доменных учётных записей только из политик, привязанных к корню домена (заданные в политике OU касаются лишь локальных учётных записей машин этой OU), и контроллеры переносят их в атрибуты корня домена (minPwdLength, lockoutThreshold и другие из части 5); отдельные парольные требования для групп задаются не политикой, а объектами PSO (fine-grained password policy) в каталоге. Default Domain Controllers Policy — права пользователей и аудит на контроллерах; в ней же по умолчанию включены обязательная подпись SMB и защищённого канала (RequireSecuritySignature, RequireSignOrSeal в GptTmpl.inf). Остальное в них не кладут: свои настройки — в свои политики, а эти две при порче возвращает к исходному виду dcgpofix /target:domain или /target:dc.
Привязка
Сама по себе политика ни к кому не относится. Её привязывают к сайту, домену или OU, и привязка — атрибут gPLink на этом объекте:
PS C:\> Get-ADObject 'DC=corp,DC=example,DC=com' -Properties gPLink, gPOptions | Format-List gPLink, gPOptions
gPLink : [LDAP://cn={8b9c0d1e-2f3a-4b4c-9d5e-6f7a8b9c0d1e},cn=policies,cn=system,DC=corp,DC=example,DC=com;0][LDAP://cn={3C5D6E7F-8091-4A2B-B3C4-D5E6F7081920},cn=policies,cn=system,DC=corp,DC=example,DC=com;0][LDAP://CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=corp,DC=example,DC=com;0]
gPOptions :
В схеме gPLink — одна строка, а групповая политика читает её как список: в квадратных скобках DN контейнера политики и через точку с запятой флаги привязки — 0 обычная, 1 отключена, 2 принудительная (enforced), 3 — отключённая принудительная. Новая привязка дописывается в начало строки, а применяются они справа налево: последняя в строке — первая по порядку (Order 1) и выигрывает у соседей по контейнеру. Тот же домен глазами модуля:
PS C:\> (Get-GPInheritance -Target 'DC=corp,DC=example,DC=com').GpoLinks | Format-Table Order, DisplayName, Enabled, Enforced -AutoSize
Order DisplayName Enabled Enforced
----- ----------- ------- --------
1 Default Domain Policy True False
2 Users - Intranet Zone True False
3 Time - No Hyper-V Sync True False
Default Domain Policy, привязанная первой, стоит в строке последней и имеет порядок 1; привязанные позже получили 2 и 3. gPOptions = 1 на домене или OU — блокировать наследование; пустой атрибут означает 0. Если снять последнюю привязку, в gPLink остаётся строка из одного пробела.
Клиент собирает политики по цепочке LSDOU: локальная политика машины, затем политики сайта, домена, OU и вложенных OU до той, в которой лежит объект. Применяются по порядку, и каждая следующая перекрывает предыдущую в тех настройках, которые задаёт. Отсюда правила:
- настройка из OU побеждает настройку из домена, из вложенной OU — из родительской;
- блокировка наследования на OU отрезает всё сверху — кроме принудительных привязок;
- принудительная привязка побеждает всё ниже себя, в том числе блокировку, и из двух принудительных побеждает та, что выше;
- внутри одного контейнера побеждает привязка с меньшим номером.
PS C:\> (Get-GPInheritance -Target 'OU=Domain Controllers,DC=corp,DC=example,DC=com').InheritedGpoLinks | Format-Table Order, DisplayName, Enabled, Enforced, Target -AutoSize
Order DisplayName Enabled Enforced Target
----- ----------- ------- -------- ------
1 Default Domain Controllers Policy True False OU=Domain Controllers,DC=corp,DC=example,DC=com
2 Network Discovery True False OU=Domain Controllers,DC=corp,DC=example,DC=com
3 Remote Desktop True False OU=Domain Controllers,DC=corp,DC=example,DC=com
4 DC - PDC Time Source True False OU=Domain Controllers,DC=corp,DC=example,DC=com
1 Default Domain Policy True False DC=corp,DC=example,DC=com
2 Users - Intranet Zone True False DC=corp,DC=example,DC=com
3 Time - No Hyper-V Sync True False DC=corp,DC=example,DC=com
Список идёт по убыванию приоритета: верхняя строка выигрывает у всех нижних. Order — номер привязки внутри своего контейнера, поэтому у политик домена нумерация начинается заново. Принудительные привязки модуль ставит в начало списка, блокировка наследования на OU (GpoInheritanceBlocked : Yes в выводе Get-GPInheritance) убирает из него всё, что выше, кроме них.
Особый режим — loopback: обычно пользовательские настройки берутся из политик, привязанных к OU пользователя; на терминальных серверах и киосках нужно, чтобы они брались из OU компьютера. Настройка «Configure user Group Policy loopback processing mode» (Computer Configuration → Administrative Templates → System → Group Policy) в режиме Replace берёт для пользователя только политики компьютера, в режиме Merge — дописывает их после пользовательских, и при конфликте выигрывают они. Режим клиент записывает в журнал событием 5311.
Как клиент применяет
Служба Group Policy Client (gpsvc) на каждой машине домена:
- При загрузке — политики компьютера, при входе пользователя — его политики; затем в фоне каждые 90 минут со случайным сдвигом до 30 (на контроллерах — каждые 5). Фоновое обновление с Windows 8 и Server 2012 запускается задачей планировщика, и, судя по журналу, сдвиг выбирается один раз при старте службы: на рабочей станции события фонового обновления идут ровно через 105 минут, после перезагрузки — ровно через 106.
- Находит контроллер (событие 5308 в журнале) и запрашивает у него по LDAP
gPLinkиgPOptionsсвоего сайта, домена и цепочки OU до своего объекта; для каждой найденной политики — её контейнер: версию, флаги, список расширений, права, WMI-фильтр. - Отбрасывает отключённые, не прошедшие фильтры и пустые для этой половины (версия 0); расширение, у которого не поменялись ни политики, ни их список, свои настройки повторно не применяет.
- Для оставшихся читает файлы из SYSVOL по SMB — по пути из
gPCFileSysPath, через пространство DFS\\corp.example.com\SYSVOL, которое отдаёт ссылки на контроллеры, начиная со своего сайта. - Передаёт каждому расширению из списка его файлы, и расширения применяют настройки: реестр пишет в
HKLM\SOFTWARE\PoliciesиHKCU\SOFTWARE\Policies, параметры безопасности применяет движокsecedit, предпочтения создают диски и задачи.
В фоне применяется не всё: установка программ — только при загрузке или входе, перенаправление папок — при входе, сценарии запускаются при загрузке, выключении, входе и выходе. Если такому расширению есть что применить, оно пишет событие 1112 (нужна перезагрузка или новый вход), а gpupdate предлагает перезагрузиться или выйти. На медленном канале (по умолчанию меньше 500 кбит/с, событие 5314 с оценкой) реестр и безопасность применяются всегда, а установка программ, перенаправление папок и сценарии — нет. С Windows 8.1 и Server 2012 R2 клиент сохраняет полученные политики в локальное хранилище (событие 5216), и при синхронной обработке на следующей загрузке читает их оттуда, а не с контроллера; это управляется настройкой «Configure Group Policy Caching».
Два слова о tattooing. Настройки административных шаблонов пишутся в ветки Policies реестра, которые приложения читают первыми; когда политика перестаёт действовать, клиент эти ключи удаляет, и настройка возвращается к умолчанию. Предпочтения и часть параметров безопасности пишут в обычные ключи, и после снятия политики значение остаётся — «татуировка». Это не ошибка, а свойство, о котором нужно помнить, снимая политику.
Виды настроек
| Раздел | Где хранится | Что |
|---|---|---|
| Административные шаблоны | Registry.pol |
тысячи настроек Windows и приложений, описанных файлами ADMX; результат — ключи в Policies |
| Параметры безопасности | GptTmpl.inf |
политика учётных записей (действует только из политик корня домена), права пользователей, аудит, ограниченные группы, службы, ACL на реестр и файлы, файрвол, AppLocker |
| Сценарии | Scripts\ |
запуск при загрузке, выключении, входе, выходе; PowerShell или любые |
| Установка программ | каталог и MSI на общей папке | назначение и публикация MSI; устаревает, но работает |
| Перенаправление папок | каталог | Documents и Desktop на сервер |
| Предпочтения (Group Policy Preferences, GPP) | Preferences\*.xml |
сетевые диски, принтеры, ярлыки, файлы, ключи реестра, локальные пользователи и группы, задачи планировщика, переменные среды — с нацеливанием на уровне элемента по десяткам условий (группа, ОС, IP, время, существование файла) и без татуировки, если отметить «Remove this item when it is no longer applied» |
Предпочтения тоже записываются в gPCMachineExtensionNames: у политики с предпочтением реестра там [{B087BE9D-…}{BEE07A6A-…}] — расширение Group Policy Registry и его компонент редактора. Редактор вдобавок пишет запись с нулевым GUID расширения, [{00000000-0000-0000-0000-000000000000}{BEE07A6A-…}], в которой перечисляет свои компоненты, — у политик, собранных командами, её может не быть.
Административные шаблоны описываются файлами ADMX (структура) и ADML (строки на языке, по папке на язык: en-US, ru-RU), и у каждой версии Windows они свои. Редактор берёт их с локальной машины, если в домене нет Central Store — папки PolicyDefinitions в SYSVOL, откуда их читают все редакторы домена. В свежем домене её нет:
PS C:\> $store = '\\corp.example.com\SYSVOL\corp.example.com\Policies\PolicyDefinitions'
PS C:\> Test-Path $store
False
PS C:\> (Get-ChildItem C:\Windows\PolicyDefinitions -Filter *.admx).Count
225
На Windows 11 25H2 локально 225 шаблонов. Создают хранилище копированием всей папки C:\Windows\PolicyDefinitions с самой новой Windows в домене (или из пакета Administrative Templates, который Microsoft выпускает к каждой версии):
PS C:\> Copy-Item C:\Windows\PolicyDefinitions -Destination $store -Recurse
При обновлении Microsoft советует собирать новую папку с другим именем (PolicyDefinitions-25H2), добавлять туда шаблоны Office, Edge, Chrome от производителей и только потом переименовывать её в PolicyDefinitions, а старую оставить для отката: файлы разных версий, скопированные поверх друг друга, дают ошибки в редакторе.
Фильтры
Привязка к OU — первый фильтр. Второй — права: политику применяют только те, у кого на её контейнере есть Read и Apply Group Policy. По умолчанию это Authenticated Users:
PS C:\> Get-GPPermission -Name 'DC - PDC Time Source' -All | Format-Table @{n='Trustee'; e={$_.Trustee.Name}}, @{n='Type'; e={$_.Trustee.SidType}}, Permission, Denied, Inherited -AutoSize
Trustee Type Permission Denied Inherited
------- ---- ---------- ------ ---------
Authenticated Users WellKnownGroup GpoApply False False
Domain Admins Group GpoEditDeleteModifySecurity False False
Enterprise Admins Group GpoEditDeleteModifySecurity False False
ENTERPRISE DOMAIN CONTROLLERS WellKnownGroup GpoRead False False
SYSTEM WellKnownGroup GpoEditDeleteModifySecurity False False
Чтобы политика действовала на одну группу, Apply у Authenticated Users забирают и выдают этой группе. С обновлением безопасности 2016 года (MS16-072) компьютер читает политики пользователя своей учётной записью, и если у Authenticated Users забрать и Read, пользовательские политики перестанут применяться совсем. Поэтому Authenticated Users понижают до чтения, а не убирают (или выдают Read группе Domain Computers). Set-GPPermission без -Replace более высокий уровень не понижает — молча оставляет прежний:
PS C:\> Set-GPPermission -Name 'Sales - Drive Maps' -TargetName 'Authenticated Users' -TargetType Group -PermissionLevel GpoRead -Replace
PS C:\> Set-GPPermission -Name 'Sales - Drive Maps' -TargetName 'Sales' -TargetType Group -PermissionLevel GpoApply
Оба вызова возвращают объект политики. Без -Server командлеты модуля обращаются к PDC.
Третий — WMI-фильтр: запрос WQL к машине, и политика применяется, если он вернул хоть что-то. Классические: SELECT * FROM Win32_OperatingSystem WHERE ProductType = 2 — контроллеры домена; SELECT * FROM Win32_ComputerSystem WHERE DomainRole = 5 — владелец PDC; SELECT * FROM Win32_OperatingSystem WHERE Version LIKE "10.0.2%" — по версии. Запрос выполняется на клиенте при каждой обработке, и медленный запрос замедляет загрузку. Фильтр — объект класса msWMI-Som в CN=SOM,CN=WMIPolicy,CN=System, к политике его привязывает атрибут gPCWQLFilter её контейнера; у одной политики не больше одного фильтра, один фильтр — на сколько угодно политик. Командлета для создания фильтров в модуле нет, только оснастка или запись в каталог напрямую, как в примере ниже. У предпочтений свой, более удобный механизм — нацеливание на уровне элемента, и там, где можно, фильтруют им.
Модуль GroupPolicy
Команды для всего, что выше:
Get-GPO -All; Get-GPO -Name 'Servers - Baseline' # объекты
New-GPO -Name 'X' -Comment '…'; Remove-GPO; Rename-GPO; Copy-GPO # создание
New-GPLink -Name 'X' -Target 'OU=Servers,DC=corp,DC=example,DC=com' -LinkEnabled Yes -Order 1 -Enforced No
Set-GPLink -Name 'X' -Target '…' -Enforced Yes; Remove-GPLink
Get-GPInheritance -Target '…'; Set-GPInheritance -Target '…' -IsBlocked Yes
Set-GPRegistryValue -Name 'X' -Key 'HKLM\SOFTWARE\Policies\…' -ValueName 'V' -Type DWord -Value 1 # административные шаблоны по ключу
Get-GPRegistryValue -Name 'X' -Key 'HKLM\SOFTWARE\Policies\…'
Set-GPPrefRegistryValue -Name 'X' -Context Computer -Action Update -Key '…' -ValueName 'V' -Type String -Value 'a' # предпочтение реестра
Set-GPPermission -Name 'X' -TargetName 'Helpdesk' -TargetType Group -PermissionLevel GpoEdit
Get-GPOReport -Name 'X' -ReportType Html -Path .\X.html; Get-GPOReport -All -ReportType Xml
Backup-GPO -All -Path D:\GPOBackup; Restore-GPO -Name 'X' -Path D:\GPOBackup
Import-GPO -BackupGpoName 'X' -Path D:\GPOBackup -TargetName 'X' -CreateIfNeeded -MigrationTable .\map.migtable # в другой домен
Get-GPResultantSetOfPolicy -Computer ws1 -User CORP\alice -ReportType Html -Path .\rsop.html
Invoke-GPUpdate -Computer ws1 -RandomDelayInMinutes 0 -Force # удалённый gpupdate через задачу планировщика (с 2012)
Invoke-GPUpdate не подключается к машине по WinRM: он создаёт на ней задачу планировщика, которая запускает gpupdate. Для этого на машине должны быть открыты правила Remote Scheduled Tasks Management (RPC и RPC-EPMAP) и Windows Management Instrumentation (WMI-In); у серверов они по умолчанию выключены (часть 15), и тогда проще Invoke-Command dc1 { gpupdate /target:computer }. -Force у командлета по документации только отключает запрос подтверждения.
Get-GPOReport -ReportType Xml отдаёт политику целиком: имя, время создания и изменения, дескриптор безопасности, имя и описание WMI-фильтра, версии обеих частей (VersionDirectory и VersionSysvol), для каждой настройки административного шаблона — её имя в редакторе, состояние и текст справки, и в конце — куда политика привязана (LinksTo).
Чего в модуле нет: настройки параметров безопасности (GptTmpl.inf — текстовый INI, его правят редактором или копируют из эталонной политики через Import-GPO), сценарии, предпочтения кроме реестра (их XML можно положить в папку политики руками и добавить GUID расширения в gPCMachineExtensionNames, но это уже внутренности), WMI-фильтры.
Политика для PDC
Обещанное в части 12: источник времени, который следует за ролью PDC. Три части — WMI-фильтр на роль, политика с настройками W32Time, привязка к OU контроллеров. Сначала фильтр — объект в каталоге, без командлета:
PS C:\> $domain = Get-ADDomain
PS C:\> $id = '{' + (New-Guid).Guid.ToUpper() + '}'
PS C:\> $now = (Get-Date).ToUniversalTime().ToString('yyyyMMddHHmmss.ffffff') + '-000'
PS C:\> $query = 'SELECT * FROM Win32_ComputerSystem WHERE DomainRole = 5'
PS C:\> $attrs = @{
'msWMI-Name' = 'PDC emulator'
'msWMI-Parm1' = 'Domain controller holding the PDC emulator role (DomainRole = 5)'
'msWMI-Parm2' = "1;3;10;$($query.Length);WQL;root\CIMv2;$query;"
'msWMI-ID' = $id
'msWMI-Author' = 'alice.admin@corp.example.com'
'msWMI-CreationDate' = $now
'msWMI-ChangeDate' = $now
'instanceType' = 4
'showInAdvancedViewOnly' = $true
}
PS C:\> New-ADObject -Name $id -Type 'msWMI-Som' -Path "CN=SOM,CN=WMIPolicy,CN=System,$($domain.DistinguishedName)" -OtherAttributes $attrs -PassThru
msWMI-Parm2 — строка с версией формата, числом запросов, длиной запроса, языком, пространством имён и самим запросом. Затем политика: десять значений в ветке Policies\Microsoft\W32Time — ровно то, что пишут административные шаблоны Configure Windows NTP Client, Enable Windows NTP Client, Enable Windows NTP Server и AnnounceFlags из Global Configuration Settings:
PS C:\> $gpo = New-GPO -Name 'DC - PDC Time Source' -Comment 'PDC emulator of the forest root syncs from pool.ntp.org and announces itself as a reliable time source; WMI filter "PDC emulator" makes the setting follow the role.'
PS C:\> $w = 'HKLM\SOFTWARE\Policies\Microsoft\W32Time'
PS C:\> $values = @(
@{ Key = "$w\Parameters"; ValueName = 'NtpServer'; Type = 'String'; Value = '0.pool.ntp.org,0x8 1.pool.ntp.org,0x8 2.pool.ntp.org,0x8 3.pool.ntp.org,0x8' }
@{ Key = "$w\Parameters"; ValueName = 'Type'; Type = 'String'; Value = 'NTP' }
@{ Key = "$w\Config"; ValueName = 'AnnounceFlags'; Type = 'DWord'; Value = 5 }
@{ Key = "$w\TimeProviders\NtpClient"; ValueName = 'Enabled'; Type = 'DWord'; Value = 1 }
@{ Key = "$w\TimeProviders\NtpClient"; ValueName = 'CrossSiteSyncFlags'; Type = 'DWord'; Value = 2 }
@{ Key = "$w\TimeProviders\NtpClient"; ValueName = 'ResolvePeerBackoffMinutes'; Type = 'DWord'; Value = 15 }
@{ Key = "$w\TimeProviders\NtpClient"; ValueName = 'ResolvePeerBackoffMaxTimes'; Type = 'DWord'; Value = 7 }
@{ Key = "$w\TimeProviders\NtpClient"; ValueName = 'SpecialPollInterval'; Type = 'DWord'; Value = 1024 }
@{ Key = "$w\TimeProviders\NtpClient"; ValueName = 'EventLogFlags'; Type = 'DWord'; Value = 0 }
@{ Key = "$w\TimeProviders\NtpServer"; ValueName = 'Enabled'; Type = 'DWord'; Value = 1 }
)
PS C:\> foreach ($v in $values) { Set-GPRegistryValue -Guid $gpo.Id @v | Select-Object DisplayName, @{n='Computer'; e={$_.Computer.DSVersion}} }
Каждый вызов — одно сохранение компьютерной части, так что после десяти версия станет 10. Ключи под Policies\Microsoft\W32Time — это те же параметры, что w32tm /config писал в Services\W32Time, но заданные политикой: они имеют приоритет и исчезают, когда политика перестаёт действовать. Get-GPOReport показывает такие значения как настройки соответствующих шаблонов, а не как «лишние» значения реестра.
Связь с фильтром и привязка:
PS C:\> Set-ADObject "CN=$($gpo.Id.ToString('B').ToUpper()),CN=Policies,CN=System,$($domain.DistinguishedName)" -Replace @{ gPCWQLFilter = "[$($domain.DNSRoot);$id;0]" }
PS C:\> New-GPLink -Guid $gpo.Id -Target "OU=Domain Controllers,$($domain.DistinguishedName)" -LinkEnabled Yes
PS C:\> Get-GPO -Guid $gpo.Id | Select-Object DisplayName, @{n='WmiFilter'; e={$_.WmiFilter.Name}}, GpoStatus
DisplayName WmiFilter GpoStatus
----------- --------- ---------
DC - PDC Time Source PDC emulator AllSettingsEnabled
Без вычисляемой колонки Select-Object WmiFilter покажет в таблице имя типа Microsoft.GroupPolicy.WmiFilter, а не фильтра: у объекта фильтра есть свойства Name, Description и Path. Сам фильтр в каталоге:
PS C:\> Get-ADObject -SearchBase 'CN=SOM,CN=WMIPolicy,CN=System,DC=corp,DC=example,DC=com' -Filter 'objectClass -eq "msWMI-Som"' -Properties msWMI-Name, msWMI-Parm2, msWMI-CreationDate |
Format-List msWMI-Name, msWMI-Parm2, msWMI-CreationDate
msWMI-Name : PDC emulator
msWMI-Parm2 : 1;3;10;55;WQL;root\CIMv2;SELECT * FROM Win32_ComputerSystem WHERE DomainRole = 5;
msWMI-CreationDate : 20261025082704.247764-000
На dc2, у которого DomainRole = 4 (контроллер без роли PDC), фильтр вернёт пустой результат, политика не применится, и он останется в иерархии домена. Когда роль переедет, на следующем обновлении политики (у контроллеров — через пять минут) новый PDC получит внешний источник, а со старого ключи Policies снимутся, и он вернётся к своим локальным настройкам. Поэтому на самих контроллерах локальную конфигурацию W32Time оставляют по умолчанию (NT5DS): тогда второй политики для остальных контроллеров не нужно. Проверить итог на PDC — Invoke-Command dc1 { w32tm /query /source } после обновления политики (Invoke-Command dc1 { gpupdate /target:computer }).
Резервная копия после изменения — привычка из части 20:
PS C:\> Backup-GPO -Guid $gpo.Id -Path D:\GPOBackup -Comment 'PDC time source' | Select-Object DisplayName, GpoId, Id, BackupDirectory
gpupdate и gpresult
На клиенте: gpupdate применяет изменившиеся политики, gpupdate /force — все, /target:computer или /target:user — только одну часть, /boot и /logoff — с перезагрузкой или выходом, если расширения этого требуют, /wait:<секунды> — сколько ждать (по умолчанию 600). Обновить только свою пользовательскую часть можно без повышения прав:
PS C:\> gpupdate /target:user
Updating policy...
User Policy update has completed successfully.
Что в итоге применилось — gpresult. Без повышения прав он видит только пользовательскую часть; gpresult /r без /scope молча её одну и покажет, а gpresult /r /scope:computer ответит «ERROR: Access Denied.» — компьютерную часть смотрят из консоли «от имени администратора». Пользовательская часть на ws1 (начало вывода gpresult /r /scope:user, без шапки и списка групп):
RSOP data for CORP\alice on WS1 : Logging Mode
---------------------------------------------------------------
OS Configuration: Member Workstation
OS Version: 10.0.26200
Site Name: N/A
Roaming Profile: N/A
Local Profile: C:\Users\alice
Connected over a slow link?: No
USER SETTINGS
--------------
CN=Alice Smith,OU=Sales,OU=People,DC=corp,DC=example,DC=com
Last time Group Policy was applied: 29.10.2026 at 15:41:11
Group Policy was applied from: dc1.corp.example.com
Group Policy slow link threshold: 500 kbps
Domain Name: CORP
Domain Type: Windows 2008 or later
Applied Group Policy Objects
-----------------------------
Users - Intranet Zone
The following GPOs were not applied because they were filtered out
-------------------------------------------------------------------
Local Group Policy
Filtering: Not Applied (Empty)
Default Domain Policy и Time - No Hyper-V Sync тоже привязаны к домену, но пользовательская часть у них пустая, и в этом списке их нет вовсе. Дальше в выводе идёт список групп пользователя, по которому проверялись права на политики. В компьютерной части тот же отчёт перечисляет политики, отсеянные фильтрами, с причиной: Denied (Security) — нет прав, Denied (WMI Filter) — фильтр вернул пустой результат, Disabled (Link) — привязка отключена.
gpresult /h report.html даёт тот же отчёт с каждой настройкой и политикой, из которой она пришла, — главный инструмент для «почему у этой машины такая настройка»; gpresult /x — то же в XML. Путь к файлу у обоих ключей не длиннее 127 символов, иначе «ERROR: Value for '…' option cannot be more than 127 character(s).». Get-GPResultantSetOfPolicy делает отчёт для удалённой машины, и ему нужны открытые на ней правила Remote Event Log Management и WMI-In.
Итог каждой обработки клиент пишет в журнал System: 1500 и 1501 — политики компьютера и пользователя обработаны, изменений нет; 1502 и 1503 — обнаружены и применены новые настройки N политик. Подробный протокол каждого цикла — в журнале Microsoft-Windows-GroupPolicy/Operational, читать его можно только с повышенными правами:
| События | Что |
|---|---|
| 4000, 4001 / 8000, 8001 | начало и конец обработки при загрузке и при входе |
| 4004, 4005 / 8004, 8005 | ручная обработка (gpupdate) компьютера и пользователя |
| 4006, 4007 / 8006, 8007 | фоновая обработка |
| 5308, 5326 | какой контроллер найден и за сколько |
| 5311, 5314 | режим loopback, оценка канала и порог медленного |
| 5312, 5313 | список применяемых политик и отсеянных фильтрами |
| 4016 / 5016, 7016 | начало обработки расширения со списком политик, её успешный или неудачный конец со временем |
| 5315 | когда будет следующая обработка |
Ошибки в журнале System: 1058 — не удалось прочитать gpt.ini политики из SYSVOL (разрешение имени и связь с контроллером, задержка репликации SYSVOL, отключённый клиент DFS — сам текст перечисляет эти причины); 1030 — не удалось получить новые настройки, код ошибки — на вкладке подробностей, обычно идёт в паре с 1058; 1129 — нет связи с контроллером; 1053 и 1055 — не удалось определить имя пользователя или компьютера (разрешение имён на контроллере, задержка репликации, защищённый канал); 1006 — не удалась привязка LDAP к контроллеру; 1096 — не удалось применить Registry.pol конкретной политики. Настоящее 1058 на рабочей станции:
PS C:\> (Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Microsoft-Windows-GroupPolicy'; Id=1058} -MaxEvents 1).Message
The processing of Group Policy failed. Windows attempted to read the file \\corp.example.com\SysVol\corp.example.com\Policies\{3C5D6E7F-8091-4A2B-B3C4-D5E6F7081920}\gpt.ini from a domain controller and was not successful. Group Policy settings may not be applied until this event is resolved. This issue may be transient and could be caused by one or more of the following:
a) Name Resolution/Network Connectivity to the current domain controller.
b) File Replication Service Latency (a file created on another domain controller has not replicated to the current domain controller).
c) The Distributed File System (DFS) client has been disabled.
Одиночные 1058 на свежей политике — обычно SYSVOL контроллера, до которого изменение ещё не дошло, и gpresult строкой «applied from» скажет, какого. Бывает и так, что 1058 сыплются раз в пять минут на самом контроллере при здоровых SYSVOL и DNS: так ведёт себя виртуальный контроллер после переподключения его сетевого адаптера на гипервизоре, и лечится это перезагрузкой. Журнал Operational маленький и на контроллере перезаписывается быстрее чем за сутки — разбирать сбой нужно сразу.
Смотрим руками
Политика для PDC из примера, собранная в домене такими же командами. Её файлы в SYSVOL — только то, во что что-то записано:
PS C:\> $g = Get-GPO -Name 'DC - PDC Time Source'
PS C:\> $root = "\\corp.example.com\SYSVOL\corp.example.com\Policies\$($g.Id.ToString('B').ToUpper())"
PS C:\> Get-ChildItem $root -Recurse -File | Select-Object @{n='File'; e={$_.FullName.Substring($root.Length + 1)}}, Length
File Length
---- ------
GPO.cmt 328
GPT.INI 23
Machine\Registry.pol 1816
PS C:\> Get-Content "$root\GPT.INI"
[General]
Version=10
PS C:\> $g.Computer | Select-Object DSVersion, SysvolVersion, Enabled
DSVersion SysvolVersion Enabled
--------- ------------- -------
10 10 True
PS C:\> $g | Select-Object CreationTime, ModificationTime
CreationTime ModificationTime
------------ ----------------
25.10.2026 11:27:21 25.10.2026 11:27:34
Десять сохранений за 13 секунд — версия 10. GPO.cmt — комментарий из New-GPO -Comment, модуль показывает его свойством Description. Версия в каталоге и в GPT.INI на каждом контроллере — если где-то меньше, изменение туда ещё не дошло, и клиенты, которые обращаются к этому контроллеру, применят политику позже:
PS C:\> $id = $g.Id.ToString('B').ToUpper()
PS C:\> 'dc1','dc2','dc3','dc4' | ForEach-Object {
[pscustomobject]@{
DC = $_
DS = (Get-ADObject "CN=$id,CN=Policies,CN=System,DC=corp,DC=example,DC=com" -Server $_ -Properties versionNumber).versionNumber
Sysvol = (Select-String -Path "\\$_\SYSVOL\corp.example.com\Policies\$id\GPT.INI" -Pattern '^Version=(\d+)').Matches.Groups[1].Value
}
} | Format-Table -AutoSize
DC DS Sysvol
-- -- ------
dc1 10 10
dc2 10 10
dc3 10 10
dc4 10 10
Что лежит в Registry.pol — через модуль, который его разбирает:
PS C:\> Get-GPRegistryValue -Name 'DC - PDC Time Source' -Key 'HKLM\SOFTWARE\Policies\Microsoft\W32Time\Parameters' | Format-Table ValueName, Type, Value -AutoSize
ValueName Type Value
--------- ---- -----
NtpServer String 0.pool.ntp.org,0x8 1.pool.ntp.org,0x8 2.pool.ntp.org,0x8 3.pool.ntp.org,0x8
Type String NTP
Какие контейнеры клиент перебрал для пользователя и в каком порядке — в XML-отчёте gpresult. Это и есть цепочка LSDOU, записанная самим клиентом:
PS C:\Temp> gpresult /scope:user /x rsop.xml /f
PS C:\Temp> $x = [xml](Get-Content .\rsop.xml)
PS C:\Temp> $x.Rsop.UserResults.SearchedSOM | Sort-Object { [int]$_.Order } | Format-Table Order, Type, Path, BlocksInheritance
Order Type Path BlocksInheritance
----- ---- ---- -----------------
1 Local Local false
2 Site corp.example.com/Configuration/Sites/Office false
3 Domain corp.example.com false
4 OU corp.example.com/People false
5 OU corp.example.com/People/Sales false
PS C:\Temp> $x.Rsop.UserResults.ExtensionStatus | Format-Table Name, BeginTime, EndTime, Error -AutoSize
Name BeginTime EndTime Error
---- --------- ------- -----
Group Policy Infrastructure 2026-10-29T12:41:11 2026-10-29T12:41:11 0
Registry 2026-10-18T15:33:42 2026-10-18T15:33:42 0
Инфраструктура отработала только что (время в UTC), а расширение реестра последний раз применяло настройки 18 октября — когда изменилась единственная пользовательская политика. С тех пор ни политики, ни их список не менялись, и расширение каждый цикл пропускает. Фоновые циклы компьютера в журнале System:
PS C:\> Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Microsoft-Windows-GroupPolicy'; Id=1500} -MaxEvents 6 | Format-Table TimeCreated, Id
TimeCreated Id
----------- --
29.10.2026 14:24:05 1500
29.10.2026 12:38:06 1500
29.10.2026 10:52:06 1500
29.10.2026 9:06:05 1500
29.10.2026 7:20:05 1500
29.10.2026 4:31:31 1500
Между 4:31 и 7:20 машина перезагрузилась; после этого циклы идут ровно через 1 час 46 минут — 90 минут и сдвиг в 16, который не меняется до следующей перезагрузки.
Источники
Устройство политики и порядок применения:
- Group Policy overview — что такое GPO, GPC и GPT, расширения клиента;
- Group Policy processing — LSDOU, принудительные привязки и блокировка наследования, loopback, интервалы обновления (90 минут со сдвигом до 30, пять минут на контроллерах), что не применяется в фоне;
- Group Policy scope — формат
gPLink, флаги привязки, порядок записей в строке, фильтрация правами и WMI; - [MS-GPOL]: Group Policy: Core Protocol и Sample gpt.ini File — спецификация: контейнер и шаблон политики,
versionNumberиз двух 16-битных половин,gPCMachineExtensionNames,flags,gPCWQLFilter,gpt.ini; - Loopback processing of Group Policy — режимы Merge и Replace;
- What's New in Group Policy in Windows Server — кеширование политик, фоновое обновление задачей планировщика,
Invoke-GPUpdate, состояние инфраструктуры; - Group Policy Preferences — предпочтения и нацеливание на уровне элемента;
- dcgpofix — восстановление двух политик по умолчанию и что в них хранить.
Фильтры и права:
- MS16-072: Security update for Group Policy и Deploying Group Policy Security Update MS16-072 — чтение пользовательских политик учётной записью компьютера и права Read;
- ms-WMI-Som class — класс объекта WMI-фильтра в каталоге;
- Configuring Account Policies — политика учётных записей действует из политик домена.
Административные шаблоны:
- Create and manage the Central Store — ADMX и ADML, путь Central Store, порядок обновления с новой папкой.
Модуль GroupPolicy и утилиты:
- GroupPolicy module — все командлеты модуля;
- Get-GPInheritance, New-GPLink и Set-GPRegistryValue — наследование, привязка, значения реестра;
- Set-GPPermission — уровни прав и
-Replace; - Invoke-GPUpdate — удалённое обновление через задачу планировщика и нужные правила файрвола;
- Get-GPOReport и Backup-GPO — отчёт и резервная копия;
- gpupdate и gpresult — ключи обеих утилит.
Время и диагностика:
- Windows Time service tools and settings — параметры W32Time и их значения в групповой политике;
- Applying Group Policy troubleshooting guidance — порядок разбора, журналы и события клиента.
Политики настроили машины. Следующий блок — о том, как машины и люди доказывают, кто они, не паролем, а сертификатом, и о том, кто эти сертификаты выдаёт.
Дальше — часть 25: удостоверяющий центр AD CS. Зачем своя инфраструктура открытых ключей и как устроена двухуровневая иерархия с отключённым корнем; установка корневого и выпускающего центров командами ADCSDeployment; шаблоны сертификатов и их права; автозачисление через групповую политику; списки отзыва, точки их распространения и OCSP; и что из части 23 сетевой серии про TLS здесь работает, а что устроено иначе.
Оставить комментарий могут только зарегистрированные пользователи.
Войдите на сайт или зарегистрируйтесь, чтобы оставить комментарий.