Disclaimer
This is my personal blog. The opinions and views I express are my own. The information I provide is on an as-is basis. I make no representations as to accuracy, completeness, currentness, suitability, or validity of any information on this blog and will not be liable for any errors, omissions, or delays in this information or any losses, injuries or damages arising from its use.

Hey PowerShell… Text me if my Domain Admins Group changes

This is why I Love PowerShell… It’s simple, yet functional.

From an Administrative perspective, I think we can all agree that any changes in your Domain Admins group without your knowledge would be of interest to you. If you’re in a large organization with access to enterprise management tools you probably have some widget that fires off a message to you or a group of people in the event a change is detected… or maybe you don’t.

If you’re an admin at a small business and maybe even some medium sized businesses, you may not have access to those enterprise management tools and widgets. Turns out, we can use PowerShell to monitor any group for us and notify us when a change occurs. It’s actually pretty simple.

You can even have PowerShell send you a text message… which is pretty cool.

I’m using the script to keep an eye on my Domain Admins Group but you could easily adapt it to monitor services or processes. You might want to monitor your Exchange Servers Transport service, if it stops for whatever reason send me an email and text message.

First, we have to get all the members of the Domain Admins Group and export to an xml file.

# Run this once to get the Domain Admins group baseline
Get-ADGroupMember -Server signalwarrant.local -Identity "Domain Admins" |
    Select-Object -ExpandProperty samaccountname | 
    Export-Clixml -Path 'C:\scripts\CurrentDomainAdmins.xml'

This is the script we’ll run on a schedule.

# This is the script we'll run on a regular basis

# Get the filehash of the CurrentDomainAdmins.xml
    $CurrentAdminsHash = Get-FileHash -Path 'C:\scripts\CurrentDomainAdmins.xml' | 
      Select-Object -expandProperty Hash
# Get the current date
    $Date = Get-Date
# This is the file we're testing the CurrentDomainAdmins.xml file against
    $newAdmins = 'c:\scripts\NewAdmins.xml'
# A variable we will use in the if statement below
    $Change = ''

# As we run the test we're going to get the contents of the Domain Admins Group
Get-ADGroupMember -Server signalwarrant.local -Identity 'Domain Admins' |
    Select-Object -ExpandProperty samaccountname | 
    Export-Clixml -Path $newAdmins -Force

# Get the filehash of the new file 
$NewAdminsHash = Get-FileHash -Path $newAdmins | Select-Object -expandProperty Hash

# If the CurrentDomainAdmins.xml (our baseline file) and NewAdmins.xml do not match
If ($NewAdminsHash -ne $CurrentAdminsHash){
    
    # Do all of this if a change is detected
    $Change = 'Yes'
    $ChangesDetected = 'Domain Admins Group changed detected on: ' + $date
    $ChangesDetected | Out-File -FilePath 'C:\scripts\DA_Changes.txt' -Append -Force
} else {

    # If no change detected just write when the script last ran
    $Change = 'No'
    $NoChangesDetected = 'No Changes detected on: ' + $Date
    $NoChangesdetected | Out-File -FilePath 'C:\scripts\DA_NoChanges.txt' -Append -Force
}

# Credentials for the email account
# Do not store cleartext passwords in scripts
# https://powershell.org/forums/topic/powershell-specifiy-a-literal-encrypted-standard-string/
# The above link will tell you why I had to do it.

# If your Email account is on the same domain as the machine you're running the script from
# I would suggest using this function to create your encrypted Password file.
# https://gist.github.com/davefunkel/415a4a09165b8a6027a297085bf812c5
$username = 'your email here'
$password = 'password for the above email address'
$secureStringPwd = $password | ConvertTo-SecureString -AsPlainText -Force 
$creds = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd

# If the test above fails and the $change = "yes" then send me an email and text message
# and attach the NewAdmins.xml
If ($Change -eq 'Yes') {
    # Code to send the email and lof the message sent in the EventLog
    $From = 'your email here'
    $To = 'your email here'
    $Cc = 'your email here'
    $Attachment = $newAdmins
    $Subject = '----Domain Admin Members has changed----'
    $Body = 'Your awesome PowerShell script has detected a change in your Domain Admin members'
    $SMTPServer = 'your smtp server address'
    $SMTPPort = '587'
    Send-MailMessage -From $From -to $To -Cc $Cc -Subject $Subject `
    -Body $Body -SmtpServer $SMTPServer -port $SMTPPort `
    -Credential $creds -Attachments $Attachment
}

These are the Action arguments for the scheduled task.
-NoLogo -NonInteractive -WindowStyle Hidden -NoProfile -Executionpolicy bypass -file “C:\scripts\AD_Audit.ps1”

 

7 Comments

  1. YP Chien | | Reply

    Get-ADGroupMember -Server signalwarrant.local -Identity “Domain Admins” |
    Select-Object -ExpandProperty samaccountname | Sort-Object -Descending |
    Export-Clixml -Path ‘C:\scripts\CurrentDomainAdmins.xml’

    Without the sort-object, it will always report changes even no member changes.

  2. Andrew | | Reply

    What about nested groups? Maybe add a -Recursive switch to your Get-ADGroupMember?

    • SignalWarrant | | Reply

      I didn’t think of nested groups. 🙂

  3. Philip | | Reply

    Just out of curiosity, but why not re-import the xml and do a compare-object. Then you can report what has changed.

    • SignalWarrant | | Reply

      I just wanted something quick and dirty. You certainly could compare the 2.

    • SignalWarrant | | Reply

      Thanks François-Xavier,

      Your script is much more comprehensive.

Leave a Reply to François-Xavier Cat (@LazyWinAdm) Cancel reply

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