Don’t you hate when you have large distribution groups in your environment with enabled and disabled accounts as members and when you send email messages to the account NDRs are sent throughout the environment. As may or may not know, there are options in Exchange on how to handle NDRs for distribution groups. My issue is with the options provided by Exchange, for example enabling certain features against a DG could remove valid NDRs or create a lot of false positives. To combat this problem in environments we put together a script that will only look in DG, not security groups, and remove disabled user accounts. This script will remove all groups from disabled users within a particular OU.  You have to specify the OU that you want to search for the disabled mailboxes. This will also write out the removed groups of each user to a log.

The script can be found on our Tools page or directly at this link:

Option Explicit
On Error Goto 0

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set wshNetwork = WScript.CreateObject("WScript.Network")
    wscript.echo vbcrlf
    wscript.echo "COMPANY - REMOVE GROUP MEMBERSHIP FOR DISABLED USERS "
    wscript.echo "--------------------------------------------------"
    wscript.echo "WARNING! This will remove group membership for disabled users!"
    wscript.echo vbcrlf

' CONFIRMATION
Dim strAnswer, myQuestion, strdirectory, strfile, strDate, strBreak, myanw, wshNetwork
Dim objFSO, objFolder, objShell, objTextFile, objFile, intanswer, open, strthere
Dim conn, com, conn1
strDate = Now
strBreak = "***************************************************"
Const ForAppending = 8

WScript.StdOut.Write "Do you want to continue? (Y/N)"
strAnswer = wscript.stdin.readline
    if not StrComp(strAnswer,"Y",1) = 0 then
        wscript.echo "Process aborted."
        wscript.quit

    else
        wscript.echo "There are only 2 modes: TEST & REMOVE.  Would you like to run in Test Mode? (Y/N)"
                myQuestion = wscript.stdin.readline
                   if not StrComp(myQuestion,"N",1) = 0 then
                                Call TestLog
                    Else
                                wscript.echo "WARNING! YOU HAVE SELECTED TO RUN THIS IN REMOVE MODE"
                                strthere = MsgBox("WARNING! YOU HAVE SELECTED TO RUN THIS IN REMOVE MODE.  DO YOU WANT TO CONTINUE?", vbYesNo, "Confirmation")
                                If strthere = vbYes Then
                                                                Call Removeusers
                                Else
                                wscript.echo "Process aborted."
                        wscript.quit
                                End If
                    End If
    End If
wscript.echo " "
wscript.echo "**************************"
Wscript.echo "    ACTION IS COMPLETE!   "
wscript.echo "**************************"

' WScript.StdOut.Write "Do you want to display the file? (Y/N)"
' myanw = wscript.stdin.readline
'    if not StrComp(myanw,"Y",1) = 0 then
'        wscript.echo "OK!"
'               wscript.echo vbcrlf
'    else
'        wscript.echo vbcrlf
'               Set objShell = CreateObject("WScript.Shell")
'               objShell.run ("Explorer" & " " & strDirectory & "" )
'   End If
wscript.echo vbcrlf
wscript.echo "ATTENTION: The files are on the root of C:"
wscript.echo "           Be sure to remove these files as needed."

''''''''''''''''''''''''''''''''''
' FUNCTIONS
''''''''''''''''''''''''''''''''''
Function TestLog
wscript.echo vbcrlf
wscript.echo "*******************************************"
wscript.echo "********** RUNNING IN TEST MODE ***********"
wscript.echo "*******************************************"

' CREATE FILE
strDirectory = "C:"
strFile = "TestExport-" & getDate & ".log"
Set objTextFile = objFSO.OpenTextFile _
(strFile, ForAppending, True)
                objTextFile.WriteLine()
                objTextFile.WriteLine(strbreak)
                objTextFile.WriteLine(strDate)
                objTextfile.WriteLine(" Domain: " & wshNetwork.UserDomain)
                objTExtFIle.WriteLine(" Computer Name: " & wshNetwork.ComputerName)
                objTextFile.WriteLine(" User name that ran script: " & wshNetwork.UserName)
