Cyber Security

PowerShell: Notify me when someone is added to the Administrator Group

Will you be notified when there are changes to group memberships? No? Memberships in groups are particularly interesting. Especially if it is the group of the domain administrators. The following article shows how to recognize changes and then check them at regular intervals. The administrator should be notified of any changes. This can be done by message or e-mail. Instead of configuring Audit Policies we do everything in PowerShell and then we put our script into a scheduled task.

The Goal

We want to achieve the following.

Unbenannt

If there are membership changes in the Domain Admins Group, then notifiy me by E-Mail or Message or whatever. It could be look like this:

6.PNG

Or this:

1.JPG

Introduction

First we have to retrieve all Domain Admin group members.

Get-ADGroupMember -Identity "Domain Admins").Name

1.PNG

Alternatively, we could save it in a file Admins.txt:

(Get-ADGroupMember -Identity "Domain Admins").Name | Out-File C:\Temp\Admins.txt

I now add a new user to the group. His name is Arnold Schwarzenberg. Similarities to famous persons are purely coincidental. 😉

Then I save the result in another file Admins2.txt

(Get-ADGroupMember -Identity "Domain Admins").Name | Out-File C:\Temp\Admins2.txt

Now let’s have a look at both files.

3.PNG

Our next step is to compare the content of both files. In order to do that I use Compare-Object.

$a=Get-Content C:\Temp\Admins.txt
$b=Get-Content C:\Temp\Admins2.txt
$differ=Compare-Object -ReferenceObject $a -DifferenceObject $b | Select-Object -ExpandProperty InputObject

4.PNG

Fine. We’ve got him!

Another method is to save the group members in a variable. This is my preferred way. I don’t like those text files 😉

$ref=(Get-ADGroupMember -Identity "Domain Admins").Name
$diff=(Get-ADGroupMember -Identity "Domain Admins").Name

Create a Script to compare membership on a regular basis once per day

Open PowerShell ISE. Let’s put it all together in a script. The first script initiates a Message on the Administrator’s desktop. It checks the members and then waits for about an hour. Then the script checks again and compares the result. Now we use the SideIndicator. This indicator could be helpful if you only want to query changes of values in one direction. The valid values are => and <=

$ref=(Get-ADGroupMember -Identity "Domain Admins").Name
Start-Sleep -Seconds 86398
$diff=(Get-ADGroupMember -Identity "Domain Admins").Name
$result=(Compare-Object -ReferenceObject $ref -DifferenceObject $diff | Where-Object {$_.SideIndicator -eq "=>"} | Select-Object -ExpandProperty InputObject) -join ", "
If ($result)
{msg * "The following user was added to the Domain Admins Group: $result"}

The second one sends an alert E-Mail.

$ref=(Get-ADGroupMember -Identity "Domain Admins").Name
Start-Sleep -Seconds 86398
$diff=(Get-ADGroupMember -Identity "Domain Admins").Name
$date=Get-Date -Format F
$result=(Compare-Object -ReferenceObject $ref -DifferenceObject $diff | Where-Object {$_.SideIndicator -eq "=>"} | Select-Object -ExpandProperty InputObject) -join ", "
If ($result)
{Send-MailMessage -From SecurityAlert@domain.com -To p.gruenauer@domain.com -SmtpServer EX01 -Subject "Domain Admin Membership Changes | $result was added to the Group" -Body "This alert was generated at $date" -Priority High}

Note the last line. You must fill in these values. Make sure your Mailserver accepts E-Mails from your computer.

The Test

For testing, I’ve simplified the script and sent PowerShell to sleep for only 20 seconds. In this period I quickly add a user to the domain admins group. That was stressful 😉

5.PNG

We’ve got him again!

Now save your script as PowerShell file. (ps1)

Put it into a Scheduled Task

No matter which notification you prefer, you should put it all into a scheduled task that will run every 60 minutes, for example. Watch the Argument in the first line (location of your script), the RepititionInterval in the second line and the UserId in the 4th line. You have to modify this values, especially the UserId.

