Infrastructure-as-code framework for Active Directory objects and Group Policy. Sanitized from production deployment for public sharing.
136 lines
4.6 KiB
PowerShell
136 lines
4.6 KiB
PowerShell
# Get-UnmanagedGPOs.ps1
|
|
# Discovers GPOs in AD that are not managed by the framework,
|
|
# and framework-defined GPOs that do not yet exist in AD.
|
|
#
|
|
# Usage:
|
|
# .\Get-UnmanagedGPOs.ps1
|
|
|
|
[CmdletBinding()]
|
|
param()
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$ScriptRoot = $PSScriptRoot
|
|
|
|
. (Join-Path $ScriptRoot 'lib\GPOHelper.ps1')
|
|
|
|
# -------------------------------------------------------------------
|
|
# Discover managed GPO names from settings.ps1 files
|
|
# -------------------------------------------------------------------
|
|
$gpoDirs = Get-ChildItem -Path $ScriptRoot -Directory |
|
|
Where-Object { Test-Path (Join-Path $_.FullName 'settings.ps1') }
|
|
|
|
$managedNames = @{}
|
|
foreach ($dir in $gpoDirs) {
|
|
$settings = & (Join-Path $dir.FullName 'settings.ps1')
|
|
$managedNames[$settings.GPOName] = $dir.Name
|
|
}
|
|
|
|
Write-Host "Framework manages $($managedNames.Count) GPO(s).`n" -ForegroundColor Cyan
|
|
|
|
# -------------------------------------------------------------------
|
|
# Enumerate all GPOs in AD
|
|
# -------------------------------------------------------------------
|
|
$allGPOs = Get-GPO -All
|
|
|
|
# -------------------------------------------------------------------
|
|
# Build OU link map (check known OUs for GPO links)
|
|
# -------------------------------------------------------------------
|
|
$domainDN = (Get-ADDomain).DistinguishedName
|
|
$checkTargets = @(
|
|
$domainDN
|
|
"OU=Domain Controllers,$domainDN"
|
|
"OU=ExampleUsers,$domainDN"
|
|
"OU=ExampleWorkstations,$domainDN"
|
|
"OU=ExampleServers,$domainDN"
|
|
"OU=ExampleAdmins,$domainDN"
|
|
"OU=ExampleAdminWorkstations,$domainDN"
|
|
)
|
|
|
|
# Map GPO GUID -> list of linked OU names
|
|
$linkMap = @{}
|
|
foreach ($target in $checkTargets) {
|
|
try {
|
|
$inheritance = Get-GPInheritance -Target $target -ErrorAction Stop
|
|
} catch {
|
|
continue
|
|
}
|
|
|
|
# Extract short OU name for display
|
|
$ouDisplay = if ($target -eq $domainDN) {
|
|
'(domain root)'
|
|
} else {
|
|
($target -split ',')[0] -replace '^OU=', ''
|
|
}
|
|
|
|
foreach ($link in $inheritance.GpoLinks) {
|
|
$gpoId = $link.GpoId.ToString()
|
|
if (-not $linkMap.ContainsKey($gpoId)) {
|
|
$linkMap[$gpoId] = @()
|
|
}
|
|
$linkMap[$gpoId] += $ouDisplay
|
|
}
|
|
}
|
|
|
|
# -------------------------------------------------------------------
|
|
# Section 1: Unmanaged GPOs (in AD but not in framework)
|
|
# -------------------------------------------------------------------
|
|
$unmanaged = @()
|
|
foreach ($gpo in $allGPOs) {
|
|
if (-not $managedNames.ContainsKey($gpo.DisplayName)) {
|
|
$gpoId = $gpo.Id.ToString()
|
|
$linkedTo = if ($linkMap.ContainsKey($gpoId)) {
|
|
$linkMap[$gpoId] -join ', '
|
|
} else { '(not linked)' }
|
|
|
|
$unmanaged += [PSCustomObject]@{
|
|
Name = $gpo.DisplayName
|
|
Id = "{$gpoId}"
|
|
CreationTime = $gpo.CreationTime.ToString('yyyy-MM-dd')
|
|
ModificationTime = $gpo.ModificationTime.ToString('yyyy-MM-dd')
|
|
LinkedTo = $linkedTo
|
|
GpoStatus = $gpo.GpoStatus.ToString()
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-Host '=== Unmanaged GPOs in AD ===' -ForegroundColor White
|
|
if ($unmanaged.Count -eq 0) {
|
|
Write-Host 'None found. All GPOs in AD are managed by the framework.' -ForegroundColor Green
|
|
} else {
|
|
Write-Host "$($unmanaged.Count) GPO(s) exist in AD without a settings.ps1:`n" -ForegroundColor Yellow
|
|
$unmanaged | Format-Table Name, Id, CreationTime, ModificationTime, LinkedTo, GpoStatus -AutoSize
|
|
}
|
|
|
|
# -------------------------------------------------------------------
|
|
# Section 2: Framework GPOs not in AD (defined but not created)
|
|
# -------------------------------------------------------------------
|
|
$adNames = @{}
|
|
foreach ($gpo in $allGPOs) {
|
|
$adNames[$gpo.DisplayName] = $true
|
|
}
|
|
|
|
$notInAD = @()
|
|
foreach ($name in $managedNames.Keys) {
|
|
if (-not $adNames.ContainsKey($name)) {
|
|
$notInAD += [PSCustomObject]@{
|
|
GPOName = $name
|
|
ConfigDir = $managedNames[$name]
|
|
Status = 'Defined but not created in AD'
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-Host '=== Framework GPOs Not in AD ===' -ForegroundColor White
|
|
if ($notInAD.Count -eq 0) {
|
|
Write-Host 'None. All framework GPOs exist in AD.' -ForegroundColor Green
|
|
} else {
|
|
Write-Host "$($notInAD.Count) framework GPO(s) not yet created:`n" -ForegroundColor Yellow
|
|
$notInAD | Format-Table GPOName, ConfigDir, Status -AutoSize
|
|
}
|
|
|
|
# -------------------------------------------------------------------
|
|
# Summary
|
|
# -------------------------------------------------------------------
|
|
Write-Host ''
|
|
Write-Host "Summary: $($unmanaged.Count) unmanaged, $($notInAD.Count) not in AD, $($managedNames.Count) managed." -ForegroundColor Cyan
|