Files
gpo_lookup/files/check-hostname-restricted-groups.ps1
2026-11-03 03:01:00 -08:00

138 lines
5.2 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ------------------------------------------------------------------
# 1. Set up environment
# ------------------------------------------------------------------
$ComputerName = "FRRF1LLC1103011"
$printDebug = $false
Import-Module GroupPolicy -ErrorAction Stop
Import-Module ActiveDirectory -ErrorAction Stop
# ------------------------------------------------------------------
# 2. Resolve the computer’s DN and build the OU chain (leaf → root)
# ------------------------------------------------------------------
try {
$comp = Get-ADComputer -Identity $ComputerName -Properties DistinguishedName
}
catch {
Write-Error "Cannot find computer '$ComputerName' in AD: $_"
exit 1
}
$ouDN = $comp.DistinguishedName -replace '^CN=.*?,', ''
$ouChain = @()
$currentDN = $ouDN
while ($currentDN -match '^OU=') {
$ouChain += $currentDN
$currentDN = $currentDN.Substring($currentDN.IndexOf(',') + 1)
}
$ouChain += $currentDN # root
if ($printDebug) {
Write-Host "OU chain (leaf → root):" -ForegroundColor Cyan
$ouChain | ForEach-Object { Write-Host $_ }
}
# ------------------------------------------------------------------
# 3. Gather GPO links for each OU in the chain
# ------------------------------------------------------------------
$gpoLinks = @{} # Hashtable: GPO_GUID => array of OU DNs
foreach ($ouDN in $ouChain) {
try {
$ouObj = Get-ADObject -Identity $ouDN -Properties gPLink -ErrorAction Stop
}
catch {
Write-Warning "Could not read OU '$ouDN': $_"
continue
}
if ($ouObj.gPLink) {
foreach ($link in ($ouObj.gPLink -split ';')) {
$clean = $link.Trim(' ', '[', ']')
if ($clean -match '\{(?<guid>[0-9a-fA-F-]+)\}') {
$guid = $Matches.guid
if (-not $gpoLinks.ContainsKey($guid)) { $gpoLinks[$guid] = @() }
$gpoLinks[$guid] += $ouDN
}
}
}
}
if (-not $gpoLinks.Count) {
Write-Host "No GPOs linked to any OU in the hierarchy." -ForegroundColor Yellow
exit
}
Write-Host "Found $($gpoLinks.Count) distinct GPO(s) linked in this OU tree." -ForegroundColor Green
# ------------------------------------------------------------------
# 4. Collect all restricted‑group entries into an array
# ------------------------------------------------------------------
$results = @() # Will hold objects: @{ADGroup=; LocalGroup=; GPO=}
$uniqueGpoGuids = $gpoLinks.Keys | Sort-Object -Unique
$ou_counter = 0
$totalItems = $uniqueGpoGuids.Count
$startTime = Get-Date
foreach ($gpoGuid in $uniqueGpoGuids) {
$ou_counter++
try { $gpo = Get-GPO -Guid $gpoGuid -ErrorAction Stop }
catch { Write-Warning "Unable to retrieve GPO $gpoGuid – skipping."; continue }
$percentComplete = [int]( ($ou_counter / $gpoLinks.Count) * 100 )
if ($ou_counter -gt 0) {
$elapsed = (Get-Date) - $startTime
$averagePerItem = $elapsed.TotalSeconds / $ou_counter
$remainingItems = $totalItems - $ou_counter
$secondsRemaining = [int]($averagePerItem * $remainingItems)
} else { $secondsRemaining = -1 }
Write-Progress -Activity "Processing GPOs" `
-Status $gpo.DisplayName `
-PercentComplete $percentComplete `
-SecondsRemaining $secondsRemaining `
-CurrentOperation "GPO $ou_counter of $totalItems"
# Grab XML report
try { $xmlString = Get-GPOReport -Guid $gpoGuid -ReportType Xml -ErrorAction Stop }
catch { Write-Warning "Unable to generate XML report for $($gpo.DisplayName)."; continue }
$xml = [xml]$xmlString
$ns = New-Object System.Xml.XmlNamespaceManager ($xml.NameTable)
$ns.AddNamespace('m', 'http://www.microsoft.com/GroupPolicy/Settings')
$ns.AddNamespace('q1', 'http://www.microsoft.com/GroupPolicy/Settings/Security')
$ns.AddNamespace('t', 'http://www.microsoft.com/GroupPolicy/Types')
$ns.AddNamespace('xsi','http://www.w3.org/2001/XMLSchema-instance')
$restrictedGroups = $xml.SelectNodes('//q1:RestrictedGroups', $ns)
foreach ($rg in $restrictedGroups) {
$adGroupName = ($rg.SelectSingleNode('q1:GroupName/t:Name', $ns)).InnerText
$localGroupName = ($rg.SelectSingleNode('q1:Memberof/t:Name', $ns)).InnerText
$results += [pscustomobject]@{
ADGroup = $adGroupName
LocalGroup = $localGroupName
GPO = $gpo.DisplayName
}
}
}
$elapsed = (Get-Date) - $startTime
$elapsedSeconds = [math]::Round($elapsed.TotalSeconds, 2)
Write-Host "`nFinished processing $totalItems GPO(s) after $elapsedSeconds seconds." -ForegroundColor Green
# ------------------------------------------------------------------
# 5. Print two separate lists
# ------------------------------------------------------------------
Write-Host "`n=== AD groups that are members of BUILTIN\Administrators ===" -ForegroundColor Yellow
$results | Where-Object {$_.LocalGroup -eq 'BUILTIN\Administrators'} |
Select-Object -ExpandProperty ADGroup | Sort-Object | Get-Unique
Write-Host "`n=== AD groups that are members of vnc_admin ===" -ForegroundColor Yellow
$results | Where-Object {$_.LocalGroup -eq 'vnc_admin'} |
Select-Object -ExpandProperty ADGroup | Sort-Object | Get-Unique