34

Active Directory: VBscript to enumerate the members of nested groups V2

A couple of weeks ago I posted the enumeratenestedgroup script.
Last friday (while working at another script) I thought: this can be done better/more efficient.
What I have done is a rewrite of the script, it now contains 50% less code.
This is mainly because the recursion is implemented better.
When you are not familiar with recursion: here’s a extensive wikipedia article.
You can easily modify the script with extra user attributes, counters, etc.
Here you can find some mutations of the enumerate nested group script:

What the script does:

  • fill a variable with the group distinguished name
  • call the function EnumNestedgroup
  • the function checks whether the member is a group or a user
  • when the member is a user the displayname and smtp address are echoed on the screen
  • when the member is a group the group distinguished name is echoed and the function is called again
  • this loop continues untill the last member is enumerated

Follow the next steps to run the script (no admin rights needed):

  • find the distinguished name of the nested group (adsiedit.msc)
  • open your favorite text editor
  • copy and paste the script into the editor
  • change the distinguished name
  • save the script (for example c:\tempenumeratenestedgroup.vbs)
  • open a command prompt
  • go to “c:\temp”
  • give “cscript enumeratenestedgroup.vbs” (without quotes) and enter

The script:

' Name : enumeratenestedgroup.vbs
' Description : script to enumerate the members of a nested group
' Author : dirk adamsky - deludi bv
' Version : 2.2 replaced the subroutine statement with a function statement
' Date : 07-06-2011

strTargetGroupDN = "LDAP://CN=testgroup,OU=groups,DC=test,DC=org"
EnumNestedgroup strTargetGroupDN
Function EnumNestedgroup(strGroupDN)
	Set objGroup = GetObject(strGroupDN)
	For Each objMember in objGroup.Members
		If (LCase(objMember.Class) = "group") Then
			wscript.echo objMember.AdsPath
			EnumNestedgroup objMember.AdsPath
		Else
			Wscript.Echo objMember.DisplayName & " ; " & objMember.Mail
		End If
	Next
	Set objGroup = Nothing
End Function

When you have a modified version or problems/questions that you want to share please post it at the comments below.

Happy scripting.

Dirk Adamsky


