Public/Search-GPO.ps1
|
function Search-GPO { <# .SYNOPSIS Enhanced GPO Search Tool with deep-step logging. .DESCRIPTION Analyzes GPO metadata and internal script code with real-time progress watchdog. Can search for strings in GPO Names, Metadata (XML), and internal script files (Startup/Shutdown/Logon/Logoff). .PARAMETER SearchTerm The string to search for within GPOs. .PARAMETER ShowDetails If specified, outputs a formatted list of results instead of a table. .EXAMPLE Search-GPO -SearchTerm "Printer" Searches all GPOs for the string "Printer". .EXAMPLE Search-GPO "Deploy" -ShowDetails Searches for "Deploy" and shows full match details. #> [CmdletBinding()] param( [Parameter(Mandatory = $false, Position = 0, ValueFromPipeline = $true)] [string]$SearchTerm, [Parameter(Mandatory = $false)] [switch]$ShowDetails ) process { if (-not (Get-Module -ListAvailable -Name GroupPolicy)) { Write-Error "The 'GroupPolicy' module is required but not found. Please install RSAT (Remote Server Administration Tools) for Group Policy Management." return } if (-not $SearchTerm) { try { $SearchTerm = Read-Host "Enter the server name or string to search for" } catch { Write-Error "Could not read input. Run with: Search-GPO -SearchTerm 'Name'" return } } if ([string]::IsNullOrWhiteSpace($SearchTerm)) { return } $Timer = [System.Diagnostics.Stopwatch]::StartNew() $DomainDNS = $env:USERDNSDOMAIN $SysvolBase = "\\$DomainDNS\SYSVOL\$DomainDNS\Policies" Write-Host "`nInitializing Enhanced Scan for: $SearchTerm" -ForegroundColor Cyan Write-Verbose "Targeting Domain: $DomainDNS" Write-Verbose "SYSVOL Root: $SysvolBase" $AllGpos = Get-GPO -All $TotalCount = $AllGpos.Count $Results = New-Object System.Collections.Generic.List[PSObject] foreach ($Gpo in $AllGpos) { $Index = [array]::IndexOf($AllGpos, $Gpo) + 1 $Percent = [math]::Round(($Index / $TotalCount) * 100, 0) $Timestamp = Get-Date -Format "HH:mm:ss" # Progress Bar Watchdog Write-Progress -Activity "Scanning GPOs (Elapsed: $($Timer.Elapsed.ToString('mm\:ss')))" ` -Status "[$Timestamp] Analyzing [$Index/$TotalCount]: $($Gpo.DisplayName)" ` -PercentComplete $Percent # Detailed Verbose Logging for each step Write-Verbose "[$Timestamp] START: $($Gpo.DisplayName) [ID: $($Gpo.Id)]" $MatchSource = @() $MatchEvidence = @() $GpoGuid = "{$($Gpo.Id.Guid.ToString().ToUpper())}" try { # STEP 1: XML Metadata Analysis Write-Verbose " -> Step 1/2: Analyzing XML Metadata Settings..." [xml]$GpoXml = Get-GPOReport -Guid $Gpo.Id -ReportType Xml -ErrorAction Stop if ($GpoXml.OuterXml -like "*$SearchTerm*") { Write-Verbose " [!] Match found in Metadata XML." $MatchSource += "GPO Settings" if ($GpoXml.OuterXml -match "([^>]{0,50}$SearchTerm[^<]{0,50})") { $MatchEvidence += "XML Snippet: ...$($Matches[1])..." } } # Link Analysis $ActiveLinks = @($GpoXml.GPO.LinksTo) | Where-Object { $_.Enabled -eq "true" } $LinkPaths = if ($ActiveLinks) { ($ActiveLinks.SOMPath -join "; ") } else { "--- NONE ---" } Write-Verbose " -> Verified Link Status: $(if ($ActiveLinks) { 'Linked' } else { 'Unlinked' })" } catch { Write-Verbose " -> ERROR: Metadata analysis failed for this policy." $LinkPaths = "--- ERROR ---" } # STEP 2: Internal Script Code Analysis Write-Verbose " -> Step 2/2: Scraping Internal SYSVOL Script Code..." $ScriptFolders = @( "$SysvolBase\$GpoGuid\Machine\Scripts\Startup", "$SysvolBase\$GpoGuid\Machine\Scripts\Shutdown", "$SysvolBase\$GpoGuid\User\Scripts\Logon", "$SysvolBase\$GpoGuid\User\Scripts\Logoff" ) foreach ($Folder in $ScriptFolders) { if (Test-Path $Folder) { Write-Verbose " Checking Directory: $($Folder.Split('\')[-3..-1] -join '\')" $FileMatches = Get-ChildItem $Folder -File -Recurse | Select-String -Pattern $SearchTerm if ($FileMatches) { Write-Verbose " [!] Match found in Script Content." $MatchSource += "Script Code" foreach ($fm in $FileMatches) { $MatchEvidence += "File ($($fm.Filename)) line $($fm.LineNumber): $($fm.Line.Trim())" } } } } if ($MatchSource.Count -gt 0) { $Results.Add([PSCustomObject]@{ GPOName = $Gpo.DisplayName IsLinked = if ($LinkPaths -ne "--- NONE ---" -and $LinkPaths -ne "--- ERROR ---") { $true } else { $false } Source = $MatchSource -join ", " MatchDetails = $MatchEvidence -join " | " LastModified = $Gpo.ModificationTime LinkPaths = $LinkPaths }) } Write-Verbose "[$Timestamp] FINISH: $($Gpo.DisplayName)`n" } $Timer.Stop() if ($Results.Count -gt 0) { Write-Host "`n[SCAN COMPLETE] - Found $($Results.Count) matches in $($Timer.Elapsed.ToString('mm\:ss'))`n" -ForegroundColor Green if ($ShowDetails) { $Results | Format-List GPOName, IsLinked, Source, MatchDetails, LastModified, LinkPaths } else { $Results | Select-Object GPOName, IsLinked, Source, LastModified, LinkPaths | Format-Table -AutoSize } } else { Write-Host "`nNo matches found for '$SearchTerm' across $TotalCount GPOs." -ForegroundColor Yellow } } } |