A Missed Event Log Cost a Client Their Domain Admin
Last year, a mid-size logistics company we manage came to us after discovering that a domain admin account had been compromised for over three weeks. The attacker used it to create shadow admin accounts, modify group memberships, and stage data for exfiltration. The worst part? The domain controllers were generating almost no useful audit data. Default audit policies were untouched. No DS Access auditing. No logon event granularity. The attacker’s modifications to Active Directory objects left virtually zero trace in the Security event log.
That incident reinforced something I’ve seen repeatedly across client environments: Active Directory audit policies are either misconfigured, set to legacy defaults, or never configured at all. And when an incident hits, the forensic team is left reconstructing a timeline from scraps.
This post walks through exactly how to configure advanced audit policies using Group Policy and PowerShell — the way we rebuilt auditing for that client and the way I configure it for every engagement now.
Why Legacy Audit Policies Are a Liability
Windows has two tiers of audit policy: the legacy policy (pre-Windows 7) and the advanced audit policy. The legacy policy gives you nine broad categories — Account Logon, Object Access, Directory Service Access, and so on. The advanced audit policy breaks those nine categories into 53 subcategories, each independently configurable for success, failure, or both.
The difference matters. With legacy auditing enabled on “Directory Service Access,” you get a firehose of Event ID 4662 entries for every AD object read. With advanced audit policies, you can enable just Audit Directory Service Changes (a subcategory under DS Access) and capture only modifications — the events that actually matter during incident response.
I’ll say it plainly: if you’re still relying on legacy audit categories in 2026, you’re flying blind in the exact scenarios where visibility matters most — privilege escalation (MITRE ATT&CK T1078), account manipulation (T1098), and lateral movement via credential access.
The Override Setting You Cannot Skip
Here’s a caveat that trips up even experienced admins. If both legacy and advanced audit policies are configured, legacy wins by default. To force advanced policies to take precedence, you must enable this Group Policy setting:
Computer Configuration → Windows Settings → Security Settings → Local Policies → Security Options → Audit: Force audit policy subcategory settings (Windows Vista or later) to override audit policy category settings
Set it to Enabled. Without this, your carefully tuned subcategory settings will be silently ignored. We’ve inherited environments from other vendors where advanced policies were configured perfectly — and completely overridden by a legacy “Audit everything” setting no one remembered applying. After inheriting a poorly documented environment from another MSP, this is one of the first things we check now.
Configuring Advanced Audit Policies via Group Policy
The correct approach for domain controllers is to configure audit policies through the Default Domain Controllers Policy GPO, or a dedicated GPO linked to the Domain Controllers OU. I prefer a dedicated GPO for audit settings — it’s cleaner to manage and won’t collide with other security baselines.
Step-by-Step: Enabling DS Access Auditing
DS Access is the audit category that tracks who is reading, modifying, or replicating Active Directory objects. It has four subcategories:
- Audit Directory Service Access — logs read operations against AD objects
- Audit Directory Service Changes — logs create, modify, delete, move, and undelete operations
- Audit Directory Service Replication — logs replication events between DCs
- Audit Detailed Directory Service Replication — granular replication packet-level logging
For most environments, you want Directory Service Changes enabled for Success events at minimum. Here’s the GPO path:
- Open
gpmc.msc(Group Policy Management Console). - Navigate to the Domain Controllers OU for your domain.
- Right-click the Default Domain Controllers Policy (or your dedicated audit GPO) and select Edit.
- Expand:
Computer Configuration → Policies → Windows Settings → Security Settings → Advanced Audit Policy Configuration → Audit Policies → DS Access. - Double-click Audit Directory Service Changes.
- Check Configure the following audit events, then select Success (and optionally Failure).
- Click OK.
Repeat for Audit Directory Service Access if you need read-level visibility. Be warned: enabling success auditing on Directory Service Access generates significant volume. On a domain with 5,000+ objects and regular LDAP queries, you can easily hit tens of thousands of Event ID 4662 entries per hour. For most clients, we enable it only for Failure events unless there’s a specific detection use case.
Configuring SACL Entries for Object-Level Auditing
Enabling the audit policy alone isn’t enough. You also need System Access Control List (SACL) entries on the AD objects you want to monitor. This is the piece many admins miss.
- Open Active Directory Users and Computers with Advanced Features enabled (View → Advanced Features).
- Right-click the OU or object you want to audit and select Properties → Security → Advanced → Auditing.
- Add a new audit entry. Set the Principal to
Everyone(or a specific group). - Set Type to Success.
- Set Applies to:
This object and all descendant objects. - Select the permissions you want to audit — for change detection, choose Write all properties, Delete, Delete subtree, and Modify permissions.
Without SACLs in place, your audit policies will generate zero events for object modifications. The policy says “audit this category,” and the SACL says “audit this specific object.” Both are required.
PowerShell: Querying and Managing Audit Policies
Group Policy is the right mechanism for persistent, domain-wide audit configuration. But PowerShell is indispensable for querying current state, validating deployments, and rapid incident response.
Reviewing Current Audit Configuration
The auditpol.exe utility is the fastest way to check what’s actually applied on a domain controller:
# List all advanced audit policy subcategories and their current settings
auditpol /get /category:*
# Check DS Access specifically
auditpol /get /subcategory:"Directory Service Changes"
auditpol /get /subcategory:"Directory Service Access"
This tells you what the domain controller is actually enforcing, regardless of what GPO says it should be. I cannot count how many times the output of auditpol /get has contradicted what the GPO showed — usually because of conflicting policies, failed GPO application, or that legacy override setting I mentioned earlier.
Setting Audit Policies with PowerShell
For temporary testing or incident response scenarios, you can set audit policies directly via PowerShell using auditpol.exe:
# Enable success auditing for Directory Service Changes
auditpol /set /subcategory:"Directory Service Changes" /success:enable /failure:enable
# Enable success auditing for Logon events (useful during active IR)
auditpol /set /subcategory:"Logon" /success:enable /failure:enable
# Enable credential validation auditing (detects brute-force and pass-the-hash)
auditpol /set /subcategory:"Credential Validation" /success:enable /failure:enable
Important caveat: changes made directly with auditpol are temporary. The next Group Policy refresh cycle — or a manual gpupdate /force — will overwrite them with whatever the GPO defines. This is actually useful during incident response when you need immediate visibility without waiting for GPO replication, but don’t rely on it for permanent configuration.
Querying Event Logs with Get-WinEvent
Once audit policies are generating events, PowerShell becomes your primary analysis tool. Get-WinEvent is the modern replacement for the older Get-EventLog cmdlet and supports filtering with XML queries and hashtables:
# Find all Directory Service Changes events in the last 24 hours
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 5136, 5137, 5138, 5139, 5141
StartTime = (Get-Date).AddHours(-24)
} | Select-Object TimeCreated, Id, Message | Format-List
# Event ID reference for DS Access:
# 5136 = Directory Service object modified
# 5137 = Directory Service object created
# 5138 = Directory Service object undeleted
# 5139 = Directory Service object moved
# 5141 = Directory Service object deleted
For a client in the financial sector, we built a scheduled PowerShell script that queries these event IDs every 15 minutes and forwards critical changes (group membership modifications, OU deletions, GPO changes) to their SIEM. It’s not a replacement for native SIEM log forwarding, but it acts as a backup detection layer when WEF (Windows Event Forwarding) has issues — which it does, more often than Microsoft’s documentation suggests.
# Detect group membership changes (Event ID 4728, 4732, 4756 for adds)
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4728, 4732, 4756
StartTime = (Get-Date).AddHours(-1)
} | ForEach-Object {
$xml = [xml]$_.ToXml()
[PSCustomObject]@{
Time = $_.TimeCreated
EventId = $_.Id
# Extract the account that was added
MemberSid = ($xml.Event.EventData.Data | Where-Object Name -eq 'MemberSid').'#text'
# Extract the group that was modified
GroupName = ($xml.Event.EventData.Data | Where-Object Name -eq 'TargetUserName').'#text'
# Extract who made the change — critical for attribution
ChangedBy = ($xml.Event.EventData.Data | Where-Object Name -eq 'SubjectUserName').'#text'
}
}
That script has caught unauthorized group modifications in two separate engagements. One was a compromised service account adding itself to Domain Admins at 2 AM. The other was an IT contractor who had been terminated but whose account wasn’t disabled for 11 days. Both would have been invisible without DS Access auditing.
Automating GPO-Based Audit Policy Deployment
For environments with multiple domains or forests, manually clicking through the GPMC isn’t scalable. The PowerShell GroupPolicy module can automate GPO creation and linking, though audit policy subcategories specifically require a different approach.
Creating a Dedicated Audit GPO
# Create a new GPO for audit settings
$AuditGPO = New-GPO -Name "DC-Security-Audit-Policy" -Comment "Advanced audit policy for domain controllers"
# Disable User Configuration (not needed for audit policies)
$AuditGPO.GpoStatus = 'UserSettingsDisabled'
# Link the GPO to the Domain Controllers OU
New-GPLink -Name "DC-Security-Audit-Policy" -Target "OU=Domain Controllers,DC=contoso,DC=com" -LinkEnabled Yes
The catch: the GroupPolicy PowerShell module doesn’t natively support setting advanced audit policy subcategories through Set-GPRegistryValue or similar cmdlets. The subcategory settings live in a CSV file (audit.csv) inside the GPO’s Machine\Microsoft\Windows NT\Audit directory, not in registry keys.
The practical approach is to configure one GPO manually through GPMC, export it with Backup-GPO, and import it into other domains:
# Export the configured audit GPO
Backup-GPO -Name "DC-Security-Audit-Policy" -Path "C:\GPOBackups"
# Import into another domain's GPO
Import-GPO -BackupGpoName "DC-Security-Audit-Policy" -Path "C:\GPOBackups" -TargetName "DC-Security-Audit-Policy" -CreateIfNeeded
We use this method across multi-domain client environments. Configure once, validate, export, deploy everywhere. It’s predictable and auditable — you can diff the audit.csv files between GPO backups to verify consistency.
The Audit Categories That Actually Matter for Detection
All 53 subcategories exist for a reason, but enabling all of them on every system is a fast path to log volume that overwhelms your SIEM and your analysts. Here’s what I configure for domain controllers in every client engagement, mapped to the threats they detect:
| Subcategory | Success | Failure | Detects |
|---|---|---|---|
| Directory Service Changes | Yes | Yes | AD object modification, GPO tampering |
| Directory Service Access | No | Yes | Failed AD object access (recon attempts) |
| Credential Validation | Yes | Yes | Brute force, password spraying (T1110) |
| Logon | Yes | Yes | Lateral movement, RDP, network logons (T1021) |
| Special Logon | Yes | No | Privileged logon sessions, admin activity |
| Security Group Management | Yes | Yes | Group membership changes (T1098) |
| User Account Management | Yes | Yes | Account creation, deletion, password resets |
| Computer Account Management | Yes | Yes | Machine account abuse (T1136) |
| Authentication Policy Change | Yes | Yes | Kerberos policy changes, trust modifications |
| Audit Policy Change | Yes | Yes | Attacker disabling audit trails (T1562.002) |
This is opinionated. Some teams enable more. But I’ve found this baseline catches the kill chain stages that matter — initial access validation, privilege escalation, persistence through group membership, and defense evasion through audit tampering — without generating so much noise that alerts become meaningless.
If your organization is running a SIEM and forwarding Windows Security logs, you also need to think about log retention. Check that your domain controller Security log is sized appropriately — I recommend a minimum of 4 GB for the Security log on DCs. The default 20 MB fills up in minutes under proper auditing. You can set this via GPO under Computer Configuration → Administrative Templates → Windows Components → Event Log Service → Security → Maximum Log Size.
Validating Your Audit Configuration
Deploying audit policies without validation is a false sense of security. Here’s a validation sequence I run after every audit policy deployment:
# Step 1: Force GPO update on the target DC
Invoke-GPUpdate -Computer "DC01" -Force -RandomDelayInMinutes 0
# Step 2: Verify the policy applied correctly
Invoke-Command -ComputerName DC01 -ScriptBlock {
auditpol /get /subcategory:"Directory Service Changes"
auditpol /get /subcategory:"Credential Validation"
auditpol /get /subcategory:"Security Group Management"
auditpol /get /subcategory:"Logon"
}
# Step 3: Generate a test event and confirm it appears
# Create a test OU, then check for Event ID 5137
New-ADOrganizationalUnit -Name "AuditTest-DeleteMe" -Path "DC=contoso,DC=com"
Start-Sleep -Seconds 5
# Verify the creation event was logged
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 5137
} -MaxEvents 5 | Select-Object TimeCreated, Message
# Clean up
Remove-ADOrganizationalUnit -Identity "OU=AuditTest-DeleteMe,DC=contoso,DC=com" -Confirm:$false
If Event ID 5137 doesn’t appear after creating that OU, something is broken — either the GPO didn’t apply, the override setting isn’t enabled, or SACLs are missing. Troubleshoot in that order.
During a migration project for a healthcare client last year, we discovered that their audit policies had been configured correctly in the GPO but never generated a single event in six months. The root cause? The SACL on the domain root had been removed during an earlier permission cleanup by their previous IT vendor. Policies without SACLs are decorative. Always validate end to end.
Tying Audit Data to Your Detection Pipeline
Raw event logs on a domain controller are useful for forensics but useless for real-time detection. The audit events need to flow into a centralized system — whether that’s a SIEM, a log aggregator, or at minimum a Windows Event Forwarding (WEF) collector.
For organizations still building out their monitoring stack, the combination of properly configured AD audit policies and a PowerShell-based alerting script can bridge the gap. We’ve deployed this approach for several clients who needed detection capabilities before their SIEM deployment was complete.
The key event IDs to prioritize in your detection rules:
- 4728/4732/4756 — Member added to security-enabled group (global/local/universal). Any unexpected addition to Domain Admins, Enterprise Admins, or Schema Admins should trigger an immediate alert.
- 5136 — AD object modified. Filter for changes to
adminCount,servicePrincipalName(Kerberoasting setup — T1558.003), andmsDS-AllowedToDelegateTo(delegation abuse). - 4624 Type 10 — RDP logon. On domain controllers, RDP access should be tightly controlled. Any logon from an unexpected source warrants investigation.
- 4719 — Audit policy changed. If an attacker disables auditing, this is the last event you’ll see. It’s a critical canary. This maps directly to MITRE ATT&CK T1562.002 (Impair Defenses: Disable Windows Event Logging).
If you’re also tracking endpoint forensics across your fleet, techniques like USB device connection logging complement AD audit data by providing a physical-layer view of how data moves through the environment.
Common Pitfalls and How to Avoid Them
GPO Precedence Conflicts
If you have audit settings in both the Default Domain Controllers Policy and a custom GPO linked to the same OU, GPO precedence rules apply. The GPO with the highest link order wins for conflicting settings. Use gpresult /h report.html on a DC to see the Resultant Set of Policy (RSoP) and confirm which GPO is actually applying your audit settings.
Log Volume Explosion
Enabling success auditing on “Directory Service Access” for a busy domain will generate massive log volume. One of our long-term accounts — a manufacturing company with 12,000 AD objects — saw their Security log roll over every 8 minutes after enabling this subcategory with overly broad SACLs. Be surgical with your SACL entries. Audit specific OUs and specific permission types, not “Full Control” on the domain root.
Replication Delay
GPO changes replicate on the AD replication schedule, not instantly. In multi-site environments, it can take 15 minutes to several hours for audit policy changes to reach all DCs. Run repadmin /syncall /AdeP to force immediate replication if you need audit coverage now — during an active incident, for example. For organizations planning infrastructure changes like AD migrations or consolidations, audit policy consistency across all DCs should be a pre-migration validation checkpoint.
WMI Filter Gotchas
If your audit GPO uses WMI filters (for example, to target only Server 2022 DCs), verify the filter syntax carefully. A malformed WMI query silently prevents the GPO from applying. No errors in gpresult, no warnings — just silent non-application.
Building a Baseline Audit Policy with auditpol
For documentation and disaster recovery purposes, export your audit policy baseline and store it alongside your other infrastructure-as-code artifacts:
# Export current audit policy to CSV
auditpol /backup /file:C:\AuditBaseline\dc-audit-policy.csv
# Restore audit policy from backup (useful for DR scenarios)
auditpol /restore /file:C:\AuditBaseline\dc-audit-policy.csv
# Compare current policy against baseline
$current = auditpol /get /category:* /r | ConvertFrom-Csv
$baseline = Import-Csv C:\AuditBaseline\dc-audit-policy.csv
Compare-Object $baseline $current -Property 'Subcategory','Inclusion Setting' |
Where-Object SideIndicator -eq '=>' |
Select-Object Subcategory, 'Inclusion Setting'
That comparison script has saved us during more than one engagement where audit policies drifted after a Windows Update or a well-intentioned admin “cleaned up” GPOs. Attackers who target audit policies (and groups like FIN7 and APT29 have been documented doing exactly this) count on the fact that nobody is monitoring the monitoring.
What to Do Next
If you take one thing from this post, let it be this: run auditpol /get /category:* on your domain controllers today. Right now. If the output shows “No Auditing” across DS Access subcategories, you have a critical visibility gap. An attacker can modify group memberships, reset passwords, and create backdoor accounts without generating a single log entry.
Configure the ten subcategories from the table above. Set your SACLs. Validate with a test event. Forward the logs. Build detection rules around the key event IDs. This isn’t optional hardening — it’s the foundation of every AD security monitoring capability.
For related reading on securing your AD environment against specific attack vectors, see how ransomware operators exploit Windows infrastructure once they gain domain access — the audit policies in this article are precisely what gives you the visibility to catch them before encryption begins.
If your environment needs audit policy configuration, SIEM integration, or an AD security assessment, reach out to our team. We’ve done this for environments ranging from 50-seat offices to multi-domain forests with 30,000+ objects. Getting audit right is the single highest-ROI security investment you can make in a Windows environment.