$Action=New-ScheduledTaskAction -Execute "powershell" -Argument "C:\Alerts\domain_admins.ps1"
$Trigger=New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Seconds 86400) -RepetitionDuration ([timespan]::MaxValue)
$Set=New-ScheduledTaskSettingsSet
$Principal=New-ScheduledTaskPrincipal -UserId "sid-500\administrator" -LogonType S4U
$Task=New-ScheduledTask -Action $Action -Trigger $Trigger -Settings $Set -Principal $Principal
Register-ScheduledTask -TaskName "Domain Admins Check" -InputObject $Task -Force

Create a script based on a baseline

The disadvantage of the method above is that we have a time gap of 2 seconds per day.

If the administrator group membership changes very rarely, I recommend creating a baseline. First save your baseline to a file.

 (Get-ADGroupMember -Identity "Domain Admins").Name | Out-File C:\Temp\Admins.txt 

Then create a script which compares the group membership against your baseline.

$base=Get-Content C:\Temp\Admins.txt
$diff=(Get-ADGroupMember -Identity "Domain Admins").Name
$result=(Compare-Object -ReferenceObject $base -DifferenceObject $diff | Where-Object {$_.SideIndicator -eq "=>"} | Select-Object -ExpandProperty InputObject) -join ", "
If ($result)
{msg * "The following user was added to the Domain Admins Group: $result"}

Unbenannt.PNG

Now put this script into a Scheduled Task and run it as often as you like.

Adaption

A further idea would be creating two Scheduled Tasks. (One for the reference, the second for the differences). Another possibility would be to configure audit logging in combination with event log subscriptions.

Anyway: Take the opportunity to use the ideas shown above and adapt it.

See also

See also my other article in which I created a small script which informs you if a Domain Controller is down: PowerShell: Alert me, if a Domain-Controller is down (Try + Catch)

29 replies »

  1. One significant oversight in that process is handling nested groups. We’ve typically nested groups in the Domain Admins group to define roles and service accounts to control access needs.

    If an account was added to a nested group, this script would not catch it.

    Like

    • Hallo Marc, thx your the advice. Yes, in nested groups this script will in it’s original state not work. As mentioned, if you want to do real time professionale monitoring the script has to be more than 10 lines of code for sure.

      Like

  2. I run this every 10 minutes from the monitoring software, PRTG. It alerts if the value changes:

    $users = Get-ADGroupMember -Identity ‘Domain Admins’
    $admins = $users.count
    write-host $admins,”:OK”

    Liked by 1 person

    • Hello,

      I am also using PRTG but this script doesn’t work with me.It all shows green when I added users to Domain Admins group:) If possible could you give me further details.

      Thanks in advance

      Like

      • Hi

        You need to change the “If Value Changes” on the settings page – this way everything will bumble along as normal until PRTG detects there’s been a change in the number of AD admins 🙂

        Like

  3. This isn’t perfect but something to play with. Avoid the scheduled job.

    function watch-group {

    param ($groupname)

    $membercount = (get-adgroupmember $groupname).count

    start-job -name watchgroup -scriptblock {

    param ($groupname,
    $membercount)

    while ($true) {

    $searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]”)
    $searcher.Filter = “(&(objectClass=group)(samAccountName=$groupname))”
    $result = $searcher.FindOne()
    $group = [ADSI]$result.path

    if ($membercount -ne $group.member.count) {

    $host.ui.rawui.windowtitle = “Group membership changed.”

    }

    start-sleep -seconds 30
    }

    } -argumentlist $groupname, $membercount | out-null

    if (!($timer)) {

    $timer = new-object timers.timer

    $action = {

    $Global:windowtitle = receive-job -name watchgroup -keep
    }

    $timer.Interval = 10000

    $Timer.Enabled = $True

    Register-ObjectEvent -InputObject $timer -EventName elapsed –SourceIdentifier groupTimer -Action $action | Out-Null

    $Timer.Start()

    }

    }

    watch-group ‘domain admins’

    Like

Leave a Reply to Onur B. Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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