How to Audit Active Directory Changes with Advanced Audit Policies on Windows Server 2025
Active Directory is a high-value target for attackers and a frequent source of compliance audit findings. Without proper change auditing, it is impossible to answer basic security questions: Who created that privileged account? When was this group modified? Who changed the domain password policy? Windows Server 2025 includes a powerful audit framework called Advanced Audit Policy Configuration that goes far beyond the basic “Audit account management” checkbox — it lets you enable specific subcategories with surgical precision, reducing log noise while ensuring every meaningful change is recorded. This tutorial walks through configuring advanced audit policies via Group Policy and auditpol.exe, identifying the most important event IDs for AD change tracking, filtering events with PowerShell, and forwarding logs for centralized collection.
Prerequisites
- Windows Server 2025 domain controllers (auditing policy applies to the DC where the change occurs)
- Group Policy Management Console (GPMC) installed
- Domain Admin or Group Policy management rights
- Windows Remote Management (WinRM) enabled if querying event logs remotely with PowerShell
- Optional: Windows Event Forwarding (WEF) collector server or a SIEM solution
- Sufficient disk space on DCs for Security event log growth (recommended minimum: 4 GB log size)
Step 1: Understand Advanced Audit Policy vs Basic Audit Policy
Windows has two audit policy systems that can conflict if both are configured:
- Basic Audit Policy: Found at Computer Configuration → Windows Settings → Security Settings → Local Policies → Audit Policy. Coarse-grained — one setting controls an entire category (e.g., “Audit account management”).
- Advanced Audit Policy Configuration: Found at Computer Configuration → Windows Settings → Security Settings → Advanced Audit Policy Configuration. Fine-grained — individual subcategories within each category can be independently enabled for Success, Failure, or both.
Enable a Group Policy setting to prevent basic policy from overriding advanced settings:
# Verify the "Force audit policy subcategory settings" flag is enabled
# This is set via GPO: Security Settings -> Local Policies -> Security Options
# Policy: "Audit: Force audit policy subcategory settings (Windows Vista or later)
# to override audit policy category settings"
# Set to: Enabled
# Confirm the flag is set on a DC via registry
Get-ItemProperty `
"HKLM:SYSTEMCurrentControlSetControlLsa" `
-Name "SCENoApplyLegacyAuditPolicy" |
Select-Object SCENoApplyLegacyAuditPolicy
# Value 1 = Advanced Audit Policy is active; Basic Audit Policy is suppressed
Step 2: Configure Advanced Audit Policy via Group Policy
Create a dedicated GPO for DC auditing and link it to the Domain Controllers OU. This ensures the policy applies to all current and future DCs:
# Create and link a new GPO for DC Advanced Auditing
New-GPO -Name "DC-Advanced-Audit-Policy" -Domain "contoso.com" -Comment "AD change auditing"
New-GPLink -Name "DC-Advanced-Audit-Policy" `
-Target "OU=Domain Controllers,DC=contoso,DC=com" `
-LinkEnabled Yes `
-Enforced Yes
# Force GPO update on all DCs
$DCs = (Get-ADDomainController -Filter *).Name
Invoke-Command -ComputerName $DCs -ScriptBlock { gpupdate /force }
In the Group Policy Editor, navigate to Computer Configuration → Windows Settings → Security Settings → Advanced Audit Policy Configuration → Audit Policies and configure the following subcategories:
- Account Management: User Account Management — Success, Failure; Security Group Management — Success, Failure; Computer Account Management — Success
- DS Access: Directory Service Changes — Success; Directory Service Access — Success, Failure; Directory Service Replication — Failure
- Logon/Logoff: Logon — Success, Failure; Account Lockout — Success
- Privilege Use: Sensitive Privilege Use — Success, Failure
- Policy Change: Audit Policy Change — Success; Authentication Policy Change — Success
Step 3: Configure Audit Policy with auditpol.exe
auditpol.exe provides command-line control over audit subcategories, useful for scripting and verification. Apply changes directly or use it to confirm what GPO has configured:
# View current audit policy for all categories
auditpol /get /category:*
# View a specific category
auditpol /get /category:"Account Management"
# Enable key subcategories for AD auditing
auditpol /set /subcategory:"User Account Management" /success:enable /failure:enable
auditpol /set /subcategory:"Security Group Management" /success:enable /failure:enable
auditpol /set /subcategory:"Computer Account Management" /success:enable
auditpol /set /subcategory:"Directory Service Changes" /success:enable
auditpol /set /subcategory:"Directory Service Access" /success:enable /failure:enable
auditpol /set /subcategory:"Audit Policy Change" /success:enable
auditpol /set /subcategory:"Sensitive Privilege Use" /success:enable /failure:enable
auditpol /set /subcategory:"Logon" /success:enable /failure:enable
auditpol /set /subcategory:"Account Lockout" /success:enable
# Export the current audit policy to a backup file
auditpol /backup /file:C:TempAuditPolicy-Backup.csv
# Restore audit policy from a backup
auditpol /restore /file:C:TempAuditPolicy-Backup.csv
# Apply the same policy to multiple DCs remotely
$DCs = (Get-ADDomainController -Filter *).Name
foreach ($DC in $DCs) {
Invoke-Command -ComputerName $DC -ScriptBlock {
auditpol /set /subcategory:"Directory Service Changes" /success:enable
auditpol /set /subcategory:"User Account Management" /success:enable /failure:enable
auditpol /set /subcategory:"Security Group Management" /success:enable /failure:enable
}
}
Step 4: Key Event IDs for Active Directory Change Auditing
Once the audit policies are active, the following event IDs in the Security event log on domain controllers capture the most important AD changes:
User Account Events
- 4720 — A user account was created
- 4722 — A user account was enabled
- 4723 — An attempt was made to change an account’s password
- 4724 — An attempt was made to reset an account’s password (by admin)
- 4725 — A user account was disabled
- 4726 — A user account was deleted
- 4738 — A user account was changed (attribute modified)
- 4740 — A user account was locked out
- 4767 — A user account was unlocked
Group Membership Events
- 4728 — A member was added to a security-enabled global group
- 4729 — A member was removed from a security-enabled global group
- 4732 — A member was added to a security-enabled local group
- 4756 — A member was added to a security-enabled universal group
Directory Object Attribute Events (DS Access)
- 5136 — A directory service object was modified (attribute-level change detail)
- 5137 — A directory service object was created
- 5138 — A directory service object was undeleted
- 5139 — A directory service object was moved
- 5141 — A directory service object was deleted
Step 5: Query Events with Get-WinEvent and PowerShell
Use PowerShell to query Security event logs locally or remotely for specific AD change events. These snippets are useful for quick investigations and can be adapted into scheduled reports:
# Find all user account creations in the last 24 hours
$StartTime = (Get-Date).AddHours(-24)
Get-WinEvent -ComputerName DC01 -FilterHashtable @{
LogName = 'Security'
Id = 4720
StartTime = $StartTime
} | ForEach-Object {
$Xml = [xml]$_.ToXml()
[PSCustomObject]@{
Time = $_.TimeCreated
NewUser = ($Xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text'
CreatedBy = ($Xml.Event.EventData.Data | Where-Object { $_.Name -eq 'SubjectUserName' }).'#text'
DomainName = ($Xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetDomainName' }).'#text'
}
}
# Find group membership changes (4728, 4732, 4756) in the last 7 days
$StartTime = (Get-Date).AddDays(-7)
Get-WinEvent -ComputerName DC01 -FilterHashtable @{
LogName = 'Security'
Id = 4728, 4729, 4732, 4733, 4756, 4757
StartTime = $StartTime
} | ForEach-Object {
$Xml = [xml]$_.ToXml()
[PSCustomObject]@{
Time = $_.TimeCreated
EventId = $_.Id
MemberName = ($Xml.Event.EventData.Data | Where-Object { $_.Name -eq 'MemberName' }).'#text'
GroupName = ($Xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text'
ChangedBy = ($Xml.Event.EventData.Data | Where-Object { $_.Name -eq 'SubjectUserName' }).'#text'
}
} | Format-Table -AutoSize
# Find all attribute changes on AD objects (Event 5136) in the last hour
$StartTime = (Get-Date).AddHours(-1)
Get-WinEvent -ComputerName DC01 -FilterHashtable @{
LogName = 'Security'
Id = 5136
StartTime = $StartTime
} | ForEach-Object {
$Xml = [xml]$_.ToXml()
[PSCustomObject]@{
Time = $_.TimeCreated
ObjectDN = ($Xml.Event.EventData.Data | Where-Object { $_.Name -eq 'ObjectDN' }).'#text'
AttributeName = ($Xml.Event.EventData.Data | Where-Object { $_.Name -eq 'AttributeLDAPDisplayName' }).'#text'
NewValue = ($Xml.Event.EventData.Data | Where-Object { $_.Name -eq 'AttributeValue' }).'#text'
ChangedBy = ($Xml.Event.EventData.Data | Where-Object { $_.Name -eq 'SubjectUserName' }).'#text'
}
} | Format-List
# Export a full daily change report for compliance
$Report = Get-WinEvent -ComputerName DC01 -FilterHashtable @{
LogName = 'Security'
Id = 4720, 4726, 4728, 4756, 5136, 5137, 5141
StartTime = (Get-Date).Date
} | ForEach-Object {
[PSCustomObject]@{
Time = $_.TimeCreated
EventId = $_.Id
Message = $_.Message -replace "`r`n", " "
}
}
$Report | Export-Csv "C:ReportsADChanges-$(Get-Date -Format 'yyyy-MM-dd').csv" -NoTypeInformation
Step 6: Expand Security Log Size on Domain Controllers
# Increase the Security log maximum size to 4 GB on all DCs
$DCs = (Get-ADDomainController -Filter *).Name
Invoke-Command -ComputerName $DCs -ScriptBlock {
# Set Security log max size to 4 GB (4294967296 bytes)
wevtutil sl Security /ms:4294967296
# Set retention policy to overwrite as needed (do not archive automatically)
wevtutil sl Security /rt:false
# Confirm settings
wevtutil gl Security | Select-String "maximumSizeInBytes|fileMode"
}
Step 7: Collect Events with Windows Event Forwarding
Centralise DC security logs on a dedicated Windows Event Forwarding (WEF) collector so that events are preserved even if a DC is compromised or its log is cleared:
# On the WEF Collector server — enable the Windows Event Collector service
wecutil qc /q
# Create a WEF subscription for AD audit events
$SubscriptionXml = @'
AD-Audit-Events
SourceInitiated
Collect AD change audit events from all DCs
true
http://schemas.microsoft.com/wbem/wsman/1/windows/EventLog
MinLatency
<![CDATA[
*[System[(EventID=4720 or EventID=4726 or EventID=4728 or EventID=4729
or EventID=4732 or EventID=4756 or EventID=5136 or EventID=5137
or EventID=5141 or EventID=4738 or EventID=4740 or EventID=4767)]]
]]>
2060000
O:NSG:NSD:(A;;GA;;;DC)
'@
$SubscriptionXml | Out-File "C:TempAD-Audit-Sub.xml" -Encoding utf8
wecutil cs "C:TempAD-Audit-Sub.xml"
# On each DC — allow WEF and add the collector to the Event Log Readers group
# Apply via GPO: Computer Config > Windows Settings > Security Settings > System Services
# Windows Remote Management (WS-Management) — set to Automatic
# Add WEF collector computer account to the Event Log Readers group on DCs
Add-ADGroupMember -Identity "Event Log Readers" -Members "WEFCOLLECTOR$"
# Verify subscription status on the collector
wecutil gr "AD-Audit-Events"
Conclusion
Advanced Audit Policy Configuration on Windows Server 2025 gives you precise, low-noise visibility into every significant change in your Active Directory environment. By targeting specific subcategories — particularly Directory Service Changes (Event 5136), User Account Management, and Security Group Management — you capture the data needed to detect privilege escalation, account abuse, and unauthorized configuration changes without flooding your Security log with irrelevant events. Pair this with expanded log sizes, PowerShell-based alerting scripts, and Windows Event Forwarding to a centralised collector, and you have a solid foundation for both real-time threat detection and compliance reporting. Regularly review your audit policy coverage as your environment evolves, and ensure the WEF collector and any SIEM integrations are consuming and indexing the forwarded events correctly.