Related Posts:
  • Active Directory: VBscript to count users with multiple entries in a nested distribution group
  • Active Directory: VBscript to enumerate the message restrictions (send to rights) of a distributionlist
  • Active Directory: VBscript to enumerate the message restrictions (send to rights) of a user or distributiongroup v2

  • 34 Responses so far.

    1. [...] script is something I wanted to do for a long time This is a mutation of the enumeratenestedgroupV2 script. In large organizations the main distributiongroups tend to be complex also. Often the [...]

    2. erdem says:

      how to write results to text file

    3. dirk adamsky says:

      Hi Erdem,

      You can do that like this:

      1. open a command prompt
      2. go to c:\temp
      3. give cscript enumeratenestedgroup.vbs > groupname.txt

      Mostly I add some date info to the name of the file:

      cscript enumeratenestedgroup.vbs > groupname12-03-2010.txt

      Happy scripting.

      Best regards,

      Dirk Adamsky

    4. Imed says:

      Thanks a lot for the script
      Very useful and neat !

      Regards

    5. dirk adamsky says:

      Hi Imed,

      Thank you for your reaction.

      Best regards,

      dirk adamsky

    6. [...] code came from my lastlogon script, the enumeration of the group members code was taken from my enumeratenestedgroup script. The users with a lastlogon of 1-1-1601 did never log [...]

    7. Imed says:

      Hi again,
      Maybe there is a bug I don’t know, i tried it on another group and it seems looping on 3 users till i got “Mermory Full” !
      Maybe there is too many nested groups..or too many users !

    8. dirk adamsky says:

      Hi Imed,

      I have used this script a lot.
      I have tested it for nested groups with 1000 or more members, so i guess size should not be a problem. My pc is has 2,5 GB ram, can you tell me the ram size of your pc? If possible you can look at the taskmanager and see what happens if you run the script. I have found one occasion in which the script did not end: turned out that the group was member of itself (2 levels deeper) so the script could not come to an end.

      Best regards,

      Dirk Adamsky

    9. Imed says:

      Hi!
      Yes exactly, I had a group member of itself !

      It works perfectly ;)

      Thanks mate!

    10. [...] Comments Imed on Active Directory: VBscript to enumerate the members of nested groups V2dirk adamsky on Active Directory: VBscript to enumerate the members of nested groups V2Imed on [...]

    11. Frank van Rijt says:

      ->Please be aware that since Windows 2003 SP2 you can directly query nested groups. So no complex script is required. See article: http://support.microsoft.com/kb/914828

      Cheers,

      Frank.

    12. Marc says:

      Hi Dirk,

      Thanks for your blog post on this – identifying nested groups is indeed important for audits and group management, so I’m certain your post will be helpful to many IT admins out there.

      By the way, do you happen to offer any free AD Reporting Tools that can do so as well? If so, I would be interested in learning more, as I run a blog on Free Active Directory Reporting Tools, and I would be happy to consider reviewing any tools you could suggest.

      In any event, even if there are no tools thusfar, I’m sure your code and tips above will certainly be helpful to folks – nice work man!

      Thanks,
      - Marc

    13. Arun says:

      Very usefull script and it parses the DL one by one and displays the details with email ID.

      In my case as per the policy we have “+” infront of all DL and initially the DN did not work and returned an error while executing the script, i inlucded a “” which resolved the issue.

      Thanks.

    14. Ram says:

      Hi While am running the script iam getting the error ” VBSCRITPT COMPILATION ERROR : Expected State ment

    15. dirk adamsky says:

      Hi Ram,

      what i forgot to say:

      when you put your mouse pointer on the white script area 4 icons are shown in the upper right corner of the script. The second icon gives you the option to copy the script content to your clipboard. From there you can easily copy and paste it in your text editor.

      Best regards,

      dirk adamsky

    16. Ram says:

      thanks dirik,

      i did the same nad work for me….but. My request is not completed here again let me explain. I have one Distrubution Groups Call (All Emp) and inside there are are lot of DDL’s(Dynamic DL) …inside the DDL’s so many members.

      i would like to take list of members who are all in the DDL’s

      When i ran your above script. it gave the DDL names inside the Distrubution List. am expecting the result where the list of members in the DDL’s

      Hope you understand. Is it possible to get the list of members in the DDL who are the members of the Main Distribution List.

      Please help Me….

    17. dirk adamsky says:

      Hi Ram,

      I made the script for a win2003-exchange2003 environment.
      We do not use ddl’s because of the domain status (still in compatibility modus).
      I will see what I can do for you.
      Please check my site on a regular basis.
      Thank you.

      Best regards,

      dirk adamsky

    18. Ram says:

      Thanks Dirk, i Will Do that

    19. Ron says:

      I have an Active Directory user group with two nested groups inside. As I tried to run the script in VBA (with some minor modifications so Excel would run it), the first group enumerates fine, but it never seems to pick up the second group. It just exists out. Have you noticed anything anything in particular with Excel that would cause this issue?

      Thanks….

    20. dirk adamsky says:

      Hi Ron,

      Sorry for the late reply.
      I have to see your code to comment on it.
      Can you please post the code below?

      Best regards,

      Dirk Adamsky

    21. xxyy says:

      Nice script. For all those who wanted to trace through or just see the nested levels for each group and its members, modify the script to:

      	num = -1 //  set starting nested level
      
      	EnumNestedgroup (connectStr, num)  // call function
      
      	Function EnumNestedgroup(strGroupDN, num)
      
      	    Set objGroup = GetObject(strGroupDN)
      
      	    For Each objMember in objGroup.Members
      
      	        If (LCase(objMember.Class) = "group") Then
      
      		    num = num + 1
      		    wscript.echo " "
      	            wscript.echo num & " " & objMember.AdsPath
      
              	    EnumNestedgroup objMember.AdsPath, num
      
      	        Else
      
      		    num = num + 1
      	            wscript.echo num & " " & objMember.Mail
      
      	        End If
      
      		num = num - 1
      
      	    Next
      
      	    Set objGroup = Nothing
      
      	End function
      
    22. xxyy says:

      Nice script. For all those who wanted to trace through or just see the nested levels for each group and its members, modify the script to:

      	num = -1
      	EnumNestedgroup connectStr, num
      
      	Function EnumNestedgroup(strGroupDN, num)
      
      	    Set objGroup = GetObject(strGroupDN)
      
      	    For Each objMember in objGroup.Members
      
      	        If (LCase(objMember.Class) = "group") Then
      
      		    num = num + 1
      		    textFile.writeLine " "
      	            textFile.writeLine num & " " & objMember.AdsPath
      
              	    EnumNestedgroup objMember.AdsPath, num
      
      	        Else
      
      		    num = num + 1
      	            textFile.writeLine num & " " & objMember.Mail
      
      	        End If
      
      		num = num - 1
      
      	    Next
      
      	    Set objGroup = Nothing
      
      	End function
      
    23. dirk adamsky says:

      Hi xxyy,

      Sorry for my late reply.
      Thanks for your addition.

      Best regards,

      Dirk Adamsky

    24. Malik says:

      Hi,

      Is there an easy way to filter on only active users? I think this would be a good addition to the script.

      I’ve done a bit of programming in other languages and this line usually allows me to filter for only active users:

      (!(userAccountControl:1.2.840.113556.1.4.803:=2) )

      Cryptic but it works, I’m wondering how I can implement this piece or some other way of finding only active users…

    25. dirk adamsky says:

      Hi Malik,

      Yes there is an easy way.
      Here’s the modified version:

      strTargetGroupDN = "LDAP://CN=testgroup,OU=groups,DC=test,DC=org"
      EnumNestedgroup strTargetGroupDN
      Function EnumNestedgroup(strGroupDN)
      	Set objGroup = GetObject(strGroupDN)
      	For Each objMember in objGroup.Members
      		If (LCase(objMember.Class) = "group") Then
      			wscript.echo objMember.AdsPath
      			EnumNestedgroup objMember.AdsPath
      		ElseIf objMember.AccountDisabled = FALSE Then
      			Wscript.Echo objMember.DisplayName & " ; " & objMember.Mail
      		End If
      	Next
      	Set objGroup = Nothing
      End Function
      

      Best regards,

      dirk adamsky

    26. Malik says:

      Thanks for the reply, I’m actually writing the output to a text file using “cscript adlist.vbs > mytextfile.txt

      I get an error with the code though that says “Active Directory: The directory property cannot be found in the cache”

    27. dirk adamsky says:

      Hi Malik,

      I think there’s one or more users in your testgroup that do not have a value in the ‘mail’ attribute. You can test this by running the script without the mail attribute:

      strTargetGroupDN = "LDAP://CN=testgroup,OU=groups,DC=test,DC=org"
      EnumNestedgroup strTargetGroupDN
      Function EnumNestedgroup(strGroupDN)
      	Set objGroup = GetObject(strGroupDN)
      	For Each objMember in objGroup.Members
      		If (LCase(objMember.Class) = "group") Then
      			wscript.echo objMember.AdsPath
      			EnumNestedgroup objMember.AdsPath
      		ElseIf objMember.AccountDisabled = FALSE Then
      			Wscript.Echo objMember.DisplayName
      		End If
      	Next
      	Set objGroup = Nothing
      End Function
      

      Best regards,

      dirk adamsky

    28. Malik says:

      Your right, some users are missing the mail attribute, but I’d still like to run the script and if the mail attribute is missing, then it just shouldn’t show I would think.

      If you look at this link and the 2nd post specifically it seems this is an issue:

      http://social.technet.microsoft.com/Forums/en/ITCG/thread/2c290223-a51e-4900-ab25-19df682ae504

      I don’t know if it’s true or not, but that thread seems to indicate that there isn’t an “AccountDisabled” attribute…

    29. dirk adamsky says:

      Hi Malik,

      Indeed there is no “AccountDisabled” attribute.
      Richard Mueller says it is a “property method”.
      I think that your error is related to the lack of a mail address for certain users.
      Please try my last script first.

      Best regards,

      dirk adamsky

    30. Ananth kumar says:

      Can someone help to change code to get input from a file and run the script for each DL listed inside the input file. Thanks in advance.

    31. [...] The script for today is made for Ananth Kumar. He asked me to make an extension to the “enumerate nested groups script” so that multiple nested groups can be enumerated based on an input file. I did choose Excel for the [...]

    Leave a Reply