This PowerShell Script Watches Your Domain Admins Like a Hawk—Literally

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

  1. Initialization:
  • Checks for a designated state directory (e.g., C:customappsadgroupmembers).
  • Creates it if it doesn’t exist.
  1. Group Enumeration:
  • Fetches the current members of each monitored group via Get-ADGroupMember.
  • Stores each group’s state as a sorted list of SamAccountNames.
  1. Change Detection:
  • Compares current membership against previously saved state.
  • Uses Compare-Object to identify additions or removals.
  1. 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.
  1. 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 = "ADHawk@YourCompanyHere.com"
$EmailTo = "notifyParty1@YourCompanyHere.com,notifyParty2@YourCompanyHere.com"
$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

  1. Prerequisites:
  • PowerShell with ActiveDirectory module installed
  • SMTP server configured and accessible
  1. 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:customappsadgroupmembers
  1. Scheduling the Task:
  • Open Task Scheduler

  • Create a new task:

    • Trigger: Every 5 minutes
    • Action: Run powershell.exe with argument:
       -ExecutionPolicy Bypass -File "C:PathToADHawk.ps1"
    
    • Run with highest privileges
  1. 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:customappsadgroupmembers"
$logFilePath = "C:customappsadgroupmemberschange.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 = "ADAccountHawk@YourCompanyHere.com"
    $EmailTo = "notifyParty1@YourCompanyHere.com,notifyParty2@YourCompanyHere.com"
    $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
}

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.