Group Policy Objects are the backbone of Active Directory management, but they're also prime targets for changing centralized settings that can affect the whole domain.
I've created a PowerShell script that exports all domain GPOs to CSV format, perfect for baseline creation and integration with Microsoft Sentinel watchlists.
The Challenge
When you're managing an Active Directory environment, GPO changes can happen silently. New policy objects might be created by legitimate administrators or potentially by attackers who've gained elevated privileges. Having a baseline of existing GPOs becomes crucial for detecting unauthorized changes.
The Solution
This script captures all GPOs in your domain with key identifying information that can be imported directly into Microsoft Sentinel as a watchlist. Once imported, you can create analytics rules to alert on newly created GPOs that don't exist in your baseline.
# PowerShell script to export all Group Policy Objects to CSV
# Requires Group Policy module and appropriate domain permissions
# Import the Group Policy module
Import-Module GroupPolicy -ErrorAction Stop
# Set the output file path
$OutputPath = ".\GPO_Export_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
# Get current timestamp for TimeGenerated field
$TimeGenerated = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
try {
Write-Host "Retrieving Group Policy Objects from domain..." -ForegroundColor Yellow
# Get all GPOs in the domain
$GPOs = Get-GPO -All
# Create array to hold the results
$Results = @()
# Process each GPO
foreach ($GPO in $GPOs) {
$GPOObject = [PSCustomObject]@{
TimeGenerated = $TimeGenerated
GPOId = $GPO.Id
GPOName = $GPO.DisplayName
LastModified = $GPO.ModificationTime.ToString("yyyy-MM-dd HH:mm:ss")
}
$Results += $GPOObject
}
# Export to CSV
$Results | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
Write-Host "Successfully exported $($Results.Count) GPOs to: $OutputPath" -ForegroundColor Green
Write-Host "File location: $(Resolve-Path $OutputPath)" -ForegroundColor Cyan
} catch {
Write-Error "An error occurred: $($_.Exception.Message)"
Write-Host "Please ensure you have:" -ForegroundColor Red
Write-Host "1. Group Policy Management Console installed" -ForegroundColor Red
Write-Host "2. Appropriate domain permissions" -ForegroundColor Red
Write-Host "3. Connection to domain controller" -ForegroundColor Red
}
What does it do?
The script exports four key fields for each GPO:
- TimeGenerated: When I ran the export (useful for baseline tracking)
- GPOId: The unique GUID identifier for each policy
- GPOName: The human-readable display name
- LastModified: When the GPO was last changed
Sentinel Integration
Once you have the CSV file, you can import it directly into Microsoft Sentinel as a watchlist. This creates a baseline of known GPOs that I can reference in KQL queries. When Sentinel detects GPO creation events and cross-reference against this watchlist to identify newly created policies that weren't in the original baseline.
The output file gets a timestamp in the filename, so multiple runs won't overwrite previous exports. This makes it easy to track changes over time or create multiple baselines for different purposes.