I recently had a client who wanted me to find an automated method for finding and hiding/disabling distribution groups that are essentially defunct. The project was part of a larger goal to cleanup AD and Exchange and keep it as automated as possible.
Criteria for the goal:
- Any group that had not received email in 6 months is hidden.
- Any group that had not received email in 12 months is disabled.
- When a group is hidden or disabled, an email goes to the manger.
- IT is notified when the group id disabled to determine if its OK to delete.
- Run the script monthly
As with any script of this type, I wrote it in a test lab that had multiple Exchange 2010 Transport servers and over a thousand groups (due to the 1000 item limit in some scripts. In order to test this script without waiting for 12 months, I had to generate some messaging logs. See my previous article on how to do this. Once these logs were in place I could perform my testing. In order to track activity or inactivity for a group, I am using the attribute ‘CustomAttribute10’ to keep track of
Here is the script, that has been test and provided to you as-is.
The below section of code is simply an explanation of what the script is about as well as some variable definition for later use.
<# .SYNOPSIS Distribution List Cleanup Script .DESCRIPTION This script will cleanup all scripts that have not been used within a certain timeframe. .NOTES Version : 1.6 Date Created : 11/12/2013 Change Log : 1.6 - Fixed email notifications : 1.5 - Added support for multiple transport servers : 1.4 - Finalized single transport server solution : 1.3 - Converting from CSV to array variables and AD attribute : 1.2 - Email notifications tested : 1.1 - Store all data in CSV files : 1.0 - Script first set up Wish list : HTML Report to IT? Rights Required : Local admin on server Sched Task Req'd : No Exchange Version : 2010 Author : Damian Scoles Dedicated Blog : http://justaucguy.wordpress.com/ Disclaimer : You are on your own. This was not written by, support by, or endorsed by Microsoft. Code stolen from: : Multiple sources to be listed later .EXAMPLE .\DistributionListCleanup.ps1 To be run once per month as a recurring task .INPUTS None. You cannot pipe objects to this script. #> # Global variable section # Testing Dates # $onemonth = ((get-date).addmonths(-13)) # $current = ((get-date).addmonths(-12)) # Production Dates $current = get-date $onemonth = ((get-date).addmonths(-1)) # Arrays $activegroups2 = @() $activegroups = @() $inactivegroups = @() $allgroups = @() $smtp = @() # Load AD Module for PowerShell import-module activedirectory
Let’s take a look at the rest of the script, section by section.
# Get a list of the active groups $servers = get-transportserver foreach ($name in $servers) { $activegroups2 += (Get-MessageTrackingLog -Server $name.name -EventId Expand -ResultSize Unlimited -start $onemonth -end $current | Sort-Object RelatedRecipientAddress | Group-Object RelatedRecipientAddress | Sort-Object Name | select-object name) } $activegroups2 = $activegroups2 | sort-object name | group-object name foreach ($line in $activegroups2) { $activegroups += $line.name }
This part of the script stores information about groups that have had email sent to them in the past month. Information from this part of the script is stored in an array variable called $activegroups. We’ll store this information to be used later in the script.
# Get a list of all groups $allgroups2 = get-distributiongroup -resultsize unlimited | Select-Object -Property @{Label="Name";Expression={$_.PrimarySmtpAddress}} foreach ($line in $allgroups2) { $allgroups += $line.name }
The $AllGroups variable gets a list of the distribution groups in Active Directory
# Find inactive groups by comparing active groups to all groups $InactiveGroups2 = Compare-Object $activegroups $allgroups foreach ($line in $inactivegroups2) { $smtp2=$line.inputobject $address=$smtp2.local+"@"+$smtp2.domain $inactivegroups += $address }
This section compares the two sets of data that was gathered – all distribution groups ($Allgroups) with the active distribution groups ($ActiveGroups). The differences are stored in a variable called $Inactivegroups which holds information about groups that were not active this past month.
# Set custom attribute 10 for active groups to 0 foreach ($line in $ActiveGroups){ set-distributiongroup -identity $line -CustomAttribute10 0 -warningaction silentlycontinue }
This section resets the CustomAttribute10 value to 0 (the one we are using to track how many months a group has been inactive for. So 0 is active and 1-whatever means inactive.
# Set custom attribute 10 for inactive groups - increase by 1 # Hide or disable group foreach ($line in $InactiveGroups){ [string]$email = $line [int]$number = (get-distributiongroup -identity $email).CustomAttribute10 $number += 1 set-distributiongroup -identity $email -CustomAttribute10 $number if ($number -eq 6) { $notes = "$current - Hidden from address list due to inactive use." Set-Group -identity $email -notes $notes Set-DistributionGroup -identity $email -HiddenFromAddressListsEnabled $true # Email manager - group hidden mail-managerhidden $email } if ($number -eq 12) { # Email manager and IT of group removal mail-managerdisabled $email emailIT-Groupremoval $email # Disable the group $notes = "$current - No longer Mail Enabled due to inactive use." Set-Group -identity $email -notes $notes Disable-DistributionGroup -identity $email -Confirm:$false } }
The above section is a bit complex, but what it essentially does i go through each group deemed inactive and see if it has been inactive for 6 or 12 months. If it has been inactive for 6 months (customerattribute10 = 6), then the group is hidden and an email is sent to the manager of the group through a function called ‘mail-managerhidden’. If the group has been inactive 12 months (customerattribute10 = 12), then the group is disabled and an email is sent to the IT group through a function called ’emailIT-Groupremoval’. The functions are listed below and are custom coded for this script.
function mail-managerhidden ($groupsmtpaddress) { $manager = ((get-distributiongroup $groupsmtpaddress).managedby) $manager | foreach { $mgr = $_.name $smtp4 = (get-mailbox $mgr).emailaddresses $smtp4 | foreach { $smtp3 = $_.smtpaddress $smtp3 } $smtp += @($smtp3) } $DLName = (get-distributiongroup $groupsmtpaddress).displayname [string] $body = "<strong>NOTIFICATION</strong><BR><BR>As a part of regular maintanence, IT has decided to monitor the usage of Distribution # Lists.<BR><BR>This email is a notification that an Email Distribution List that you manage has been inactive for 6 months. Because of this level of inactivity, the group has been hidden from the Global Address List. Please check this list to see if it is still valid or not.<BR><BR>Please send an email to dscoles@testing.local if the list is no longer needed. Thanks for you assistance with this matter." foreach ($line in $smtp) { $messageParameters = @{ Subject = "Distribution List Manager Alert - Inactive Distribution List - $DLName" Body = $body From = "tuser01@dsl4.local" To = $line SmtpServer = "172.31.122.159" } Send-MailMessage @messageParameters –BodyAsHtml } }
In the above code section, the first this we need to do is get the manager list for each distribution group. Because of the way the managers are stored we need to parse each one to get the correct email address for the manager. After we get the manager, we format the message body, subject, who it goes to and who it is from. Then we send the message.
function mail-managerdisabled ($groupsmtpaddress) { $manager = ((get-distributiongroup $groupsmtpaddress).managedby) $manager | foreach { $mgr = $_.name $smtp2 = (get-mailbox $mgr).emailaddresses $smtp2 | foreach { $smtp3 = $_.smtpaddress } $smtp += @($smtp3) } $DLName = (get-distributiongroup $groupsmtpaddress).displayname [string] $body = "<strong>NOTIFICATION</strong><BR><BR>As a part of regular maintanence, IT has decided to monitor the usage of Distribution # Lists.<BR><BR>This email is a notification that an Email Distribution List that you manage has been inactive for over 12 months. This Distribiution group has been deleted.<BR><BR>Please send an email to dscoles@dsl4.local if you have any questions. Thanks for you assistance with this matter." foreach ($line in $smtp) { $messageParameters = @{ Subject = "Distribution List Manager Alert - Removed Distribution List - $DLName" Body = $body From = "tuser01@dsl4.local" To = $line SmtpServer = "172.31.122.159" } Send-MailMessage @messageParameters –BodyAsHtml } }
This code is almost identical to the first function, with the only difference being the content of the subject and body.
function emailIT-Groupremoval ($groupsmtpaddress) { $DLName = (get-distributiongroup $groupsmtpaddress).displayname [string] $body = "<strong>NOTIFICATION</strong><BR><BR>As a part of regular maintanence this group was disabled. The group has been inactive for 12 months per the DL Cleanup Script. Confirm that this list can be deleted and remove it from AD." $messageParameters = @{ Subject = "Distribution List - IT Alert - Removed Distribution List - $DLName" Body = $body From = "tuser01@dsl4.local" to = "dscoles@dsl4.local" SmtpServer = "172.31.122.158" } Send-MailMessage @messageParameters –BodyAsHtml }
This last function sends an email to the It Group about the group being disabled. No parsing is needed so that section was not included.
I’ve provided the entire script here for your testing as the script has only been used in a test lab with Exchange 2010 SP2.
Download the script below:
The script is in the TechNet Gallery.
Notes
Some information needs to be changed to match your environment – SmtpServer, From, To, as well as what you want the Subject and Body of the message to contain. Also, the script uses ‘CustomAttribute10’ for tracking the activity. Feel free to change it to the attribute necessary for your environment.