At my company, the system administrators have separate admin accounts to administer our server infrastructure. These admin accounts are often highly privileged and powerful accounts. Therefore, I would like to receive an e-mail notification when a user account is added to or removed from a group (in my previous post I shared with you a script to monitor just that), but added to that I also would like to receive a notification when for example the Password Never Expires option is ticked. Other scenarios may include notification when an admin account is created or deleted. Or when the password of an admin account has been changed. And I would like to know who has made these changes and when. As and added benefit, you can also claim to any auditor that you have a log of all changed made to your admin accounts by simply saving the e-mails.
In this post I would like to share with you the script I have made to monitor AD user account changes. This script will check all user account related events from the last hour. You can implement this script by running it every hour via a scheduled task.
!! Note that the scheduled task needs to be run with an account which has domain admin privileges to be able to read from the security logs of all your domain controllers. I would advice you to create and use a dedicated service account for running this scheduled task, and to limit the Logon To of this account to just the server running the scheduled task !!
The script needs some customization to your environment:
- variable $Time, as mentioned before, needs to be changed to the interval you will for the scheduled task (my preference is 1 hour)
- variable $ListOfMonitoredOUs needs to be changed to contain all OU’s that contain the groups you want to monitor
- variables $FromAddress, $ToAddress and $SMTPServer need to be updated to reflect the appropriate email addresses and SMTP server
This script also requires that user account managementr auditing has been enabled. I have found that this site provides a clear step-by-step guide explaining how to implement user account management auditing.
#############################################################################################################################
# // Start of section Script initialization. Load all required modules and declare base variables \\
If (-not (Get-Module -Name 'ActiveDirectory' -ErrorAction SilentlyContinue)) {
Import-Module ActiveDirectory
}
# \\ End of section Script initialization //
#############################################################################################################################
# // Fixed variable declaration \\
$LogEntry = @()
$LogEntries = @()
$FilteredLog = @()
# Dynamic variable declaration
$Time = (Get-Date).AddHours(-1)
$ListOfDCs = Get-ADDomainController -Filter { Name -like "*" }
$FromAddress = '<from email address>'
$ToAddress = '<to email address>'
$SMTPServer = '<SMTP server>'
# https://www.morgantechspace.com/2013/08/active-directory-change-audit-events.html
# The following table document lists the event IDs of the Security Group Management category.
$EventIDHashTable = [ordered]@{
'4720' = 'A user account was created.'
'4722' = 'A user account was enabled.'
'4723' = 'An attempt was made to change an accounts password.'
'4724' = 'An attempt was made to reset an accounts password.'
'4725' = 'A user account was disabled.'
'4726' = 'A user account was deleted.'
'4738' = 'A user account was changed.'
'4740' = 'A user account was locked out.'
'4767' = 'A user account was unlocked.'
'4780' = 'The ACL was set on accounts which are members of administrators groups.'
'4781' = 'The name of an account was changed.'
'4794' = 'An attempt was made to set the Directory Services Restore Mode administrator password'
'5376' = 'Credential Manager credentials were backed up.'
'5377' = 'Credential Manager credentials were restored from a backup.'
}
# GetSecurityLogEntries
ForEach ($DC in $ListofDCs) {
Write-Host "Processing domain controller $DC"
$LogEntries += (Get-WinEvent -ComputerName $DC.Hostname -FilterHashtable @{Logname = 'Security'; StartTime = $Time } -ErrorAction Ignore |
Where-Object { $_.TaskDisplayName -eq "User Account Management" -and $_.Message -notmatch "<filtered text="">" })
$LogEntries = $LogEntries | Sort-Object TimeCreated
}
#$LogEntries
# Process Log Entries
If ($LogEntries -ne "") {
ForEach ($LogEntry in $LogEntries) {
$Subject = "[$env:USERDOMAIN] - Eventid " + $LogEntry.ID + " - " + $EventIDHashTable.Item($LogEntry.Id.ToString())
$Subject
$MailBody = ($LogEntry | Format-List | Out-String)
Send-MailMessage `
-From $FromAddress `
-To $ToAddress `
-Subject $Subject `
-SmtpServer $SMTPServer `
-Body $MailBody
}
}
As always, please keep in mind this script is tailored to my environment, but can be used as a template for your environment. I do not pretend to be a PowerShell guru and as such my script may not be perfect. I am open to suggestions 🙂 . If you found this script useful, I’d appreciate it if you leave a comment.