AD 组策略继承与优先级
AD 组策略继承与优先级
同一台域成员服务器可以同时命中父 OU、子 OU 和同一容器中的多个 GPO。看到所有 GPO 都出现在应用列表里,仍然无法判断同一个设置最终由谁决定;开启阻止继承以后,也可能继续收到父级策略。排查时要把三个问题分开:策略是否进入候选列表、链接之间如何处理冲突、客户端最终写入了什么值。
这次在 Windows Server 2022 Datacenter 的 LAB-DC1 和 LAB-MEMBER 上做对照,使用隔离域 corp.test.checo.cc 对同一组无害注册表标记进行四组串行对照。域控 Windows PowerShell 为 5.1.20348.5386,成员机系统为 10.0.20348。域控地址为 10.77.77.10,成员机为 10.77.77.20,同时保留 IPv6 ULA。计算机策略由成员机本地 SYSTEM 刷新,域控设置动作通过域控 SYSTEM 执行。
实验结构如下,计算机对象临时位于 Child,结束后移回原 Computers 容器。
DC=corp,DC=test,DC=checo,DC=cc
└─ OU=KB-Lab-20261009
└─ OU=Parent ← KB-GPO-221-Parent
└─ OU=Child ← KB-GPO-221-ChildA / KB-GPO-221-ChildB
└─ CN=LAB-MEMBER三个 GPO 都配置 HKLM\Software\Policies\KB-GPO-221\Winner,值分别为 Parent、ChildA、ChildB。父 GPO 另配置 ParentOnly=InheritedParent,用于区分父策略被覆盖和父策略完全没有应用。初始注册表键不存在,三个专属 GPO 和三层实验 OU 也不存在。
这里不改默认域策略。一个冲突值用来判断谁胜出,另一个父级独有值用来判断父策略是否还在应用;把两者放在一起,才能看出继承实际发生了什么。
1. 覆盖与排除
1.1 比较冲突项与独有项
四组实验覆盖了下面六种链接状态。每组开始和结束都恢复无实验链接、无阻止继承、无实验 marker 的基线,再执行计算机策略刷新及回读。
| 对照 | Winner 实际值 | ParentOnly 实际值 | 说明 |
|---|---|---|---|
| 父与子均为普通链接 | ChildA | InheritedParent | 子覆盖冲突值,父独有设置仍应用 |
| ChildA order 1,ChildB order 2 | ChildA | InheritedParent | 同容器编号较小的链接优先 |
| ChildB 改为 order 1 | ChildB | InheritedParent | 顺序反转改变最终值 |
| Child 阻止继承,父普通链接 | ChildA | 缺失 | 子直接链接保留,父设置被排除 |
| 父链接 Enforced,Child 正常继承 | Parent | InheritedParent | 强制父链接覆盖子冲突 |
| 父链接 Enforced,Child 阻止继承 | Parent | InheritedParent | 阻止继承仍挡不住该强制父链接 |
正常继承时,成员机回读为:
{
"Winner": "ChildA",
"ParentOnly": "InheritedParent",
"SecureChannel": true,
"MarkerKeyExists": true
}这两个值共同说明,父 GPO 并没有因为子 GPO 胜出而整份失效。冲突针对具体设置处理,父级未被覆盖的设置可以继续生效。
一般处理顺序为本地、站点、域、父 OU、子 OU,也称 LSDOU。本次实际改变的是父子 OU 和同 OU 链接,没有改动本地或站点策略。普通父子冲突的观察与这一顺序一致;同一 OU 的链接顺序另按较小编号优先处理,order 1 的优先级高于 order 2。
1.2 阻止继承与强制
Block Inheritance 是容器属性,Enforced 是链接属性。阻止继承设置在 Child 上时,Child 直接链接的 ChildA 继续应用,普通父链接及默认域策略则未应用。
真实 gpresult 输出为:
Applied Group Policy Objects
-----------------------------
KB-GPO-221-ChildA
The following GPOs were not applied because they were filtered out
-------------------------------------------------------------------
KB-GPO-221-Parent
Filtering: Not Applied (Unknown Reason)
Default Domain Policy
Filtering: Not Applied (Unknown Reason)工具这里显示 Unknown Reason,因此要结合域控回读的 GpoInheritanceBlocked 和成员机 ParentOnly 缺失判断原因,而不是把它解释成安全筛选拒绝。它是本次观察到的未应用输出;策略刷新本身没有报错,也没有遇到命令执行失败。
父链接开启 Enforced 后,父冲突值胜出;在同样的强制链接上增加 Child 阻止继承,仍得到 Parent 和 InheritedParent。其机制是较高层级的强制链接阻止较低层级覆盖,并穿过下级容器的阻止继承。它不是脱离链接位置的通用最高优先级开关。本次没有对多个强制链接、安全筛选或 WMI 条件进行实验。
2. 链接与继承对照
2.1 保存恢复基线
在 LAB-DC1 管理员 PowerShell 中导入模块,显式指定实验域控和域。进入任何写入步骤前核验域名和 SID,避免默认域选择错误。
$ErrorActionPreference = 'Stop'
Import-Module ActiveDirectory
Import-Module GroupPolicy
$dc = 'LAB-DC1.corp.test.checo.cc'
$domain = 'corp.test.checo.cc'
$d = Get-ADDomain -Server $dc
$d | Select-Object DNSRoot,DomainSID
$base = $d.DistinguishedName
$root = 'OU=KB-Lab-20261009,' + $base
$parent = 'OU=Parent,' + $root
$child = 'OU=Child,' + $parent
$c = Get-ADComputer LAB-MEMBER -Server $dc
$c | Select-Object DistinguishedName,ObjectGUID
$originalDN = $c.DistinguishedName
$computerGUID = $c.ObjectGUID
$backup = 'C:\KB-GPO-221\initial-backup'
New-Item -ItemType Directory -Path $backup -Force | Out-Null
Backup-GPO -All -Path $backup -Domain $domain -Server $dc
Get-ADOrganizationalUnit -Filter * -Server $dc -Properties gPLink,gPOptions |
Select-Object DistinguishedName,ObjectGUID,gPLink,gPOptions实测域 SID 为 S-1-5-21-3628476133-752301219-3504167884,LAB-MEMBER 对象 GUID 为 27512149-7cc9-4b2e-8297-be529978e6c3,原 DN 为 CN=LAB-MEMBER,CN=Computers,DC=corp,DC=test,DC=checo,DC=cc。
在成员机上记录原键是否存在和各值内容。本次键不存在,恢复判据就是刷新后该键再次不存在。若环境中键已存在,应选用新的专属键,避免覆盖旧值。
Test-Path 'HKLM:\Software\Policies\KB-GPO-221'恢复顺序在创建前确定:先清除本次链接和继承变更,刷新并确认标记消失;再把计算机移回原容器,精确删除本次 GPO 和已空的实验 OU。每组结束执行前半段恢复,以便下一组重新从同一状态开始。最终恢复再执行对象清理,保留备份与日志。
2.2 创建 OU 与 GPO
下列命令在 LAB-DC1 执行,目标 OU 应尚不存在。记录创建返回的 GUID,后续通过 GUID 识别本次资源。实验不修改默认 GPO,也不向域根或 Domain Controllers OU 添加链接。
New-ADOrganizationalUnit -Name 'KB-Lab-20261009' -Path $base -ProtectedFromAccidentalDeletion $false -Server $dc
New-ADOrganizationalUnit -Name 'Parent' -Path $root -ProtectedFromAccidentalDeletion $false -Server $dc
New-ADOrganizationalUnit -Name 'Child' -Path $parent -ProtectedFromAccidentalDeletion $false -Server $dc
$ids = @{}
foreach ($name in @('Parent','ChildA','ChildB')) {
$g = New-GPO -Name ('KB-GPO-221-' + $name) -Domain $domain -Server $dc
$ids[$name] = $g.Id
Set-GPRegistryValue -Guid $g.Id -Key 'HKLM\Software\Policies\KB-GPO-221' -ValueName 'Winner' -Type String -Value $name -Domain $domain -Server $dc
}
Set-GPRegistryValue -Guid $ids.Parent -Key 'HKLM\Software\Policies\KB-GPO-221' -ValueName 'ParentOnly' -Type String -Value 'InheritedParent' -Domain $domain -Server $dc
Move-ADObject -Identity $computerGUID -TargetPath $child -Server $dc这里使用 Policies 下的注册表策略值,而不是随意创建的业务应用设置。三个字符串不驱动服务或安全功能,适合在同一个键上观察冲突。
2.3 执行四组对照
每次更改链接之前,重新备份 GPO,并导出 Get-GPInheritance。链接及容器属性不包含在 GPO 内容备份中,需要另外保留其目标、顺序、Enabled、Enforced 和阻止继承状态。
第一组只链接 Parent 和 ChildA,两者都启用且不强制:
New-GPLink -Guid $ids.Parent -Target $parent -LinkEnabled Yes -Enforced No -Order 1 -Domain $domain -Server $dc
New-GPLink -Guid $ids.ChildA -Target $child -LinkEnabled Yes -Enforced No -Order 1 -Domain $domain -Server $dc
Get-GPInheritance -Target $child -Domain $domain -Server $dc在 LAB-MEMBER 本地提升权限的 PowerShell 中执行,每一次对照都使用相同命令:
gpupdate /target:computer /force /wait:120
if ($LASTEXITCODE -ne 0) { throw 'gpupdate failed' }
gpresult /scope computer /r
if ($LASTEXITCODE -ne 0) { throw 'gpresult failed' }
Get-ItemProperty 'HKLM:\Software\Policies\KB-GPO-221' |
Select-Object Winner,ParentOnly正常刷新真实输出为:
Updating policy...
Computer Policy update has completed successfully.第一组 Winner=ChildA,同时 ParentOnly=InheritedParent。完成这一组后恢复无实验链接,再开始第二组。
第二组重新建立上述两个普通链接,加上 ChildB order 2,回读为 ChildA;然后只将 ChildB 调到 order 1,回读变为 ChildB。
New-GPLink -Guid $ids.ChildB -Target $child -LinkEnabled Yes -Enforced No -Order 2 -Domain $domain -Server $dc
Set-GPLink -Guid $ids.ChildB -Target $child -Order 1 -Domain $domain -Server $dc这两条命令之间要执行一次成员机刷新和回读,分别保存反转前后结果,避免直接跑到最终状态而漏掉对照。第二组结束再次恢复。
第三组重新建立父与 ChildA 普通链接,先确认正常继承,然后只改变 Child 的阻止继承:
Set-GPInheritance -Target $child -IsBlocked Yes -Domain $domain -Server $dc
Get-GPInheritance -Target $child -Domain $domain -Server $dc回读 Winner=ChildA,ParentOnly 缺失。第三组结束恢复阻止继承和链接,刷新确认两个值都不再存在。
第四组重新建立父与 ChildA 普通链接,先将父链接强制,再加 Child 阻止继承。两次变化之间分别刷新回读:
Set-GPLink -Guid $ids.Parent -Target $parent -Enforced Yes -Domain $domain -Server $dc
Set-GPInheritance -Target $child -IsBlocked Yes -Domain $domain -Server $dc两次均得到 Winner=Parent、ParentOnly=InheritedParent。诊断实际业务配置时也采用同样的三层证据:域控链接配置、成员机 RSoP 列表、目标设置实际值。只看到 gpupdate 成功,不足以确定某个冲突值的来源;如果实际值与链接配置不符,先核 gpresult 中的应用域控、过滤原因和对象 DN,再检查所联系域控的 AD 与 SYSVOL 策略版本。
2.4 恢复与清理
每组恢复时,只枚举本实验 OU 的链接,确认 GUID 属于本次创建集合,再逐条移除,并关闭阻止继承:
foreach ($ou in @($root,$parent,$child)) {
$links = @((Get-GPInheritance -Target $ou -Domain $domain -Server $dc).GpoLinks)
foreach ($link in $links) {
if ($link.GpoId -notin @($ids.Values)) { throw 'Unexpected link' }
Remove-GPLink -Guid $link.GpoId -Target $ou -Domain $domain -Server $dc
}
Set-GPInheritance -Target $ou -IsBlocked No -Domain $domain -Server $dc
}在成员机刷新后检查键存在性,不通过手动删键掩盖策略清理结果。本次四组的恢复都得到了相同真实回读:
{
"Winner": "ABSENT",
"ParentOnly": "ABSENT",
"SecureChannel": true,
"MarkerKeyExists": false
}完成最后一组恢复后,在 LAB-DC1 将计算机移回原容器,再删除本次 GPO,最后从最深层开始清理空 OU。保存并使用创建时记录的 OU GUID,删除前检查 DN 和子项;不使用递归删除。
Move-ADObject -Identity $computerGUID -TargetPath ('CN=Computers,' + $base) -Server $dc
Get-ADComputer -Identity $computerGUID -Server $dc |
Select-Object DistinguishedName,ObjectGUID
foreach ($id in $ids.Values) {
Remove-GPO -Guid $id -Domain $domain -Server $dc -Confirm:$false
}
foreach ($dn in @($child,$parent,$root)) {
$items = @(Get-ADObject -SearchBase $dn -SearchScope OneLevel -Filter * -Server $dc)
if ($items.Count -ne 0) { throw 'OU not empty' }
$ou = Get-ADOrganizationalUnit -Identity $dn -Server $dc
Remove-ADOrganizationalUnit -Identity $ou.ObjectGUID -Server $dc -Confirm:$false
}参考资料
- Microsoft Learn Group Policy processing,处理顺序及 Enforced 的层级关系。
- Microsoft Learn Set-GPLink,Order、LinkEnabled 和 Enforced 参数。
- Microsoft Learn Set-GPInheritance,阻止上级站点、域及 OU 的非强制链接继承。
