Active Directory重要组成员变更监控咨询:PowerShell脚本及Microsoft安全中心实现方法
Great question! Monitoring critical AD group membership changes (like Domain Admins) is a core security practice, and moving beyond just weekly full lists to tracking specific additions/removals will give you far more actionable insights. Let’s break down both PowerShell-based solutions and how to set this up in Microsoft Defender for Cloud (formerly Microsoft Security Center):
You have two solid approaches here, depending on whether you have AD auditing enabled:
1. Event Log-Based Script (Real-Time/Periodic Change Tracking)
This method leverages AD’s built-in audit logs to pull actual change events, which is more reliable than snapshot comparisons. First, ensure your domain controllers have Audit Security Group Management enabled via Group Policy (enable both Success and Failure audits under Computer Configuration > Windows Settings > Security Settings > Advanced Audit Policy Configuration > Audit Policies > Account Management).
Here’s a script that queries these events and sends targeted change alerts:
# Configure your environment variables $criticalGroup = "Domain Admins" $domainController = "DC01.yourdomain.local" # Replace with your DC name $alertRecipients = "security-team@yourdomain.local" $senderEmail = "ad-monitor@yourdomain.local" $smtpServer = "smtp.yourdomain.local" $lookbackHours = 168 # 7 days, adjust for your schedule (e.g., 24 for daily checks) # Get the group's SID to filter relevant events $group = Get-ADGroup -Identity $criticalGroup -Server $domainController $groupSID = $group.SID.Value # Pull security events for group membership changes $changeEvents = Get-WinEvent -ComputerName $domainController -FilterHashtable @{ LogName = "Security" ID = 4728, 4729 # 4728 = Add member, 4729 = Remove member StartTime = (Get-Date).AddHours(-$lookbackHours) } | Where-Object { $_.Properties[2].Value -eq $groupSID } # Format events into a readable report $changeReport = foreach ($event in $changeEvents) { $action = if ($event.Id -eq 4728) { "Added to" } else { "Removed from" } $member = $event.Properties[0].Value $actor = $event.Properties[4].Value $timestamp = $event.TimeCreated.ToString("yyyy-MM-dd HH:mm:ss") [PSCustomObject]@{ Timestamp = $timestamp Action = $action Group = $criticalGroup Member = $member ChangedBy = $actor } } # Send alert email if ($changeReport.Count -gt 0) { $htmlBody = $changeReport | ConvertTo-Html -Head "<style>table {border-collapse: collapse;} th, td {border:1px solid #ddd; padding:8px;} th {background:#f2f2f2;}</style>" Send-MailMessage -To $alertRecipients -From $senderEmail -Subject "ALERT: $criticalGroup Membership Changes" -Body ($htmlBody -join "") -BodyAsHtml -SmtpServer $smtpServer } else { # Optional: Send a "no changes" confirmation Send-MailMessage -To $alertRecipients -From $senderEmail -Subject "UPDATE: $criticalGroup - No Membership Changes" -Body "No changes detected in the last $lookbackHours hours." -SmtpServer $smtpServer }
2. Snapshot Comparison Script (For Environments Without Audit Logs)
If auditing isn’t enabled, you can track changes by comparing weekly snapshots of group members. This is simpler but less precise (it won’t capture when changes happened or who made them):
# Configure variables $criticalGroup = "Domain Admins" $historyPath = "C:\AD-Monitor\$criticalGroup-Members.csv" $alertRecipients = "security-team@yourdomain.local" $senderEmail = "ad-monitor@yourdomain.local" $smtpServer = "smtp.yourdomain.local" # Get current group members $currentMembers = Get-ADGroupMember -Identity $criticalGroup -Recursive | Select-Object Name, SamAccountName # Check if a history snapshot exists if (Test-Path $historyPath) { $previousMembers = Import-Csv $historyPath # Identify additions and removals $additions = Compare-Object $previousMembers $currentMembers -Property SamAccountName | Where-Object { $_.SideIndicator -eq "=>" } $removals = Compare-Object $previousMembers $currentMembers -Property SamAccountName | Where-Object { $_.SideIndicator -eq "<=" } # Build email body $emailBody = "<h3>$criticalGroup Membership Changes</h3>" if ($additions.Count -gt 0) { $emailBody += "<h4>Added Members:</h4><ul>" $additions | ForEach-Object { $emailBody += "<li>$($currentMembers | Where-Object SamAccountName -eq $_.SamAccountName | Select-Object -ExpandProperty Name) ($($_.SamAccountName))</li>" } $emailBody += "</ul>" } if ($removals.Count -gt 0) { $emailBody += "<h4>Removed Members:</h4><ul>" $removals | ForEach-Object { $emailBody += "<li>$($previousMembers | Where-Object SamAccountName -eq $_.SamAccountName | Select-Object -ExpandProperty Name) ($($_.SamAccountName))</li>" } $emailBody += "</ul>" } if ($additions.Count -eq 0 -and $removals.Count -eq 0) { $emailBody += "<p>No changes detected since last check.</p>" } # Send email Send-MailMessage -To $alertRecipients -From $senderEmail -Subject "$criticalGroup Membership Update" -Body $emailBody -BodyAsHtml -SmtpServer $smtpServer } else { # First run: create initial snapshot $currentMembers | Export-Csv $historyPath -NoTypeInformation Send-MailMessage -To $alertRecipients -From $senderEmail -Subject "AD Monitor Initialized: $criticalGroup" -Body "Baseline member list created. Future reports will compare against this snapshot." -SmtpServer $smtpServer } # Update history with current members $currentMembers | Export-Csv $historyPath -NoTypeInformation -Force
Schedule either script via Task Scheduler to run on your desired frequency (weekly, daily, etc.).
If you’re using a hybrid AD environment (or cloud-only Azure AD), Microsoft Defender for Cloud offers centralized, real-time monitoring with built-in alerting. Here’s how to set it up:
1. Prerequisites
- For on-prem AD: Ensure Azure AD Connect is configured to sync your domain groups and users to Azure AD.
- Enable Azure AD Audit Logs (this is enabled by default, but confirm in the Azure Portal > Azure AD > Audit logs).
2. Create a Custom Alert Rule
- Go to the Microsoft Defender for Cloud portal > Security alerts > Create alert rule.
- Under Condition:
- Select Signal name and search for signals like
Add member to grouporRemove member from group. - Add a filter for Target resource name equals
Domain Admins(or your critical group name).
- Select Signal name and search for signals like
- Under Action groups:
- Create or select an action group to send email alerts to your security team. You can also integrate with ticketing systems (e.g., ServiceNow) here.
- Set the Severity to High (since Domain Admins changes are critical) and configure any additional alert details.
3. Advanced Log Querying (Optional)
For deeper visibility, use Azure Monitor Logs to query audit logs directly. Example Kusto query for tracking Domain Admins changes:
AuditLogs | where OperationName in ("Add member to group", "Remove member from group") | where TargetResources has "Domain Admins" | project TimeGenerated, OperationName, InitiatedBy, TargetResources | sort by TimeGenerated desc
You can save this query and set up an alert to trigger whenever results are returned.
Key Benefits of This Approach
- Real-time alerts instead of weekly reports.
- Centralized monitoring across hybrid/cloud environments.
- Integration with other Microsoft security tools (e.g., Microsoft Sentinel for SIEM).
内容的提问来源于stack exchange,提问作者29yannic

