Let’s look at how to create a simple administrator notification system when someone adds a new user to the important Active Directory security group. For example you want to track the changes of domain administrator group, and if a new user is added to it, you want to get the corresponding notification (by e-mail or in a pop-up alert message).
There are to ways to implement it:
- You can enable the event audit on the domain controllers and track the event of adding a new user to the security group (EventID 4728);
- You can store a local text file with the list of users of a certain group and regularly compare it to the current members list of the domain group.
Audit of Adding a User to a Group on the Domain Controller
If the audit policy is enabled in the GPO section Computer Configuration -> Windows Settings -> Security Settings -> Advanced Audit Configuration -> Account Management -> Audit Security Group Management, the event with the EventID 4732 (A member was added to a security-enabled global group) appears in the Security log after adding a new user to any Active Directory group.
Using PowerShell, you can track this event in the Security log. For example, let’s display all events with this ID on the domain controller for the last 24 hours. To make it more convenient, we’ll display the name of the AD group that has changed, the name of the added account and the administrator who has added this user to the group. The script is similar to the one given in the article How to Get all Active Directory Users Created in the Last 24 Hours.
$CurrTime = (get-date) - (new-timespan -hour 24)
Get-WinEvent -FilterHashtable @{LogName="Security";ID=4732;StartTime=$CurrTime}| Foreach {
$event = [xml]$_.ToXml()
if($event)
{
$CurrTime = Get-Date $_.TimeCreated -UFormat "%Y-%d-%m %H:%M:%S"
$New_GrpUser = $event.Event.EventData.Data[0]."#text"
$AD_Group = $event.Event.EventData.Data[2]."#text"
$AdminWhoAdded = $event.Event.EventData.Data[6]."#text"
$dc = $event.Event.System.computer
$dc + “|” + $CurrTime + “|” + “|” + $AD_Group + “|” + $New_GrpUser + “|” + $AdminWhoAdded
}
}
Then create a new scheduler task on the domain controller to be triggered by the event with the ID 4732. When this event occurs, a message will be sent to the user. ( use the Windows Event Triggers to attach a script to event).
However, the problem is that the security log of only one DC is checked. If a user has been added to a group on another domain controller, you won’t see this event. Of course, you can subscribe to the events of several DCs or run the script on each controller, but if there are a lot of DCs in the domain, it is not very convenient.
$time = (get-date) - (new-timespan -hour 124)
$DCs = Get-ADDomainController -Filter *
foreach ($DC in $DCs){
Get-WinEvent -ComputerName $DC -FilterHashtable @{LogName="Security";ID=4732;StartTime=$Time}| Foreach {
$event = [xml]$_.ToXml()
if($event)
{
CurrTime = Get-Date $_.TimeCreated -UFormat "%Y-%d-%m %H:%M:%S"
$New_GrpUser = $event.Event.EventData.Data[0]."#text"
$AD_Group = $event.Event.EventData.Data[2]."#text"
$AdminWhoAdded = $event.Event.EventData.Data[6]."#text"
$dc = $event.Event.System.computer
$dc + “|” + $CurrTime + “|” + “|” + $AD_Group + “|” + $New_GrpUser + “|” + $AdminWhoAdded
}
}
}
Let’s consider another approach.
Comparing the Current Members of the Domain Group with the Saved Template
Let’s display the list of users in the “Domain Admin” group using the Get-ADGroupMember cmdlet and save the resulting list to a text file (we are building a recursive list of users including nested groups):
(Get-ADGroupMember -Identity "Domain Admins" -recursive).Name | Out-File C:\PS\DomainAdmins.txt
Then add a new user to the “Domain Admins” group and save the list of users again to another file:
(Get-ADGroupMember -Identity "Domain Admins" -recursive).Name | Out-File C:\PS\DomainAdminsActual.txt
Now compare two files and display the difference in the lists:
$old_adgroup_members=GC C:\PS\DomainAdmins.txt
$new_adgroup_members=GC C:\PS\DomainAdminsActual.txt
$diff=Compare-Object -ReferenceObject $old_adgroup_members -DifferenceObject $new_adgroup_members | Select-Object -ExpandProperty InputObject
write-host $diff
The new account added to the AD group is displayed.
You can also display the message in the console:
$result=(Compare-Object -ReferenceObject $old_adgroup_members -DifferenceObject $diff | Where-Object {$_.SideIndicator -eq "=>"} | Select-Object -ExpandProperty InputObject) -join ", "
If ($result)
{msg * "A user $result has been added to Domain the Admins group"}
Or send an email using Send-MailMessage cmdlet:
If ($result)
{Send-MailMessage -SmtpServer war-msg01 -From [email protected] -To [email protected] -Subject "A user $result has been added to the Domain Admins group" -Body "Created on $date" -Priority High}
You can save this script to a file admins_group_changes.ps1 and run it regularly using Task Scheduler (you can create scheduled task using PowerShell ). Create a new Scheduler job that will run your PowerShell script every 24 hours. It will compare the members of the Domain Admins group with the list saved locally.
$Trigger= New-ScheduledTaskTrigger -At 17:00am -Daily
$User= "NT AUTHORITY\SYSTEM"
$Action= New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "C:\PS\admins_group_changes.ps1 "
Register-ScheduledTask -TaskName "Check Domain Group Changes" -Trigger $Trigger -User $User -Action $Action -RunLevel Highest –Force
Thus, the members of the Domain administrator group will be checked once a day, and if there are any changes, an administrator will get an alert (in a pop-up window or by email).
3 comments
I tried the ‘Comparing the Current Members of the Domain Group with the Saved Template’ part but it doesn’t work. It writes the files with the correct content but something in diff goes wrong.
(Get-ADGroupMember -Identity “Domain Admins” -recursive).Name | Out-File C:\PS\DomainAdmins.txt
(Get-ADGroupMember -Identity “Domain Admins” -recursive).Name | Out-File C:\PS\DomainAdminsActual.txt
$old_adgroup_members=GC C:\PS\DomainAdmins.txt
$new_adgroup_members=GC C:\PS\DomainAdminsActual.txt
$diff=Compare-Object -ReferenceObject $old_adgroup_members -DifferenceObject $new_adgroup_members | Select-Object -ExpandProperty InputObject
write-host $diff
$result=(Compare-Object -ReferenceObject $old_adgroup_members -DifferenceObject $diff | Where-Object {$_.SideIndicator -eq “=>”} | Select-Object -ExpandProperty InputObject) -join “, ”
If ($result)
{msg * “A user $result has been added to Domain the Admins group”}
Compare-Object : Cannot bind argument to parameter ‘DifferenceObject’ because it is null.
At C:\ps\da2.ps1:7 char:81
+ … -ReferenceObject $old_adgroup_members -DifferenceObject $diff | Where …
+ ~~~~~
+ CategoryInfo : InvalidData: (:) [Compare-Object], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.CompareObje
ctCommand
Please, make sure that your DomainAdmins.txt and DomainAdminsActual.txt files are not empty.
This only seems to work if you add users to security groups on the domain controller itself, not if someone adds a user on their workstation — it won’t generate an event on the DC. I’m only getting event ID 4728 when the user is added locally on the DC. If I add a user to a security group on my workstation via AD, I generate event ID 4732 on my local workstation, but nothing on the DC.