Infrastructure-as-code framework for Active Directory objects and Group Policy. Sanitized from production deployment for public sharing.
218 lines
9.9 KiB
PowerShell
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
|
|
}
|