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.