See also those related BlogPosts:
- [2013/11/28] - Version 1.6 - [UPDATE] PowerShell - Monitor and Report Active Directory Group Membership Change
- [2013/10/13] - Version 1.5 - PowerShell - Monitor and Report Active Directory Group Membership Change
A couple of weeks back, my boss asked me to set a quick monitoring tool to check membership change made on Active Directory groups.
In my case here i'm talking about "Domain Admins" and "Enterprise Admins"
Unfortunately we currently don't have a tool in place to do this.
So why not taking advantage of Powershell ? :-)
Required
-A Script to monitor a list of Groups
-Create a Scheduled Task to run every minutes
(if you set the Scheduled task on a Windows Server 2008R2 or a Windows 7, you might want to take a look at my previous post: Run this task every minute !!!)
Description
This script will first check the members and export the result to a CSV file (if it does not exist yet) If a file already exist, it content will be compared with the result of $Members If different an email is sent to $EmailTo email with the member who has been added or removed.
Script
http://gallery.technet.microsoft.com/Monitor-Active-Directory-4c4e04c7
#requires -version 2.0 # ############################################################################# # NAME: TOOL-Monitor-AD_DomainAdmins_EnterpriseAdmins.ps1 # # AUTHOR: Francois-Xavier CAT # DATE: 2012/02/01 # EMAIL: info@lazywinadmin.com # # COMMENT: This script is monitoring group(s) in Active Directory and send an email when # someone is added or removed # # REQUIRES: # -Quest AD Snapin # -A Scheduled Task # # VERSION HISTORY # 1.0 2012.02.01 Initial Version. # 1.1 2012.03.13 CHANGE to monitor both Domain Admins and Enterprise Admins # 1.2 2013.09.23 FIX issue when specifying group with domain 'DOMAIN\Group' # CHANGE Script Format (BEGIN, PROCESS, END) # ADD Minimal Error handling. (TRY CATCH) # # ############################################################################# BEGIN { TRY{ # Monitor the following groups $Groups = "Domain Admins","Enterprise Admins" # The report is saved locally $ScriptPath = (Split-Path ((Get-Variable MyInvocation).Value).MyCommand.Path) $DateFormat = Get-Date -Format "yyyyMMdd_HHmmss" # Email information $Emailfrom = "sender@company.local" $Emailto = "receive@company.local" $EmailServer = "emailserver.company.local" # Quest Active Directory Snapin if (!(Get-PSSnapin Quest.ActiveRoles.ADManagement -ErrorAction Silentlycontinue)) {Add-PSSnapin Quest.ActiveRoles.ADManagement} } CATCH{Write-Warning "BEGIN BLOCK - Something went wrong"} } PROCESS{ TRY{ FOREACH ($item in $Groups){ # Let's get the Current Membership $GroupName = Get-Qadgroup $item $Members = Get-QADGroupMember $item -Indirect | Select-Object Name, SamAccountName, DN $EmailSubject = "PS MONITORING - $GroupName Membership Change" # Store the group membership in this file $StateFile = "$($GroupName.domain.name)_$($GroupName.name)-membership.csv" # If the file doesn't exist, create one If (!(Test-Path $StateFile)){ $Members | Export-csv $StateFile -NoTypeInformation } # Now get current membership and start comparing it to the last lot we recorded # catching changes to membership (additions / removals) $Changes = Compare-Object $Members $(Import-Csv $StateFile) -Property Name, SamAccountName, DN | Select-Object Name, SamAccountName, DN, @{n='State';e={ If ($_.SideIndicator -eq "=>"){ "Removed" } Else { "Added" } } } # If we have some changes, mail them to $Email If ($Changes) { $body = $($Changes | Format-List | Out-String) $smtp = new-object Net.Mail.SmtpClient($EmailServer) $smtp.Send($emailFrom, $emailTo, $EmailSubject, $body) } #Save current state to the csv $Members | Export-csv $StateFile -NoTypeInformation -Encoding Unicode } } CATCH{Write-Warning "PROCESS BLOCK - Something went wrong"} }#PROCESS END{"Script Completed"} #end region script
Hi
ReplyDeleteThanks for your great script but I facing challanges in this script.
Every time I got the alert of added and removed user list. I need only the list of if someone add or removed the groups not all users.
also If I can connect our child domain domain admins groups then it would be great for me..
pls guide..
Hey Gopi, thanks for the comment.
DeleteNot sure I understand correctly.
You want to get an alert only if a group object is added to the group you monitor, is that right ? You don't want to receive alert when user objects are added to the monitored group.
Please send me the script and some more details here: fxcat@lazywinadmin.com
Thanks
Thanks Xavier for your reply,
ReplyDeleteI have sent you mail as well describing below:
We have parent domain and child domain scenario, While running the above script on child domain, it providing all users list like below everytime.
Name : gopi.chand
SamAccountName : gchand-admin
DN : CN=chand\, gopi,OU=IT,OU=Admins,OU=Management,DC=contoso,DC=com
State : Removed
Name : test
SamAccountName : test
DN : CN=test,gopi,OU=IT,OU=Admins,OU=Management,DC=contoso,DC=com
State : Added
Also, We need to enterprise admin, Schema Admins of parent domain monitoring in the same script if possible.
I have modified your original script to more suit my needs in that I use ActiveDirectory modules vice quest. Additionally I also needed to be able to support a Root and Child domain at the same time.
ReplyDelete# Original script from: http://www.lazywinadmin.com/2012/03/powershell-monitor-membership-change-to.html
Clear-Host
# Import Active Directory Modules, if needed
if (!(Get-Module ActiveDirectory)) {Import-Module ActiveDirectory}
# A little setup for dealing with Null Groups
$GroupName = @()
$NullGroups = New-Object PSObject -Property @{
Name = "No Users or Groups"
SamAccountName = "No Users or Groups"
}
# - Monitoring the following Groups -
$ChildGroups = "Domain Admins"
$RootGroups = "Enterprise Admins","Domain Admins","Schema Admins"
# Loop through each child domain group to add "Domain"
foreach ($ChildGroup in $ChildGroups)
{
$GroupName += New-Object PSObject -Property @{
GPName = $ChildGroup;
Domain = 0
}
}
# Loop through each Root domain group to add "domain"
foreach ($RootGroup in $RootGroups)
{
$GroupName += New-Object PSObject -Property @{
GPName = $RootGroup;
Domain = 1
}
}
# Set up the logs path (I wanted to keep the logs separate from the actual script)
$ScriptPath = (Split-Path ((Get-Variable MyInvocation).Value).MyCommand.Path) + "\Logs"
if (!(Test-Path $ScriptPath))
{
New-Item -Path $ScriptPath -ItemType Directory | Out-Null
}
$emailFrom = "PSGroupMonitoring@yourEmail.com"
$EmailTo = "YourEmail@yourEmail.com"
$smtp = "YourSMTPServerName"
foreach ($Group in $GroupName)
{
switch ($Group.Domain)
{
0 {$domain = (Get-ADDomain).DNSRoot}
1 {$domain = (Get-ADDomain).ParentDomain}
}
[array]$members = Get-ADGroupMember $Group.GPName -server $domain | select Name, SamAccountName
Write-Host "$($Group.GPName) Count = [$($members.count)]"
$EmailSubject = "PS MONITORING - $($Group.GPName) Membership Change"
$StateFile = "$($Group.GPName)_$($Group.Domain)_membership.csv"
if (!($members))
{
$members = $NullGroups
}
if (!(Test-Path (Join-Path $ScriptPath $StateFile)))
{
# Create the file if one does not already exist
$members | Export-Csv (Join-Path $ScriptPath $StateFile) -NoTypeInformation
$subj = "PS Monitoring - $($Group.GPName)"
$body = "$($Group.GPName), is now being monitored.`n`nNew baseline files have been created and stored at $(Join-Path $ScriptPath $StateFile)"
Send-MailMessage -To $EmailTo -From $emailFrom -Subject $subj -body $body -SmtpServer $smtp
}
# Get the current membership and start comparing to the last one
$Changes = Compare-Object $Members $(Import-Csv (Join-Path $ScriptPath $StateFile)) -Property Name, SamAccountName | Select-Object Name, SamAccountName,@{n='State';e={If ($_.SideIndicator -eq "=>") {"Removed"} Else {"Added"}}}
if ($Changes)
{
$body = $changes | ConvertTo-Html | Out-String
Send-MailMessage -To $EmailTo -From $emailFrom -Subject $EmailSubject -body $body -BodyAsHtml -SmtpServer $smtp
# Update the CVS file with new Changes, only if there are changes
$Members | Export-csv (Join-Path $ScriptPath $StateFile) -NoTypeInformation
}
}
Nice script! Thanks for sharing!!! :-)
Delete