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

by barberionApril 12th, 2025
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

ADHawk is a no-frills, practical PowerShell tool that automates the process of tracking, alerting, and logging changes to sensitive AD groups.

Company Mentioned

Mention Thumbnail
featured image - This PowerShell Script Watches Your Domain Admins Like a Hawk—Literally
barberion HackerNoon profile picture
0-item

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:\customapps\adgroupmembers).
    • Creates it if it doesn't exist.
  2. Group Enumeration:
    • Fetches the current members of each monitored group via Get-ADGroupMember.
    • Stores each group’s state as a sorted list of SamAccountNames.
  3. Change Detection:
    • Compares current membership against previously saved state.
    • Uses Compare-Object to identify additions or removals.
  4. 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.
  5. 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

  1. Prerequisites:
    • PowerShell with ActiveDirectory module installed
    • SMTP server configured and accessible
  2. 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
  3. 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

  4. 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
}


Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks