# ------------------------------------------------------------------ # 0. Load modules (they are usually loaded by default, but be safe) # ------------------------------------------------------------------ Import-Module GroupPolicy -ErrorAction Stop Import-Module ActiveDirectory -ErrorAction Stop $TargetOU = "OU=NA,OU=Manufacturing,OU=Tesla Systems,DC=teslamotors,DC=com" $OutputFile = "C:\Users\matanderson\gpo\gpo-update.yaml" # Add-Content -Path $OutputFile -Value $line if (Test-Path $OutputFile) { Remove-Item -Path $OutputFile -Force } # ------------------------------------------------------------------ # 1. Grab every OU under $TargetOU (including $TargetOU itself) # ------------------------------------------------------------------ Write-Output "Enumerating OUs under '$TargetOU' ..." Add-Content -Path $OutputFile -Value "---" Add-Content -Path $OutputFile -Value "- root_ou: $TargetOU" $Start_Date = (Get-Date).ToString('MM/dd/yyyy hh:mm:ss tt') Add-Content -Path $OutputFile -Value " init_timestamp: $Start_Date" $ouObjects = Get-ADObject ` -Filter 'ObjectClass -eq "organizationalUnit"' ` -SearchBase $TargetOU ` -SearchScope Subtree ` -Properties gPLink # Also grab the target OU itself (in case it is linked directly) $targetOUObj = Get-ADObject ` -Identity $TargetOU ` -Properties gPLink if ($targetOUObj) { $ouObjects += $targetOUObj } # ------------------------------------------------------------------ # 2. Build a hashtable: GPO_GUID => list of OU DNs it is linked to # ------------------------------------------------------------------ $gpoLinks = @{} foreach ($ou in $ouObjects) { if ($ou.gPLink) { foreach ($link in ($ou.gPLink -split ';')) { $linkTrim = $link.Trim('[', ']') if ($linkTrim -match '\{(?[0-9a-fA-F-]+)\}') { $guid = $Matches.guid if (-not $gpoLinks.ContainsKey($guid)) { $gpoLinks[$guid] = @() } $gpoLinks[$guid] += $ou.DistinguishedName } } } } if (-not $gpoLinks.Count) { Write-Host "No GPOs linked under the searched OU tree." -ForegroundColor Yellow exit } Write-Host "Found $($gpoLinks.Count) distinct GPO(s) linked in the OU tree." Add-Content -Path $OutputFile -Value " gpo_links: $($gpoLinks.Count)" # ---------------------------------------------------- # 3. For each GPO, get an XML report and pull RestrictedGroup nodes # ---------------------------------------------------- Add-Content -Path $OutputFile -Value " configured_gpos:" $ou_counter = 0 foreach ($gpoGuid in $gpoLinks.Keys) { $ou_counter++ try { $gpo = Get-GPO -Guid $gpoGuid -ErrorAction Stop } catch { Write-Warning "Unable to retrieve GPO $gpoGuid – skipping." continue } Write-Host "GPO $ou_counter of $($gpoLinks.Count): $($gpo.DisplayName)" Add-Content -Path $OutputFile -Value " $($gpo.DisplayName):" # ok, i need to start generating a variable with all links in it # -------- Linked OUs ---------- $linkedOUs = $gpoLinks[$gpoGuid] # <-- the list we built earlier Add-Content -Path $OutputFile -Value " - Linked_OUs:" foreach ($ouDn in $linkedOUs) { Add-Content -Path $OutputFile -Value " - $ouDn" } # Pull the 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') # default namespace $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') # Find every element $restrictedGroups = $xml.SelectNodes('//q1:RestrictedGroups', $ns) # Loop and build the string foreach ($rg in $restrictedGroups) { $adGroupName = ($rg.SelectSingleNode('q1:GroupName/t:Name', $ns)).InnerText $localGroupName = ($rg.SelectSingleNode('q1:Memberof/t:Name', $ns)).InnerText $plainAD_Groupname = ($adGroupName -split '\\')[-1] #Write-Output "AD Group: $adGroupName - Local Group: $localGroupName" Add-Content -Path $OutputFile -Value " - ad_group: $plainAD_Groupname" Add-Content -Path $OutputFile -Value " local_group: $localGroupName" } Add-Content -Path $OutputFile -Value "" } $Current_Date = (Get-Date).ToString('MM/dd/yyyy hh:mm:ss tt') Add-Content -Path $OutputFile -Value " timestamp: $Current_Date" Add-Content -Path $OutputFile -Value "..."