Use PowerShell to Fix Those Annoying NDR Emails

Doctor Scripto

Summary: Microsoft PFE, Norman Drews, shows how to use the Active Directory cmdlets and the Exchange cmdlets to clean up distribution groups.

Microsoft Scripting Guy, Ed Wilson, is here. Welcome our guest blogger, Norman Drews. Norman is a Microsoft PFE, and I had the privilege to meet with him when I was speaking at Geek Ready last year in San Diego. While I was out there, I also took the opportunity to encourage him to write a few guest blogs for us. Here is the first one. Now, let’s see what he has to say about himself…

Photo of Norman Drews

At Microsoft, I am a developer premier field engineer. I am part of a Microsoft group that supports our premier customers with issues in their environment both onsite and remotely. I handle application profiling, user-mode debugging, application compatibility, and currently the IT environment by way of Windows PowerShell. I live in the Houston area, and I have a beautiful wife and two kids. I speak a few languages (English, German, and Spanish) and enjoy being on the computer, watching television, and spending time with the family. The usual stuff. I started a blog after customers said that I should post my scripts online. It is a little empty right now, but I plan to add useful scripts over time.
Blog: $AutomateThisAndThat = $true with Windows PowerShell

Recently, I have been doing many Windows PowerShell workshops to help spread the “word.” I am often surprised that there are so many things that could get automated quickly and easily with Windows PowerShell, but people don’t do it. Perhaps it is just not being aware of how easy it can be.

I was teaching a Windows PowerShell class a couple months back, and we had just finished a day of fundamentals. The problem with fundamentals is that they are not applied. Some of the students started saying how they have over 50000 exchange mailboxes and 10000 distribution groups that they had to clean up. They were getting tons of non-delivery report (NDR) emails because it was not uncommon to have several mailboxes disconnected or removed on a daily basis. Their current process was to open each user account and manually remove it from active distribution groups. Sure, they could have been using dynamic distribution groups, but that was not the case here. So, I said, “Let us automate the process!”

After a few moments, we came up with a couple approaches:

  • Proactive: Enumerate all distribution groups and check if the mailbox is still valid (based on criteria)
  • Reactive: Wait for the NDR and then remove the user from the distribution groups

I created my MyTestGroup, and I added a few users including John Doe who has a ProhibitSendReceiveQuota = 0.

The following image shows MyTestGroup:

 Image of command output

Here is the mailbox information for John Doe:

Image of command output

Active Directory and Exchange cmdlets to use

Following are the Active Directory cmdlets and the Exchange cmdlets that we will use in the scripts.

Get-ADUser

Get-ADGroup

Get-ADGroupMember

Remove-ADGroupMember

Get-Mailbox

Get-MailboxStatistics

For more information about using the Active Directory cmdlets, refer to these Hey, Scripting Guy! blogs.

For more information about using the Exchange commands, see the following blogs in Hey, Scripting Guy!

Proactive approach: Enumerate all distribution groups

Here is the basic idea:

  1. Get users from all distribution groups, even the nested ones (-Recursive).
  2. Keep track of processed users so we don’t work too hard.
  3. Check if the users’ mailbox’s are disconnected, non-existent, or have a ProhibitSendReceiveQuota set to 0.
  4. Loop through their mail-enabled group memberships and remove them.

You probably would not want to run the following script every hour on-the-hour, but you could set it up as a scheduled task to run daily or weekly. For more information about running Windows PowerShell scripts via a scheduled task, see these Hey, Scripting Guy! blogs.

param

(

    $Path = “ou=myTestOU,dc=exgcore,dc=lab”

)

 

# Import AD Module

Import-Module -Name ActiveDirectory

 

# Set up array to track processed users

$UsersAlreadyChecked = @()

 

# Loop through all Groups at a specific location

foreach($Group in (Get-ADGroup -Filter * -SearchBase $Path -SearchScope onelevel))

