In every enterprise environment, Active Directory (AD) group memberships play a pivotal role in access control and security. Unauthorized modifications to privileged groups like "Domain Admins" or "Enterprise Admins" can expose your organization to risk. Enter ADHawk: a simple but powerful PowerShell script that watches over your AD group memberships like a hawk—hence the name.
ADHawk is designed to run as a scheduled task every five minutes, automatically logging changes and sending email alerts for any detected modifications. Lightweight, modular, and highly customizable, this tool is perfect for security-conscious sysadmins who want real-time visibility without deploying heavyweight monitoring solutions.
What ADHawk Monitors
By default, ADHawk keeps a close eye on the following critical groups:
"Domain Admins", "Exchange Admins", "Enterprise Admins",
"Schema Admins", "Backup Operators", "Account Operators", "Server Operators"
You can easily modify this list to suit your organizational structure.
How It Works
- Initialization:
- Checks for a designated state directory (e.g.,
C:\customapps\adgroupmembers
). - Creates it if it doesn't exist.
- Checks for a designated state directory (e.g.,
- Group Enumeration:
- Fetches the current members of each monitored group via
Get-ADGroupMember
. - Stores each group’s state as a sorted list of
SamAccountNames
.
- Fetches the current members of each monitored group via
- Change Detection:
- Compares current membership against previously saved state.
- Uses
Compare-Object
to identify additions or removals.
- Notification & Logging:
- Constructs a detailed message with a timestamp and change summary.
- Sends the alert via email.
- Appends the event to a log file (
change.log
) for audit-ability.
- State Refresh:
- Updates the stored file with the current membership snapshot.
Email Notification Setup (REQUIRED EDIT)
Before using ADHawk in your environment, you must customize the following parameters:
$EmailFrom = "[email protected]"
$EmailTo = "[email protected],[email protected]"
$SMTPServer = "Your SMTP server IP here"
These fields define where your email alerts come from, who receives them, and which SMTP server relays them.
Implementation Steps
- Prerequisites:
- PowerShell with
ActiveDirectory
module installed - SMTP server configured and accessible
- PowerShell with
- Deployment:
- Save the full script to a
.ps1
file, e.g.,ADHawk.ps1
- Modify the group list or email fields as needed
- Create the directory
C:\customapps\adgroupmembers
- Save the full script to a
- Scheduling the Task:
- Open Task Scheduler
- Create a new task:
-
Trigger: Every 5 minutes
-
Action: Run
powershell.exe
with argument:-ExecutionPolicy Bypass -File "C:\Path\To\ADHawk.ps1"
-
Run with highest privileges
-
- Testing:
- Manually run the script and simulate changes by adding/removing users
- Verify emails are sent and logs are updated
Why ADHawk?
- Minimal Footprint: No agents or external dependencies
- Real-Time Monitoring: 5-minute check intervals provide near-instant detection
- Customizable: Choose which groups to watch and who gets notified
- Audit Trail: Keeps a log of every change for forensic or compliance reviews
Final Thoughts
ADHawk embodies what PowerShell does best—simple, direct, and effective automation. Whether you're a solo sysadmin or part of a larger security team, this script gives you a lightweight, proactive way to harden your AD infrastructure.
Try it out, customize it to your needs, and let ADHawk keep a vigilant eye on your domain.
#Another /\_[]_/\
# fine |] _||_ [|
# ___ \/ || \/
# /___\ ||
# (|0 0|) ||
# __/{\U/}\_ ___/vvv
# / \ {~} / _|_P|
# | /\ ~ /_/ []
# |_| (____)
# \_]/______\ Barberion
# _\_||_/_ Production
# (_,_||_,_)
#
#Requires -Modules ActiveDirectory
$groups = @("Domain Admins", "Exchange Admins", "Enterprise Admins", "Schema Admins", "Backup Operators", "Account Operators", "Server Operators")
$stateFilePath = "C:\customapps\adgroupmembers"
$logFilePath = "C:\customapps\adgroupmembers\change.log"
# directory exists?
if (-not (Test-Path $stateFilePath)) {
New-Item -Path $stateFilePath -ItemType Directory
}
# get group members and return as simple string array
function Get-GroupMembers {
param (
[string]$GroupName
)
Get-ADGroupMember -Identity $GroupName | Select-Object -ExpandProperty SamAccountName | Sort-Object
}
# send email notification
function Send-Email {
param (
[string]$Subject,
[string]$Body
)
$EmailFrom = "[email protected]"
$EmailTo = "[email protected],[email protected]"
$SMTPServer = "Your SMTP server IP here"
Send-MailMessage -From $EmailFrom -To $EmailTo -Subject $Subject -Body $Body -SmtpServer $SMTPServer
# Append to change.log
Add-Content -Path $logFilePath -Value $Body
Add-Content -Path $logFilePath -Value "rn" # Add a blank line
}
foreach ($group in $groups) {
$currentMembers = Get-GroupMembers -GroupName $group
$filePath = Join-Path -Path $stateFilePath -ChildPath "$group.csv"
if (Test-Path $filePath) {
$previousMembers = Get-Content $filePath
$differences = Compare-Object -ReferenceObject $previousMembers -DifferenceObject $currentMembers
if ($differences) {
$changes = $differences | ForEach-Object {
if ($_.SideIndicator -eq "<=") {
"$($_.InputObject) was removed from $group"
} else {
"$($_.InputObject) was added to $group"
}
}
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$body = "Changes detected at ${timestamp}:rn" + ($changes -join "rn")
Send-Email -Subject "AD Group Altered" -Body $body
}
}
# Always update the file with the current state for next comparison
$currentMembers | Out-File $filePath
}