' END CREATION FILE

wscript.echo "Logging to:" & strfile & "..."
intanswer = true
Call QueryAD
End Function

Function Removeusers
wscript.echo vbcrlf
wscript.echo "*******************************************"
wscript.echo "********* RUNNING IN REMOVE MODE **********"
wscript.echo "*******************************************"

' CREATE  FILE
strDirectory = "C:"
strFile = "RemoveGrp-" & getDate & ".log"
Set objTextFile = objFSO.OpenTextFile _

(strFile, ForAppending, True)
                objTextFile.WriteLine()
                objTextFile.WriteLine(strbreak)
                objTextFile.WriteLine(strDate)
                objTextfile.WriteLine(" Domain: " & wshNetwork.UserDomain)
                objTExtFIle.WriteLine(" Computer Name: " & wshNetwork.ComputerName)
                objTextFile.WriteLine(" User name that ran script: " & wshNetwork.UserName)
' END CREATION OF FILE

wscript.echo "Logging to:" & strfile & "..."
intanswer = false
Call QueryAD
End Function

Function QueryAD
' This function will Query AD for Disabled Users within a specific OU that you define.
' You MUST modify the OU name!

Dim conn, com, conn1, iAdRootDSE, strNamingContext, strDefaultNamingContext, objParentRS
Dim objChildRS, strSQL, strConnString, strNameingContext, QueryFilter, strQuery, rs, strLocation
Dim Rs1, objuser, objgroup, objuserDisNam, objGroupDisName
wscript.echo " "
wscript.echo "Attaching to Active Directory....."
set conn = createobject("ADODB.Connection")
set com = createobject("ADODB.Command")
set conn1 = createobject("ADODB.Connection")
strConnString = "Data Provider=NONE; Provider=MSDataShape"
conn1.Open strConnString

Set iAdRootDSE = GetObject("LDAP://RootDSE")
strNameingContext = iAdRootDSE.Get("configurationNamingContext")
strDefaultNamingContext = iAdRootDSE.Get("defaultNamingContext")
Set objParentRS = createobject("adodb.recordset")
Set objChildRS = createobject("adodb.recordset")

strSQL = "SHAPE APPEND" & _
           "  NEW adVarChar(255) AS GRPDisplayName, " & _
           "  NEW adVarChar(255) AS GRPDN, " & _
           " ((SHAPE APPEND  " & _
           "      NEW adVarChar(255) AS USDisplayName, " & _
           "      NEW adVarChar(255) AS USDN, " & _
           "      NEW adVarChar(255) AS USGRPDisplayName, " & _
           "      NEW adVarChar(255) AS USGRPDN " & _
                   ")" & _
           "      RELATE GRPDN TO USGRPDN) AS rsGRPUS "

objParentRS.LockType = 3
objParentRS.Open strSQL, conn1
Conn.Provider = "ADsDSOObject"
Conn.Open "ADs Provider"

QueryFilter =  "(&(distinguishedName=*)(|(objectCategory=group)))"
strQuery = "<LDAP://"  & strDefaultNamingContext & ">;" & QueryFilter & ";distinguishedName,displayname;subtree"
Com.ActiveConnection = conn
Com.CommandText = strQuery
Set rs = Com.Execute
while not rs.eof
                objParentRS.addnew
                objParentRS("GRPDisplayName") = rs.fields("displayname")
                objParentRS("GRPDN") = rs.fields("distinguishedName")
                objParentRS.update
                rs.movenext
wend

QueryFilter = "(&(&(distinguishedName=*)(objectCategory=person)(userAccountControl:1.2.840.113556.1.4.803:=2)))"

