UPDATE 2016/05/03: The most recent update is available on Github
See also the related blogpost: http://www.lazywinadmin.com/2013/11/update-powershell-monitor-and-report.html
Today I will update a post that I published at the beginning of last year : Monitor Active Directory Membership changes. I updated the script to add some of the things I learned during the Scripting Games 2013 back in April/May. The script will also create a nice html report and send it via Email.
Basically, the script will monitor the Active Directory groups that you specify and notify you if a change occurred since the last time it checked.
Overview
- How does the script works ?
- Main Process
- Comparing
- Change History
- Reporting
- What does this script does not cover ?
- Workflow
- Requirements
- PowerShell 3.0
- Quest Active Directory Snapin
- A Schedule task (Automate it!)
- Permissions
- Running the Script the first time
- Running the Script after the first change
- Running the Script after the second change
- Comments Based Help
- Download
How does the script works ?
Main Process
This script checks an Active Directory Group membership that you specify and notify you if a change occurred since the last time it checked.In order to find the right group to monitor, you can specify the group Name, SID(Security Identifier), GUID(Globally Unique IDentifier) or DN (Distinguished Name).
Group name like 'DOMAIN\GROUPNAME' will also work.
Comparing
The membership of each group is saved in a CSV file "DOMAIN_GROUPNAME-membership.csv"
If the file does not exist, the script will create one, so the next time it will be able to compare the membership with this file.
Change History
Each time a change is detected (Add or Remove an Account (Nested or Not)) a CSV file will be generated with the following name: "DOMAIN_GROUPNAME-ChangesHistory-yyyyMMdd-hhmmss.csv"
Reporting
Here is an example of report generated when a change is detected.You can see the user 'catfx' was removed from the group FX\FXGROUP
Also, If the script find some Change History files for this group, it will be added to the report.
Finally at the end of the report, information on when, where and who ran the script.
Example of Email Report generated by the script |
What does this script does not cover ?
This script won't:
- Use the Active Directory module (Next update)
- Tell you who changed the Group Membership in Active Directory (You would need to active Auditing in Active Directory)
- Create the Schedule Task for you
- Generate a HTML file (Next update)
Workflow
The script is a bit complex to understand, so I created a small workflow that explain how each parts interact with each other:
Requirements
PowerShell v3.0
You will need PowerShell version 3.0 to take advantage [mailaddress] which make a validation on the Source and Destination Email addresses.Quest Active Directory PowerShell Snappin
I used the Quest Active Directory Snapin to do my queries, get it hereIn the next update I plan to add support for the Active Directory module (maybe ADSI too).
A Scheduled task (Automate it!!)
You will need to configure a Scheduled task that will run your task for you every minute
- Make sure the account that will run the task is an Administrator OR is member of the Local Security Policy "Log on as a batch job".
- Create your task and make sure it runs every minutes!
- I recommend to assign a dedicated AD account to this task
Permissions
This PowerShell script will need some rights, it will:
- Create CSV files inside of the script parent directory
- Make sure the account you use for this job has the rights to write files inside the parent directory of this script (this does not apply if the account is part of the Local Administrators group)
- Access the Active Directory (read)
- Make sure the account you use has the rights to read the membership of the group(s) you want to monitor.
Running the Script the first time
In this example I run the script against 2 Active Directory Groups with the verbose parameter so it will let me know what it's doing.
.\TOOL-MONITOR-AD_Groups.ps1 -verbose -Group "FXGROUP", "FXGROUP2" -EmailServer "mail.fx.local" -EmailTo "catfx@fx.local" -EmailFrom "PowerShellMonitoring@fx.local"
VERBOSE: Creating the Output Folder : C:\LazyWinAdmin\Output VERBOSE: Creating the ChangeHistory Folder : C:\LazyWinAdmin\ChangeHistory VERBOSE: GROUP: FXGROUP VERBOSE: FXGROUP - The following file did not exist: FX_FXGROUP-membership.csv VERBOSE: FXGROUP - Exporting the current membership information into the file: FX_FXGROUP-membership.csv VERBOSE: FXGROUP - Comparing Current and Before VERBOSE: FXGROUP - Compare Block Done ! VERBOSE: FXGROUP - No Change VERBOSE: GROUP: FXGROUP2 VERBOSE: FXGROUP2 - The following file did not exist: FX_FXGROUP2-membership.csv VERBOSE: FXGROUP2 - Exporting the current membership information into the file: FX_FXGROUP2-membership.csv VERBOSE: FXGROUP2 - Comparing Current and Before VERBOSE: FXGROUP2 - Compare Block Done ! VERBOSE: FXGROUP2 - No Change VERBOSE: Script Completed
As you can see, the first time you run the script it will create the two directories 'Output' and 'ChangeHistory'
Output: contains the membership files
ChangeHistory: contains all the change that occurred since the script is operational.
In the Output folder, the script save the current membership of each groups |
Running the script after making a first change on a group
I changed the membership of the group FX\FXGROUPA change is detected by the script, so it creates a file for this group. |
Then the script send the following Email Report:
The script send an email with the above report. Notice there is no 'Change History' since no previous changes were detected |
Running the script after making a second change on a group
Again, I changed the membership of the group FX\FXGROUP,
A second Change History file is created by the script |
You will notice that the email you receive is a bit different. It will contains the Change History of the first file (the previous change made at first) "FX_FXGROUP-ChangeHistory-20131013_185831.csv"
This time the Email Report is a bit different, the script did detect some previous change and include a 'Change History' table in the Email Report. |
Comments Based Help
Let's test the help now...PS C:\LazyWinAdmin> Get-Help .\TOOL-MONITOR-AD_Groups.ps1 -full
NAME C:\LazyWinAdmin\TOOL-MONITOR-AD_Group.ps1 SYNOPSIS This script is monitoring group(s) in Active Directory and send an email when someone is changing the membership. SYNTAX C:\LazyWinAdmin\TOOL-MONITOR-AD_Group.ps1 [-Group] <string> [-Emailfrom] <mailaddress> [-Emailto] <mailaddress> [-EmailServer] <string> [<commonparameters>] DESCRIPTION This script is monitoring group(s) in Active Directory and send an email when someone is changing the membership. It will also report the Change History made for this/those group(s). PARAMETERS -GroupSpecifies the group(s) to query in Active Directory. You can also specify the 'DN','GUID','SID' or the 'Name' of your group(s). Using 'Domain\Name' will also work. Required? true Position? 1 Default value Accept pipeline input? false Accept wildcard characters? false -Emailfrom Specifies the Email Address of the Sender Required? true Position? 2 Default value Accept pipeline input? false Accept wildcard characters? false -Emailto Specifies the Email Address of the Destination Required? true Position? 3 Default value Accept pipeline input? false Accept wildcard characters? false -EmailServer Specifies the Email Server IPAddress/FQDN Required? true Position? 4 Default value Accept pipeline input? false Accept wildcard characters? false This cmdlet supports the common parameters: Verbose, Debug, ErrorAction, ErrorVariable, WarningAction, WarningVariable, OutBuffer, PipelineVariable, and OutVariable. For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). INPUTS System.String OUTPUTS Email Report NOTES NAME: TOOL-Monitor-AD_Group.ps1 AUTHOR: Francois-Xavier CAT DATE: 2012/02/01 EMAIL: info@lazywinadmin.com REQUIREMENTS: -Read Permission in Active Directory on the monitored groups -Quest Active Directory PowerShell Snapin -A Scheduled Task (in order to check every X seconds/minutes/hours) 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) 1.3 2013.10.05 CHANGE in the PROCESS BLOCK, the TRY CATCH blocks and placed them inside the FOREACH instead of inside the TRY block ADD support for Verbose CHANGE the output file name "DOMAIN_GROUPNAME-membership.csv" ADD a Change History File for each group(s) example: "GROUPNAME-ChangesHistory-yyyyMMdd-hhmmss.csv" ADD more Error Handling ADD a HTML Report instead of plain text ADD HTML header ADD HTML header for change history 1.4 2013.10.11 CHANGE the 'Change History' filename to "DOMAIN_GROUPNAME-ChangesHistory-yyyyMMdd-hhmmss.csv" UPDATE Comments Based Help ADD Some Variable Parameters 1.5 2013.10.13 ADD the full Parameter Names for each Cmdlets used in this script ADD Alias to the Group ParameterName -------------------------- EXAMPLE 1 -------------------------- C:\PS>.\TOOL-Monitor-AD_Group.ps1 -Group "FXGroup" -EmailFrom "From@Company.com" -EmailTo "To@Company.com" -EmailServer "mail.company.com" This will run the script against the group FXGROUP and send an email to To@Company.com using the address From@Company.com and the server mail.company.com. -------------------------- EXAMPLE 2 -------------------------- C:\PS>.\TOOL-Monitor-AD_Group.ps1 -Group "FXGroup","FXGroup2","FXGroup3" -EmailFrom "From@Company.com" -Emailto "To@Company.com" -EmailServer "mail.company.com" This will run the script against the groups FXGROUP,FXGROUP2 and FXGROUP3 and send an email to To@Company.com using the address From@Company.com and the Server mail.company.com. -------------------------- EXAMPLE 3 -------------------------- C:\PS>.\TOOL-Monitor-AD_Group.ps1 -Group "FXGroup" -EmailFrom "From@Company.com" -Emailto "To@Company.com" -EmailServer "mail.company.com" -Verbose This will run the script against the group FXGROUP and send an email to To@Company.com using the address From@Company.com and the server mail.company.com. Additionally the switch Verbose is activated to show the activities of the script. -------------------------- EXAMPLE 4 -------------------------- C:\PS>.\TOOL-Monitor-AD_Group.ps1 -Group "FXGroup" -EmailFrom "From@Company.com" -Emailto "Auditor@Company.com","Auditor2@Company.com" -EmailServer "mail.company.com" -Verbose This will run the script against the group FXGROUP and send an email to 2 persons using the address From@Company.com and the server mail.company.com. Additionally the switch Verbose is activated to show the activities of the script. RELATED LINKS
Download
Github Repo
Technet Script Repository
Thanks for Reading! If you have any questions, leave a comment or send me an email at fxcat@lazywinadmin.com. I invite you to follow me on Twitter @lazywinadm
Great Work !
ReplyDeleteThanks for sharing :)
But I was just wondering if when a Group membership changes, does that create some sort of event ?
Can we create a event subscription and perform the operation then? I guess that event will be fired on a DC (if it does) and our script will have to run there unlike this one.
Hey DexterPosh!
DeleteThanks for your comment! Appreciated!
BTW, Good job on your work during the last Scripting Games ;-)
Good point,
Unless things change recently in Windows Server, I believe you would have to activate the Auditing on the Active Directory, the problem with this is... It will be activated for all the groups and generate a lot of events.
Once this is activated I guess you could use it instead of the Schedule Tasks.
If an event subscription is only possible for this group it would be really awesome! Without activating the whole auditing...
On a change of group membership event logs are created you can find if auditing is enable but the major problem is to consolidate all created logs according to their type so here comes the necessity of the commercial product quest do have AD Auditor but apart from that Lepide AD Auditor and Manage Engine performing well in the market
DeleteHi Francois-Xavier Cat,
ReplyDeleteGreat Script, I'm receiving an error:
Unable to find type [mailaddress]: make sure that the assembly containing this type is loaded.
At C:\Scripts\ADGroupMonitoring\TOOL-MONITOR-AD_Group.ps1:93 char:22
+ [mailaddress] <<<< $Emailfrom,
+ CategoryInfo : InvalidOperation: (mailaddress:String) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
Am I doing something wrong?
I'm using following syntax:
PowerShell.exe -Command "C:\Scripts\TOOL-MONITOR-AD_Group.ps1 -verbose -Group "Domain Admins", -EmailServer "mail.mycompany.com" -EmailTo "me@mycompany.com" -EmailFrom "powershell@mycompany.com""
Thanks!
Sahilexe
Hey Sahilexe,
DeleteTwo things:
-You have a comma after the "Domain Admin"
-You must add an escape charactere like \ to ignore the quotes inside your line
The correct line would give this:
PowerShell.exe -Command "C:\Scripts\TOOL-MONITOR-AD_Group.ps1 -verbose -Group \"Domain Admins\" -EmailServer \"mail.mycompany.com\" -EmailTo \"me@mycompany.com\" -EmailFrom \"powershell@mycompany.com\""
I guess this is the command you put inside your Task Scheduler.
What is your OS ?
Delete[mailaddress] seems to only work from Windows7
http://msdn.microsoft.com/en-us/library/system.net.mail.mailaddress.aspx
to make it work on your computer, you can remove this validation by changing some lines:
FIND:
[Parameter(Mandatory=$true,HelpMessage="You must specify the Sender Email Address")]
[mailaddress]$Emailfrom,
[Parameter(Mandatory=$true,HelpMessage="You must specify the Destination Email Address")]
[mailaddress[]]$Emailto,
REPLACE BY
[Parameter(Mandatory=$true,HelpMessage="You must specify the Sender Email Address")]
[STRING]$Emailfrom,
[Parameter(Mandatory=$true,HelpMessage="You must specify the Destination Email Address")]
[STRING[]]$Emailto,
####
FIND:
$MailMessage.from = $EmailFrom.Address
FOREACH ($To in $Emailto){
$MailMessage.To.add($($To.Address))
}
REPLACE BY:
$MailMessage.from = $EmailFrom
FOREACH ($To in $Emailto){
$MailMessage.To.add($($To))
}
Hi Francois-Xavier Cat,
DeleteThe script now works and change history and output folder were created, also the csv files get generated with correct info. but the only issue is that I don't get any email. I'm sure that I'm using correct correct syntax around the "/", correct email address and mail server. I also modified other lines as per your recommendation. The OS on which I'm running this script is Windows Server 2008 R2. Can you try your script on that OS and let me know if still anything needs to be changed to make the email part working? Appreciate your help.
PowerShell.exe -Command "C:\Scripts\ADGroupMonitoring\TOOL-MONITOR-AD_Group.ps1 -verbose -Group \"Domain Admins\" -EmailServer /"mailserver.mycompany.com/" -EmailTo /"me@mycompany.com/" -Emailfrom /"Powershell@mycompany.com/""
C:\Scripts\ADGroupMonitoring>script.bat
VERBOSE: Creating the Output Folder : C:\Scripts\ADGroupMonitoring\Output
VERBOSE: Creating the ChangeHistory Folder :
C:\Scripts\ADGroupMonitoring\ChangeHistory
VERBOSE: Quest Active Directory - Loading
VERBOSE: Quest Active Directory - Loaded
VERBOSE: GROUP: Domain Admins
VERBOSE: Domain Admins - The following file did not exist: mycompany_Domain
Admins-membership.csv
VERBOSE: Domain Admins - Exporting the current membership information into the
file: mycompany_Domain Admins-membership.csv
VERBOSE: Domain Admins - Comparing Current and Before
VERBOSE: Domain Admins - Compare Block Done !
VERBOSE: Domain Admins - No Change
VERBOSE: Script Completed
this is what I get now...
DeleteVERBOSE: groupname - Preparing the notification email...
WARNING: PROCESS BLOCK - Something went wrong
Hi,
DeleteFor your first comment, It's normal you don't get an email, once you do a change to the group and run the script again, you will get notified.
For your error on "VERBOSE: groupname - Preparing the notification email..." Just want to make sure this is not related to the SLASH you used instead of BACKSLASH
REPLACE:
PowerShell.exe -Command "C:\Scripts\ADGroupMonitoring\TOOL-MONITOR-AD_Group.ps1 -verbose -Group \"Domain Admins\" -EmailServer /"mailserver.mycompany.com/" -EmailTo /"me@mycompany.com/" -Emailfrom /"Powershell@mycompany.com/""
BY
PowerShell.exe -Command "C:\Scripts\ADGroupMonitoring\TOOL-MONITOR-AD_Group.ps1 -verbose -Group \"Domain Admins\" -EmailServer \"mailserver.mycompany.com\" -EmailTo \"me@mycompany.com\" -Emailfrom \"Powershell@mycompany.com\""
Will try to test on W2008R2 at some point during the day
Hi again,
DeleteI tried on a Windows Server 2008R2, and like you did I used a script.bat (you could put this line straight inside the Task scheduler btw)
CONTENT OF MY SCRIPT.BAT
PowerShell.exe -Command "D:\test\TOOL-MONITOR-AD_Group.ps1 -verbose -Group \"FXGROUP\" -EmailServer \"mail.fx.lab\" -EmailTo \"fxcat@fx.lab\" -Emailfrom \"Powershell@fx.lab\""
And it did work! Just make sure you use \ and not /
The first time i ran the script, it does create a CSV
After a change on the group, I do receive an Email.
Let me know if I can do anything else.
NOTE:
After a few check, the [mailaddress] you got is because you need the version 3.0 of PowerShell.
But you can work around with the lines modification I said in a previous reply.
After correcting "/" to "\" and installing PowerShell3 and DotNetFramework4.5 on my WinSvr2008R2, your script worked out of box for me. You-da-man!! :)
ReplyDeleteHappy to hear that :-)
DeleteIs it possible to input the list of Active Directory groups from a text file or provide AD location in which it checks all the groups inside. I have around 30 AD groups right now that I want to monitor using this script, but if I create more groups inside an OU, the script would pick them automatically. That would be a nice monitoring system for AD.
ReplyDeleteHi!
DeleteGreat ideas! I can definitely add this to the next version.
With the current version, you can do the following (Quest Active Directory is loaded need to be loaded first.)
# USING A SEARCH ROOT (AD LOCATION)
.\TOOL-MONITOR-AD_Group.ps1 -Group (get-qadgroup -searchroot 'OU=Test,DC=FX,DC=lab').NTAccountName -Emailfrom PowerShell@fx.lab -Emailto fxcat@fx.lab -EmailServer mail.fx.lab -Verbose
You specify the Distinguished Name of the OU with the parameter -SEARCHROOT
Additionally you can specify if the cmdlet should scan recursively with the parameter -SEARCHSCOPE
It would looks like that:
.\TOOL-MONITOR-AD_Group.ps1 -Group (get-qadgroup -searchroot 'OU=Test,DC=FX,DC=lab' -SearchScope Subtree).NTAccountName -Emailfrom PowerShell@fx.lab -Emailto fxcat@fx.lab -EmailServer mail.fx.lab -Verbose
SEARCHSCOPE parameter
'Base' = Limits the search to the base (SearchRoot) object. The result contains a maximum of one object.
'OneLevel' = Searches the immediate child objects of the base (SearchRoot) object, excluding the base object.
'Subtree' = Searches the whole sub-tree, including the base (SearchRoot) object and all its child objects.
More information on Get-QADGroup here: http://wiki.powergui.org/index.php/Get-QADGroup
# USING A TEXT FILE
.\TOOL-MONITOR-AD_Group.ps1 -Group (Get-Content c:\myfile.txt) -Emailfrom PowerShell@fx.lab -Emailto fxcat@fx.lab -EmailServer mail.fx.lab -Verbose
Hope this help
Script runs fine if I do it manually from powershell, but when I try to create the scheduled task I get the error:
ReplyDeleteA positional parameter cannot be found that accepts argument 'System.Object[]'.
Ideas?
Hi,
DeleteWhich command line do you use in your scheduled task ?
Here is the command I am running.
Delete"C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe" -command C:\AD-Monitor\TOOL-Monitor-AD_Group.ps1 -Group "Domain Admins","Enterprise Admins","VMware Admins","Web Filter Admin","SophosAdministrator" -EmailFrom "DomainChange@company.com" -Emailto "italerts@company.com" -EmailServer "smtp.company.com"
Try the following:
Delete"C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe" -command "C:\AD-Monitor\TOOL-Monitor-AD_Group.ps1 -Group \"Domain Admins\",\"Enterprise Admins\",\"VMware Admins\",\"Web Filter Admin\",\"SophosAdministrator\" -EmailFrom \"DomainChange@company.com\" -Emailto \"italerts@company.com\" -EmailServer \"smtp.company.com\""
Let me know.
That did the trick. I appreciate it. Another question. I have an older second domain that I would like to use this in as well, but it's Server 2008 Standard 32bit. Is that going to be an issue?
DeleteGreat! happy to hear it is working for you
Delete2008 R1 32 bits, I believe PowerShell 3.0 can be install there
http://blogs.technet.com/b/heyscriptingguy/archive/2012/09/06/powershell-3-0-is-now-available-for-download.aspx
If you run the script from a DC in another domain, make sure you have a trust set properly, then specify the group with the domain name to the script, example:
DOMAINA\GroupA
DOMAINA\GroupB
DOMAINB\GroupC
DOMAINB\GroupD
Hope this help!
Works like a champ. I appreciate it.
ReplyDeleteHello Francois-Xavier,
ReplyDeletecould it be that there is an error in line 323 in your Script ?
At the end you filter for $_.name but I think you should filter for $_.samaccountname.
I think this is causing the appearance in the Report of "No User or Group" being removed from the Group........
Except this behavior is intentional.........
Great Script !!
Hi
DeleteThanks for your comment.
Yes this behavior is intentional.
I'm open to suggestion, Would you prefer this to stay in the report ?
Thanks
Hi,
ReplyDeleteThis is great script but I am having problems running it. I am trying to monitor a specific OU on our domain to make sure no new clients are added or removed from it. Can this script do that?
When I try to run the following command I get an error.
.\Tool-Monitor-AD_Group_20131127.ps1 -Verbose -Group "Administrative Groups" -EmailServer "**.**.**.**" -EmailTo "user@domain.com" -EmailFrom "OUCheckTest@domain.com"
Error:
VERBOSE: GROUP: Administrative Groups
VERBOSE: Administrative Groups - Group can't be found
VERBOSE: Script Completed
Apologies if this is a stupid question, I'm new to powershell.
Thank you,
Fionnan
Hi Fionnan,
DeleteYes you can monitor an OU using the last version of the script.
Please check my last post update on this script: http://www.lazywinadmin.com/2013/11/update-powershell-monitor-and-report.html
You would run it this way
.\TOOL-MONITOR-AD_Group.ps1 -SearchRoot 'FX.LAB/TEST/Groups' -Emailfrom Reporting@fx.lab -Emailto "Catfx@fx.lab" -EmailServer 192.168.1.10 -Verbose
Looks well designed, but I don't see why it's necessary to have some thrid-party snap-in. This could be done natively.
ReplyDeleteAnyway, it looks like you put a lot of effort into it, and you have a lot people that like it; so what do I know.
Hi, thanks for your message.
DeleteI totally agree, and this point is already in my list, but did not put time on this yet.
Feel free to contribute to the script on github here : https://github.com/lazywinadmin/PowerShell/tree/master/AD-GROUP-Monitor_MemberShip