Damien Coles f172d00514 Initial release: Declarative AD Framework v2.1.0
Infrastructure-as-code framework for Active Directory objects and Group Policy.
Sanitized from production deployment for public sharing.
2026-02-19 17:02:42 +00:00

218 lines
9.9 KiB
PowerShell

# GPOAudit.ps1
# Advanced Audit Policy (audit.csv) with subcategory GUID lookup table.
# Depends on: GPOCore.ps1 (Get-GPOSysvolPath, Add-GPOExtensionGuids)
# Well-known subcategory GUIDs -- static across all Windows versions.
$Script:AuditSubcategoryGuid = @{
# System
'Security State Change' = '{0CCE9210-69AE-11D9-BED3-505054503030}'
'Security System Extension' = '{0CCE9211-69AE-11D9-BED3-505054503030}'
'System Integrity' = '{0CCE9212-69AE-11D9-BED3-505054503030}'
'IPsec Driver' = '{0CCE9213-69AE-11D9-BED3-505054503030}'
'Other System Events' = '{0CCE9214-69AE-11D9-BED3-505054503030}'
# Logon/Logoff
'Logon' = '{0CCE9215-69AE-11D9-BED3-505054503030}'
'Logoff' = '{0CCE9216-69AE-11D9-BED3-505054503030}'
'Account Lockout' = '{0CCE9217-69AE-11D9-BED3-505054503030}'
'IPsec Main Mode' = '{0CCE9218-69AE-11D9-BED3-505054503030}'
'IPsec Quick Mode' = '{0CCE9219-69AE-11D9-BED3-505054503030}'
'IPsec Extended Mode' = '{0CCE921A-69AE-11D9-BED3-505054503030}'
'Special Logon' = '{0CCE921B-69AE-11D9-BED3-505054503030}'
'Other Logon/Logoff Events' = '{0CCE921C-69AE-11D9-BED3-505054503030}'
'Network Policy Server' = '{0CCE9243-69AE-11D9-BED3-505054503030}'
'User / Device Claims' = '{0CCE9247-69AE-11D9-BED3-505054503030}'
'Group Membership' = '{0CCE9249-69AE-11D9-BED3-505054503030}'
# Object Access
'File System' = '{0CCE921D-69AE-11D9-BED3-505054503030}'
'Registry' = '{0CCE921E-69AE-11D9-BED3-505054503030}'
'Kernel Object' = '{0CCE921F-69AE-11D9-BED3-505054503030}'
'SAM' = '{0CCE9220-69AE-11D9-BED3-505054503030}'
'Certification Services' = '{0CCE9221-69AE-11D9-BED3-505054503030}'
'Application Generated' = '{0CCE9222-69AE-11D9-BED3-505054503030}'
'Handle Manipulation' = '{0CCE9223-69AE-11D9-BED3-505054503030}'
'File Share' = '{0CCE9224-69AE-11D9-BED3-505054503030}'
'Filtering Platform Packet Drop' = '{0CCE9225-69AE-11D9-BED3-505054503030}'
'Filtering Platform Connection' = '{0CCE9226-69AE-11D9-BED3-505054503030}'
'Other Object Access Events' = '{0CCE9227-69AE-11D9-BED3-505054503030}'
'Detailed File Share' = '{0CCE9244-69AE-11D9-BED3-505054503030}'
'Removable Storage' = '{0CCE9245-69AE-11D9-BED3-505054503030}'
'Central Policy Staging' = '{0CCE9246-69AE-11D9-BED3-505054503030}'
# Privilege Use
'Sensitive Privilege Use' = '{0CCE9228-69AE-11D9-BED3-505054503030}'
'Non Sensitive Privilege Use' = '{0CCE9229-69AE-11D9-BED3-505054503030}'
'Other Privilege Use Events' = '{0CCE922A-69AE-11D9-BED3-505054503030}'
# Detailed Tracking
'Process Creation' = '{0CCE922B-69AE-11D9-BED3-505054503030}'
'Process Termination' = '{0CCE922C-69AE-11D9-BED3-505054503030}'
'DPAPI Activity' = '{0CCE922D-69AE-11D9-BED3-505054503030}'
'RPC Events' = '{0CCE922E-69AE-11D9-BED3-505054503030}'
'Plug and Play Events' = '{0CCE9248-69AE-11D9-BED3-505054503030}'
# Policy Change
'Audit Policy Change' = '{0CCE922F-69AE-11D9-BED3-505054503030}'
'Authentication Policy Change' = '{0CCE9230-69AE-11D9-BED3-505054503030}'
'Authorization Policy Change' = '{0CCE9231-69AE-11D9-BED3-505054503030}'
'MPSSVC Rule-Level Policy Change' = '{0CCE9232-69AE-11D9-BED3-505054503030}'
'Filtering Platform Policy Change' = '{0CCE9233-69AE-11D9-BED3-505054503030}'
'Other Policy Change Events' = '{0CCE9234-69AE-11D9-BED3-505054503030}'
# Account Management
'User Account Management' = '{0CCE9235-69AE-11D9-BED3-505054503030}'
'Computer Account Management' = '{0CCE9236-69AE-11D9-BED3-505054503030}'
'Security Group Management' = '{0CCE9237-69AE-11D9-BED3-505054503030}'
'Distribution Group Management' = '{0CCE9238-69AE-11D9-BED3-505054503030}'
'Application Group Management' = '{0CCE9239-69AE-11D9-BED3-505054503030}'
'Other Account Management Events' = '{0CCE923A-69AE-11D9-BED3-505054503030}'
# DS Access
'Directory Service Access' = '{0CCE923B-69AE-11D9-BED3-505054503030}'
'Directory Service Changes' = '{0CCE923C-69AE-11D9-BED3-505054503030}'
'Directory Service Replication' = '{0CCE923D-69AE-11D9-BED3-505054503030}'
'Detailed Directory Service Replication' = '{0CCE923E-69AE-11D9-BED3-505054503030}'
# Account Logon
'Credential Validation' = '{0CCE923F-69AE-11D9-BED3-505054503030}'
'Kerberos Service Ticket Operations' = '{0CCE9240-69AE-11D9-BED3-505054503030}'
'Other Account Logon Events' = '{0CCE9241-69AE-11D9-BED3-505054503030}'
'Kerberos Authentication Service' = '{0CCE9242-69AE-11D9-BED3-505054503030}'
}
# Maps human-readable setting strings to numeric values for audit.csv
$Script:AuditSettingValue = @{
'No Auditing' = 0
'Success' = 1
'Failure' = 2
'Success and Failure' = 3
}
function Set-GPOAdvancedAuditPolicy {
<#
.SYNOPSIS
Writes an Advanced Audit Policy (audit.csv) to a GPO's SYSVOL path.
This provides subcategory-level audit control (53 subcategories)
instead of the 9 legacy Event Audit categories.
#>
param(
[Parameter(Mandatory)]
[string]$GPOName,
[Parameter(Mandatory)]
[hashtable]$AuditPolicy,
[string]$Domain = (Get-ADDomain).DNSRoot
)
$sysvolPath = Get-GPOSysvolPath -GPOName $GPOName -Domain $Domain
$auditDir = Join-Path $sysvolPath 'Machine\Microsoft\Windows NT\Audit'
$auditCsvPath = Join-Path $auditDir 'audit.csv'
if (-not (Test-Path $auditDir)) {
New-Item -ItemType Directory -Path $auditDir -Force | Out-Null
}
# Build CSV content
$sb = [System.Text.StringBuilder]::new()
[void]$sb.AppendLine('Machine Name,Policy Target,Subcategory,Subcategory GUID,Inclusion Setting,Exclusion Setting,Setting Value')
foreach ($subcategory in $AuditPolicy.Keys) {
$guid = $Script:AuditSubcategoryGuid[$subcategory]
if (-not $guid) {
Write-Host " [WARN] Unknown audit subcategory: '$subcategory'" -ForegroundColor Yellow
continue
}
$settingName = $AuditPolicy[$subcategory]
$settingValue = $Script:AuditSettingValue[$settingName]
if ($null -eq $settingValue) {
Write-Host " [WARN] Unknown audit setting value: '$settingName' for '$subcategory'" -ForegroundColor Yellow
continue
}
[void]$sb.AppendLine(",System,$subcategory,$guid,$settingName,,$settingValue")
}
# audit.csv uses UTF-8 with BOM
$utf8Bom = [System.Text.UTF8Encoding]::new($true)
[System.IO.File]::WriteAllText($auditCsvPath, $sb.ToString(), $utf8Bom)
Write-Host " Written: $auditCsvPath" -ForegroundColor Green
Write-Host " $($AuditPolicy.Count) audit subcategory setting(s) configured." -ForegroundColor Green
# Register Audit Policy CSE GUID
$auditCseGuid = '{F3BC9527-C350-4C90-861C-1EC90034520B}'
$auditToolGuid = '{D02B1F72-3407-48AE-BA88-E8213C6761F1}'
Add-GPOExtensionGuids -GPOName $GPOName -CseGuid $auditCseGuid -ToolGuid $auditToolGuid -Scope Machine -Domain $Domain
}
function Compare-GPOAdvancedAuditPolicy {
<#
.SYNOPSIS
Compares desired Advanced Audit Policy settings against the current
audit.csv in SYSVOL. Returns diff objects for mismatches.
#>
param(
[Parameter(Mandatory)]
[string]$GPOName,
[Parameter(Mandatory)]
[hashtable]$AuditPolicy,
[string]$Domain = (Get-ADDomain).DNSRoot
)
$sysvolPath = Get-GPOSysvolPath -GPOName $GPOName -Domain $Domain
$auditCsvPath = Join-Path $sysvolPath 'Machine\Microsoft\Windows NT\Audit\audit.csv'
$diffs = @()
Write-Host " Comparing advanced audit policy..." -ForegroundColor Yellow
# Parse existing audit.csv into a lookup
$currentSettings = @{}
if (Test-Path $auditCsvPath) {
$csvLines = [System.IO.File]::ReadAllLines($auditCsvPath, [System.Text.UTF8Encoding]::new($true))
foreach ($line in $csvLines) {
# Skip header and empty lines
if ($line -match '^Machine Name,' -or [string]::IsNullOrWhiteSpace($line)) { continue }
$fields = $line -split ','
if ($fields.Count -ge 5) {
$subcategory = $fields[2].Trim()
$inclusionSetting = $fields[4].Trim()
$currentSettings[$subcategory] = $inclusionSetting
}
}
}
foreach ($subcategory in $AuditPolicy.Keys) {
$guid = $Script:AuditSubcategoryGuid[$subcategory]
if (-not $guid) { continue }
$desired = $AuditPolicy[$subcategory]
$current = $currentSettings[$subcategory]
if ($current -ne $desired) {
$currentDisplay = if ($null -eq $current) { '(not set)' } else { $current }
Write-Host " [DRIFT] $subcategory`: '$currentDisplay' -> '$desired'" -ForegroundColor Red
$diffs += [PSCustomObject]@{
Type = 'AdvancedAudit'
Subcategory = $subcategory
Current = $currentDisplay
Desired = $desired
}
}
}
if ($diffs.Count -eq 0) {
Write-Host " [OK] Advanced audit policy matches desired state" -ForegroundColor Green
} else {
Write-Host " [DRIFT] $($diffs.Count) audit policy difference(s) found" -ForegroundColor Red
}
return $diffs
}