strLocation = "OU=DST,DC=cbfive,DC=com"
strQuery = "<LDAP://"  & strLocation & ">;" & QueryFilter & ";distinguishedName,displayname,legacyExchangeDN,homemdb;subtree"
wscript.echo "***********************************************"
wscript.echo "       Looking for Disabled Users in    "
wscript.echo  strLocation
wscript.echo "***********************************************"

Com.ActiveConnection = conn
Com.CommandText = strQuery
Set Rs1 = Com.Execute
Set objChildRS = objParentRS("rsGRPUS").Value
while Not rs1.eof
                if instr(rs1.fields("displayname"),"SystemMailbox{") = 0 then
                                set objuser = getobject("LDAP://" & replace(rs1.fields("distinguishedName"),"/","/"))
                                For each objgroup in objuser.groups
                                                objChildRS.addnew
                                                objChildRS("USDisplayName") = rs1.fields("displayname")
                                                objChildRS("USDN") = rs1.fields("distinguishedName")
                                                objChildRS("USGRPDisplayName") = objgroup.name
                                                objChildRS("USGRPDN") = objgroup.distinguishedName
                                                objChildRS.update
                                next
                end if
                rs1.movenext
                'wscript.echo

Wend
wscript.echo "   "
wscript.echo "       Writing information to file...  "
wscript.echo "   "
wscript.echo "***********************************************"

objParentRS.MoveFirst

'WScript.Echo "Start of parent file"
'WScript.Echo objParentRS.EOF
'WScript.Sleep 1000
Do While Not objParentRS.EOF
     Set objChildRS = objParentRS("rsGRPUS").Value
     'WScript.Echo "Start of child file"
                 'WScript.Echo objchildRS.EOF
                 'WScript.Sleep 1000
     If objChildRS.recordCount <> 0 Then
     objTextFile.WriteLine()
     objTextFile.WriteLine(" Group Name: " & objParentRS.fields("GRPDisplayName"))
                Do While Not objChildRS.EOF
                                                Set objgroup = getobject("LDAP://" & replace(objChildRS.fields("USGRPDN"),"/","/"))
                                                'Set objgroupDisNam = getobject("LDAP://" & replace(objChildRS.fields("USGRPDisplayName"),"/","/"))
                                                Set objuser = getobject("LDAP://" & replace(objChildRS.fields("USDN"),"/","/"))
                                                'Set objuserDisNam = getobject("LDAP://" & replace(objChildRS.fields("USDisplayName"),"/","/"))
                                                Set objFolder = objFSO.GetFolder(strDirectory)
                                                Set objFolder = objFSO.GetFolder(strDirectory)
                                                Set objFile = Nothing
                                                Set objFolder = Nothing
                                                'objTextFile.WriteLine()
                                                'objTextFile.WriteLine(" Group User was Removed from: " & objParentRS.fields("GRPDisplayName"))
                                                'objTextFile.WriteLine(" Group: " & objgroup)
                                                objTextFile.Writeline(" User Name: " & objChildRS.fields("USDisplayName"))
                                                'objTextFile.WriteLine()
                                               'objTexFile.WriteLine(" User: " & objChildRSRS.fields("USDN"))
                                                'WScript.Echo intanswer
                                                If intanswer = False Then
                                                                objGroup.Remove(objUser.AdsPath)
                                                                objgroup.setinfo
                                                End If
                                objChildRS.MoveNext
                Loop
     end if
     objParentRS.MoveNext
Loop

'WScript.Echo "End of parent file"
'WScript.Echo objParentRS.EOF
'WScript.Sleep 1000
End Function

Function getDate()
Dim myMonth, myDay, mydate
        myMonth  = month(now)
        myDay    = day(now)
        if len(myMonth) = 1 then
            myMonth = "0" & myMonth
        end if
        if len(myDate) = 1 then
            myDay = "0" & myDay
        end if
        getDate = year(now) & myMonth & myDay & hour(time) & minute(time)

BTW, if you are looking for the same functionality but with Security Groups, it wouldn’t take much to modify this script to that effect.