I recently discovered a configuration inconsistency across our domain controllers that was made physical when a group policy monitor script failed to detect updates.
What I found when I ran my PowerShell audit script was inconsistency’s - our Security Event Log sizes were all over the place, creating compliance gaps and potential audit trail loss.
The Discovery That Started It All
I had built a PowerShell script to audit our domain controllers' Security Event Log configurations, expecting to find uniform settings across the environment. Instead, I was greeted with this inconsistent output:
Checking ROADRUNNER...
Current size: 13958643712 bytes (13 GB)
✓ Correctly configured
Checking COYOTE...
Current size: 13421772800 bytes (12.5 GB)
MISMATCH DETECTED: Expected 13958643712 bytes (13 GB)
Checking SPEEDY...
Current size: 13428326400 bytes (12.51 GB)
MISMATCH DETECTED: Expected 13958643712 bytes (13 GB)
Checking PEPE...
Current size: 13421772800 bytes (12.5 GB)
MISMATCH DETECTED: Expected 13958643712 bytes (13 GB)
Checking TWEETY...
Current size: 5599985664 bytes (5.22 GB)
MISMATCH DETECTED: Expected 13958643712 bytes (13 GB)
Out of our domain controller infrastructure, I found configurations ranging from 5.22 GB to 12.51 GB - a massive variance that could impact audit capabilities and compliance posture.
Domain controllers with smaller log sizes were cycling through security events much faster. "TWEETY" with only 5.22 GB was overwriting security events after just 18 hours, while others maintained 3-4 days of history.
PowerShell Discovery Script
Here's the script that revealed this configuration chaos:
param([switch]$ForceValue)
# Target size: 13 GB in bytes
$RecommendedSizeBytes = 13958643712
Write-Host "Domain Controller Security Event Log Audit" -ForegroundColor Green
Write-Host "Target size: 13 GB ($RecommendedSizeBytes bytes)" -ForegroundColor Yellow
# Get all domain controllers
$DomainControllers = Get-ADDomainController -Filter * | Select-Object Name
$MismatchedDCs = @()
$CorrectDCs = @()
foreach ($DC in $DomainControllers) {
Write-Host "`nChecking $($DC.Name)..." -ForegroundColor White
try {
$SecurityLog = Get-WinEvent -ListLog Security -ComputerName $DC.Name -ErrorAction Stop
$CurrentSize = $SecurityLog.MaximumSizeInBytes
$SizeGB = [math]::Round($CurrentSize/1GB, 2)
Write-Host " Current size: $CurrentSize bytes ($SizeGB GB)" -ForegroundColor White
if ($CurrentSize -ne $RecommendedSizeBytes) {
Write-Host " MISMATCH DETECTED: Expected $RecommendedSizeBytes bytes (13 GB)" -ForegroundColor Red
$MismatchedDCs += [PSCustomObject]@{
Name = $DC.Name
CurrentSize = $CurrentSize
CurrentSizeGB = $SizeGB
RecommendedSize = $RecommendedSizeBytes
}
} else {
Write-Host " ✓ Correctly configured" -ForegroundColor Green
$CorrectDCs += $DC.Name
}
}
catch {
Write-Host " ERROR: Unable to retrieve log configuration - $($_.Exception.Message)" -ForegroundColor Red
}
}
Root Cause Analysis
After digging deeper, I discovered three main causes for this inconsistency:
1. Manual Configuration Drift
This setting was free to be updated by Administrators which means each server had the potential to be on a different value.
2. No Centralized Management
Each DC was configured locally, allowing for individual changes that weren't tracked or standardized.
3. Legacy Settings Persistence
Some domain controllers retained old configuration values from previous OS upgrades or migrations.
💡 Key Insight: Without centralized management, configuration drift is inevitable in enterprise environments.
Group Policy : Centralized Control
To solve this inconsistency permanently, I implemented a Group Policy-based approach which would centrally enforce these settings.
Step 1: Create the Domain Controller Security Policy
- Open Group Policy Management Console (gpmc.msc)
- Navigate to your domain → Domain Controllers OU
- Right-click "Default Domain Controllers Policy" → Edit
Step 2: Configure Security Event Log Size
Navigate through the policy tree:
Computer Configuration
└── Policies
└── Administrative Templates
└── Windows Components
└── Event Log Service
└── Security
Step 3: Apply the Specific Settings
Policy 1: Maximum Log File Size
- Setting: Specify the maximum log file size (KB)
- State: Enabled
- Value:13631488 (13 GB in KB)
- Impact: Forces uniform log size across all DCs
Policy 2: Retention Method
- Setting: Control Event Log behavior when the log file reaches its maximum size
- State: Enabled
- Option : Overwrite events as needed (oldest events first)
- Impact: Ensures continuous logging without manual intervention
Step 4: Link and Enforce the Policy
- Verify this GPO is linked to the Domain Controllers OU
- Verify No Conflicts: Check GPO precedence and filtering
Step 5: Force Policy Application
On each domain controller, run:
gpupdate /force
Or centrally trigger via PowerShell:
$DomainControllers | ForEach-Object {
Invoke-Command -ComputerName $_.Name -ScriptBlock { gpupdate /force }
}
Prevented Future Drift
The Event Log Properties dialog now shows:
- Maximum log size field: Grayed out
- Retention options: Grayed out
- Tooltip: "This setting is managed by your system administrator"