Cause of company policy we don’t delete users which are leaving, but we disabled them. The exchange mailbox will be removed after some months. For this incomming mails have to be forwarded to an exchange contact with an unresolvable address, so the sender receives an error message.
Cause of this, we need to remove the disabled users from all distribution list. If not, senders receive error messages each time a message was send to a distribution list with disabled users.
To automate this, i wrote a script. You can filter it by OU and run it first in a display-only mode before you remove the disabled users definitely from all distribution lists.
You can download the script RemoveDisabledUsers.vbs or copy/paste it from here:
' =========================================================================================== ' ' Script Information ' ' Title: RemoveDisabledUsers.vbs ' Author: Josh Burkard ' Date: 23.06.2011 ' Description: - displays or removes disabled users from all distribution lists ' - you can filter the output / removal by User-OU ' - to remove users from AD, you need to start the script with an ' administrator account ' ' Startup: only display disabled users in distribution lists: ' -------------------------------------------------- ' cscript RemoveDisabledUsers.vbs ' ' remove disabled users from distribution lists: ' ---------------------------------------------- ' cscript RemoveDisabledUsers.vbs remove ' ' =========================================================================================== ' If enabled users are filtered by OU's: booFilterOUs = true ' User-OU's (this array will be ignored if booFilterOUs is false): strOUs = Array ( "OU=OU1,DC=domain,DC=local", _ "OU=OU2,DC=domain,DC=local", _ "OU=OU3,DC=domain,DC=local") if wscript.arguments.length = 0 then wscript.echo "Display Mode" wscript.echo "To remove this users from distribution lists, start the script with parameter 'remove'." else if lcase(wscript.arguments(0)) = "remove" then mode = "remove" wscript.echo "Remove Mode" else wscript.echo "Display Mode" wscript.echo "To remove this users from distribution lists, start the script with parameter 'remove'." end if end if wscript.echo 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" ' Read distribution lists from AD GALQueryFilter = "(&(mailnickname=*)(|(objectCategory=group)))" strQuery = "<LDAP://" & strDefaultNamingContext & ">;" & GALQueryFilter & ";distinguishedName,displayname,legacyExchangeDN,homemdb;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 ' Read users from AD GALQueryFilter = "(&(&(mailnickname=*)(objectCategory=person)(userAccountControl:1.2.840.113556.1.4.803:=2)))" strQuery = "<LDAP://" & strDefaultNamingContext & ">;" & GALQueryFilter & ";distinguishedName,displayname,legacyExchangeDN,homemdb;subtree" 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"),"/","\/")) ' Check if user is in one of the defined OU's If booFilterOUs = true then booOU = false For Each strOU In strOUs If instr(lcase(objuser.distinguishedName), lcase(strOU)) Then booOU = true End If Next end if If (booOU = true) or (booFilterOUs = false) then 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 end if rs1.movenext wend ' Output of Groups and Users objParentRS.MoveFirst wscript.echo "GroupName,Disabled User's Name" wscript.echo Do While Not objParentRS.EOF Set objChildRS = objParentRS("rsGRPUS").Value if objChildRS.recordCount <> 0 then Do While Not objChildRS.EOF Wscript.echo objParentRS.fields("GRPDisplayName") & ", " & objChildRS.fields("USDisplayName") if mode = "remove" then ' Removing users from groups set objgroup = getobject("LDAP://" & replace(objChildRS.fields("USGRPDN"),"/","\/")) Set objUser = getobject("LDAP://" & replace(objChildRS.fields("USDN"),"/","\/")) objGroup.Remove(objUser.AdsPath) objgroup.setinfo wscript.echo "User-Removed" end if objChildRS.MoveNext loop end if objParentRS.MoveNext Loop
Hi,
I’m looking for something similar. In my case I want to search for disabled users who are owners of distribution list so we can change ownership.
Any help is appreciated.
Hello Jose
You can run the script like this:
cscript RemoveDisabledUsers.vbs > list.txt
Then you will get a text-file with all disabled users, which are in distribution lists.
After running I got an error: ” The size limit for this request has exceeded”.
Will the script actually remove the owner of the DL? Because even after we remove disabled accounts from DL’s a Disabled user can still be the owner of it.
Hello Jose
By default there is a limit in Active Directory for 10000 objects per search. You can split your search to different OU’s or increase the limit, see http://www.petri.co.il/active_directory_search_limit.htm (sorry, but i didn’t test it)
Josh.
Great script.
I’d like to use this script while my help desk staff are disabling user accounts via Active Directory Users and Computers. So, rather than searching for all users, I’d like to have this as part of the process for the currently selected user.
Similar to this; http://deenaik.blogspot.com/2009/11/add-custom-field-to-aduc-employee-id.html
I’ve tried to manipulate the script, but it seems to error out.
Any ideas/suggestions?
What kind of error do you get?
Actually no more error.
Rather than doing a full AD query for all users, I changed it to look for the currently selected user.
I’m sure it can be a lot cleaner, and/or even simpler to just search the groups the user is currently a member of, but that’s out of my depth of knowledge.
Again, great script. Will continue to check back and see what other kind of cool tricks you come up with.
Thanks a lot for this great script.
This information very helpful.Thanks