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.
