SCRIPT LIBRARY · POWERSHELL
Delegating Your Tier 0 OU to a Dedicated Admin Group with PowerShell
Create a Tier 0 admin group, keep it where only Tier 0 can touch it, and give it full control of the Tier 0 OU. Preview the whole thing with -WhatIf first.
- What it does
- Creates a Tier 0 admin group inside the Tier 0 OU, adds the admin accounts you name, and grants the group inheritable Full Control over the Tier 0 OU. Safe to re-run, and -WhatIf shows every step first.
- Requires
- Windows PowerShell 5.1 or PowerShell 7 on Windows
- ActiveDirectory module (RSAT)
- Permissions
- Rights to create groups in the target OU and to change permissions on the Tier 0 OU. In practice that's a Domain Admin, run from a Tier 0 admin workstation.
- Runs on
- Windows 10/11 with RSAT, Windows Server 2016+
- Tested
- Parse-checked and dry-run with -WhatIf against mocked AD cmdlets in PowerShell 7.4. The ACL step needs a real domain to exercise.
Part 1 of the thread Keeping Active Directory tidy
If you've read anything about securing Active Directory in the last decade, you've run into tiering. Microsoft's current name for it is the enterprise access model, but the core idea hasn't changed: the stuff that controls identity (domain controllers, AD itself, Entra Connect, your PKI, and every account and group that can manage those) is Tier 0, and nothing from a lower tier gets to control it.
The part people skip is the plumbing. You make a Tier 0 OU, then everybody who needs to manage it just... uses Domain Admins. This script does the boring, correct thing instead. It creates a dedicated group, puts that group inside Tier 0 so only Tier 0 admins can change who's in it, and delegates the Tier 0 OU to it.
The OU, group name, members and domain are all parameters, there are no credentials anywhere in it, and it supports -WhatIf, so you can see exactly what it would do before it touches anything.
<#
.SYNOPSIS
Creates a Tier 0 admin group and delegates full control of the Tier 0 OU tree to it.
.DESCRIPTION
Builds the delegation piece of a tiered admin model: one security group whose members
manage everything under the Tier 0 OU. The script creates the group (inside Tier 0, so
only Tier 0 can change who's in it), adds any members you name, and adds an inheritable
Full Control entry to the Tier 0 OU's ACL. It's safe to re-run: existing groups, members
and permissions are left alone. Supports -WhatIf.
.PARAMETER Tier0OU
Distinguished name of the Tier 0 OU, e.g. OU=Tier 0,OU=Admin,DC=contoso,DC=com.
.PARAMETER GroupName
Name of the delegation group. Default: Tier0-Admins.
.PARAMETER GroupOU
Where to create the group. Defaults to OU=Groups under the Tier 0 OU, falling back to the Tier 0 OU itself.
.PARAMETER Member
Accounts to add to the group (sAMAccountName or DN). Use dedicated admin accounts, not daily-driver ones.
.PARAMETER Server
Domain or domain controller to talk to. Defaults to the domain of the computer you're running on.
.EXAMPLE
.\Grant-Tier0Delegation.ps1 -Tier0OU 'OU=Tier 0,OU=Admin,DC=contoso,DC=com' -WhatIf
.EXAMPLE
.\Grant-Tier0Delegation.ps1 -Tier0OU 'OU=Tier 0,OU=Admin,DC=contoso,DC=com' -Member adm-t0-jdoe, adm-t0-asmith
#>
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory)][ValidatePattern('^OU=.+DC=')][string]$Tier0OU,
[ValidateNotNullOrEmpty()][string]$GroupName = 'Tier0-Admins',
[string]$GroupOU,
[string[]]$Member,
[string]$Server
)
$ErrorActionPreference = 'Stop'
Import-Module ActiveDirectory
$ad = @{}
if ($Server) { $ad.Server = $Server }
function Write-Result([string]$Action, [string]$Target, [string]$Result, [string]$Detail = '') {
[pscustomobject]@{ Action = $Action; Target = $Target; Result = $Result; Detail = $Detail }
}
# --- Check the OU and decide where the group lives
$null = Get-ADOrganizationalUnit -Identity $Tier0OU @ad
if (-not $GroupOU) {
$candidate = "OU=Groups,$Tier0OU"
$GroupOU = if (Get-ADOrganizationalUnit -Filter * -SearchBase $Tier0OU -SearchScope OneLevel @ad | Where-Object DistinguishedName -eq $candidate) { $candidate } else { $Tier0OU }
}
if ($GroupOU -notlike "*$Tier0OU") {
Write-Warning "$GroupOU is outside $Tier0OU. Whoever controls that OU can add themselves to your Tier 0 group."
}
# --- 1. The group
$group = Get-ADGroup -Filter "Name -eq '$($GroupName -replace "'", "''")'" @ad
if ($group) {
Write-Result 'Create group' $GroupName 'Skipped' "Already exists at $($group.DistinguishedName)"
}
elseif ($PSCmdlet.ShouldProcess("$GroupName in $GroupOU", 'Create security group')) {
$group = New-ADGroup -Name $GroupName -SamAccountName $GroupName -GroupCategory Security -GroupScope Global -Path $GroupOU -Description "Full control of $Tier0OU (tiered admin model)" -PassThru @ad
Write-Result 'Create group' $GroupName 'Done'
}
else {
Write-Result 'Create group' $GroupName 'WhatIf'
}
# --- 2. Members
foreach ($m in $Member) {
if (-not $group) { Write-Result 'Add member' $m 'WhatIf' 'Group would be created first'; continue }
try {
if ($PSCmdlet.ShouldProcess($GroupName, "Add member $m")) {
Add-ADGroupMember -Identity $group -Members $m @ad
Write-Result 'Add member' $m 'Done'
}
else { Write-Result 'Add member' $m 'WhatIf' }
}
catch { Write-Result 'Add member' $m 'Failed' $_.Exception.Message }
}
# --- 3. Delegate Full Control on the Tier 0 OU, inherited by everything below it
if (-not $group) {
Write-Result 'Delegate Full Control' $Tier0OU 'WhatIf' 'Group would be created first'
return
}
$sid = [System.Security.Principal.SecurityIdentifier]$group.SID.Value
$ou = Get-ADObject -Identity $Tier0OU -Properties nTSecurityDescriptor @ad
$acl = $ou.nTSecurityDescriptor
$full = [System.DirectoryServices.ActiveDirectoryRights]::GenericAll
$have = $acl.GetAccessRules($true, $false, [System.Security.Principal.SecurityIdentifier]) | Where-Object {
$_.IdentityReference -eq $sid -and ($_.ActiveDirectoryRights -band $full) -eq $full -and $_.InheritanceType -eq 'All'
}
if ($have) {
Write-Result 'Delegate Full Control' $Tier0OU 'Skipped' 'Permission already present'
}
elseif ($PSCmdlet.ShouldProcess($Tier0OU, "Grant $GroupName Full Control (this OU and all descendants)")) {
$rule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new($sid, 'GenericAll', 'Allow', [System.DirectoryServices.ActiveDirectorySecurityInheritance]::All)
$acl.AddAccessRule($rule)
Set-ADObject -Identity $Tier0OU -Replace @{ nTSecurityDescriptor = $acl } @ad
Write-Result 'Delegate Full Control' $Tier0OU 'Done'
}
else {
Write-Result 'Delegate Full Control' $Tier0OU 'WhatIf'
}
Parameters
| Parameter | Type | Default | What it's for |
|---|---|---|---|
-Tier0OU | string | — | Distinguished name of your Tier 0 OU. Required, and it has to exist already. |
-GroupName | string | Tier0-Admins | What to call the delegation group. If it already exists, the script uses it. |
-GroupOU | string | OU=Groups under the Tier 0 OU | Where the group gets created. Falls back to the Tier 0 OU itself if there's no Groups OU. You'll get a warning if you point it outside Tier 0. |
-Member | string[] | — | Admin accounts to add, by sAMAccountName or DN. These should be separate Tier 0 admin accounts, not anyone's everyday login. |
-Server | string | — | Domain name or a specific domain controller. Leave it off to use the domain you're joined to. |
-WhatIf | switch | — | Show what would be created and granted without changing anything. |
Run it
See the plan first. Nothing gets created.
.\Grant-Tier0Delegation.ps1 -Tier0OU 'OU=Tier 0,OU=Admin,DC=contoso,DC=com' -WhatIfCreate the group, add two admin accounts, and delegate the OU.
.\Grant-Tier0Delegation.ps1 -Tier0OU 'OU=Tier 0,OU=Admin,DC=contoso,DC=com' -Member adm-t0-jdoe, adm-t0-asmithUse your own naming convention and a specific DC.
.\Grant-Tier0Delegation.ps1 -Tier0OU 'OU=Tier 0,OU=Admin,DC=contoso,DC=com' -GroupName 'GG-T0-Operators' -Server dc01.contoso.comKeep a record of what it did.
.\Grant-Tier0Delegation.ps1 -Tier0OU 'OU=Tier 0,OU=Admin,DC=contoso,DC=com' -Member adm-t0-jdoe | Export-Csv .\tier0-delegation.csv -NoTypeInformationWhat you'll see
Action Target Result Detail
------ ------ ------ ------
Create group Tier0-Admins Done
Add member adm-t0-jdoe Done
Add member adm-t0-asmith Failed Cannot find an object with identity: 'adm-t0-asmith'
Delegate Full Control OU=Tier 0,OU=Admin,DC=contoso,DC=com Done
How it works
- Check the target. It confirms the Tier 0 OU exists, then decides where the group lives. A
GroupsOU under Tier 0 is the default. If you point it somewhere outside Tier 0, it warns you, because whoever controls that other OU could quietly add themselves to your Tier 0 group. - Create the group, or reuse it. A global security group with a description that says what it's for. If a group by that name already exists, it's left alone.
- Add members. Each one on its own, so a typo in one account name doesn't stop the rest.
- Delegate the OU. It reads the OU's security descriptor, checks whether the group already has Full Control inherited to everything below, and if not, adds one access rule and writes it back with
Set-ADObject. Using the AD cmdlets for this (rather than theAD:drive) means-Serverworks for the whole run. - Report. Every step returns an object with Done, Skipped, Failed or WhatIf, so you can read it on screen or export it.
Under -WhatIf it still reads from AD, so the preview is accurate. It just doesn't create or grant anything, and it tells you when a later step depends on an earlier one that hasn't happened yet.
Take it further
- Build the rest of the tiers. The same pattern works for Tier 1 servers and Tier 2 workstations and users. There's a Tier 2 version with narrower permissions.
- Stop Tier 0 accounts from wandering. Add your Tier 0 admin accounts to Protected Users and use authentication policies or "Deny log on" rights so they can't sign in to lower-tier machines.
- Audit it on a schedule. A monthly
Get-ADGroupMember Tier0-Adminscompared against a known-good list catches the "just for this weekend" additions that never got removed.
Things that'll trip you up
- AdminSDHolder wins on protected accounts. Anything that's a member of Domain Admins, Enterprise Admins and the other protected groups gets its permissions reset to the AdminSDHolder template every hour, with inheritance turned off. Your delegated Full Control won't reach those objects no matter where they sit. That's by design, so don't fight it.
- Membership in this group is Tier 0. Treat it that way. Full control of the OU that holds your Tier 0 servers and accounts is a short walk from owning the domain. Only dedicated Tier 0 admin accounts go in, and they only sign in to Tier 0 machines.
- Run it from the right place. Building your Tier 0 delegation from a daily-driver laptop, signed in with the account you read email on, undoes a good chunk of the point. Use a privileged access workstation or at least a hardened admin box.
- There's no undo switch. Re-running is safe because it skips anything that's already there, but it doesn't remove anything. To back out, delete the group's entry on the OU's Security tab (Advanced) in Active Directory Users and Computers, or with dsacls.