{

    # Retrieve all group members including those in nested groups

    $GroupMembers = Get-ADGroupMember -Identity $Group.DistinguishedName -Recursive

   

    foreach($GroupMember in $GroupMembers)

    {   

        # Store the DistinguishedName

        $MemberDN = $GroupMember.DistinguishedName

   

        # Make sure we haven’t already processed this user

        if($UsersAlreadyChecked -notcontains $MemberDN)

        {

            # Grab Mailbox information

            $MailBox = Get-Mailbox -Identity $MemberDN

            $MailBoxStats = Get-MailBoxStatistics -Identity $MemberDN

           

            # Set removal conditions

            if(($MailBox -eq $null) -or (($MailBoxStats.DisconnectDate) -or ($MailBox.ProhibitSendReceiveQuota -eq 0)))

            {

                # Get group memberships for the current user

                $User = Get-ADUser -Properties memberof -Identity $MemberDN

                $UserDN = $user.DistinguishedName

 

                # Loop through those groups and remove from mail-enabled ones

foreach($ADGroupDN in $User.memberof)

{

# Assume mail enabled since there is a populated mail attribute

$Group = Get-ADGroup -Properties mail -Identity $ADGroupDN

if($Group.mail -like “*”)

{

# Remove the user from the group defined in $ADGroupDN

Remove-ADGroupMember -Identity $ADGroupDN -Members $UserDN

}

}

# Keep track of user so we don’t check him again

$UsersAlreadyChecked += $UserDN

 

               # Keep track of user so we don’t check him again

               $UsersAlreadyChecked += $UserDN

               

            }

        }

    }

}

 The following image shows the current group members. I run the previous script saved to EnumerateGroupsAndRemove.ps1, and show the members once more. We should see that John Doe is removed. (We can ignore the unrelated warning message. It is for a different user.)

Image of command output

Note   Remove-ADGroupMember will probably prompt you for confirmation, so if you really want to remove the user and suppress the query, add -Confirm:$false to the end of the statement.

Reactive approach: Wait for the NDR and act

The idea here is similar, except we are responding to an NDR and then cleaning up that user’s memberships. We do the following:

  1. Call Get-ADUser and retrieve the user’s group memberships via the MemberOf attribute.
  2. Enumerate through those groups and check if they are mail-enabled.
  3. Remove the user from the mail-enabled group.

 

param

(

    $UserDN = “cn=John Doe,ou=myTestOU,dc=exgcore,dc=lab”

)

 

# Import AD Module

Import-Module -Name ActiveDirectory

 

# Get current group memberships for the current user

$User = Get-ADUser -Properties memberof -Identity $UserDN

 

# Loop through those groups, specifically those that are mail-enabled

foreach($ADGroupDN in $User.memberof)

{

# Assume mail enabled since there is a mail attribute

$Group = Get-ADGroup -Properties mail -Identity $ADGroupDN

if($Group.mail -like “*”)

{

# Remove the user from the group defined in $ADGroupDN

Remove-ADGroupMember -Identity $ADGroupDN -Members $User.DistinguishedName

}

}

Now I am going to show the current group members. I run the previous script saved to CleanupUserDistributionGroups.ps1, and show the members once more. We should see that John Doe gets removed.

 Image of command output

Voila!

With little modification, this script can be written to accept multiple users. It currently processes a single user.

As you can see, it is not really all that difficult. We wrote the scripts during a classroom break—about 20 minutes of FAST typing and TAB completion, and it saved the customer tons of tedious future work. I did not have an Exchange Server environment set up, but the students were Exchange administrators, and they set up a test environment to confirm that it worked for them.

In the previous scripts, I used the DistinguishedName Active Directory attribute, but we can basically use anything that uniquely identifies the Active Directory object. In addition, I assumed that the Exchange snap-in and Active Directory module (download RSAT) is loaded. If not, you need to load them via Add-PSSnapin and Import-Module respectively.

Have fun, comment your code, and test it before production deployment!

~Norman

Thank you, Norman. This is an excellent real-world type of scenario.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

0 comments

Discussion is closed.

Feedback usabilla icon