Two
	VBScript programs, and one PowerShell script, to document all members of a group 
	are linked on this page. The members can be users, 
	contacts, 
	computers, or other groups. 
	The LDAP provider is used to bind to the group. 
	Nested group members are revealed.
	
	The first VBScript program 
	also includes members that have the group, or any nested group, designated as their 
	"Primary Group".
	The program is designed to be run at a command prompt with the cscript host. The output can be 
	redirected to a text file. The Distinguished Name of the group is passed to the program as a 
	parameter. For example:
	
cscript //nologo EnumGroup.vbs "cn=Sales,ou=West,dc=MyDomain,dc=com" > Sales.txt
If the Distinguished Name passed to the program has a character that must be escaped, such as a comma, be sure to escape the character with the backslash escape character, "\". The characters that must be escaped are:
, \ / # + < > ; " =
	This program should work on any 32 or 64-bit Windows client that can log onto the domain. Windows NT 
	and Windows 98/95 clients should have DSClient installed. If DSClient is not installed, they 
	need WSH and ADSI installed. The program has been revised to document the 
	Distinguished Names of the members, instead of the sAMAccountName (pre-Windows 2000 name). This was done because members can be contacts, and Active Directory contact objects do not have a sAMAccountName value. If you are 
	sure no members will be contact objects, you can substitute sAMAccountName 
	for distinguishedName in the script.
	
	EnumGroup.txt   <<-- Click here to view or download the program
	
	A PowerShell script that performs the same function is linked below. This 
	should work in PowerShell V1 or V2.
	
	
	PSEnumGroup.txt   <<-- Click here to view or download the program
	
	The programs linked above must bind to all member objects in the group in 
	order to check if the member is a group. If the member is a group, the 
	method that enumerates direct members of the group is called recursively. If 
	the method was called recursively for all members, regardless of class, 
	errors would be raised when any members are not groups.
	
	The second program does not bind to any objects in Active Directory. This 
	should make it faster in many cases. 
	Instead, ADO is used to query Active Directory for all group objects and 
	their member attribute. The member attribute is a collection of the 
	Distinguished Names (DN's) of all direct members of the group. The second 
	program can only output the DN's of all members. Any other attributes would 
	require binding to all member objects, which would slow down the program. 
	The recordset that is retrieved has one row for each group in Active 
	Directory, with the DN of the group and the member collection. The program 
	disconnects the recordset so we can filter the recordset on group DN. The 
	program first filters on the DN of the group specified and a subroutine 
	enumerates all DN's in the member collection (the DN of all direct members 
	of the group). For each member, the subroutine is called recursively, 
	passing the DN of the member. We do not know if the member is a group, but 
	it doesn't matter. When the subroutine filters on a DN that is not a group, 
	the recordset is empty (since the recordset only has groups) and the subroutine exits immediately, so there is no 
	error.
	
	While the recordset returned by this method can be very large, all of the 
	manipulations happen in memory, which is very fast. The speed of this 
	program compared to the one above will depend on the number of groups in 
	Active Directory and the number of members in the group. However, in most 
	cases, it seems to be faster, especially if the group has more than a few 
	members. This program does not reveal any 
	"Primary Group" memberships.
	
	EnumGroup3.txt   <<-- Click here to view or download the program
	
	If
	the group (or any nested groups) has more than 1500 members, then this 
	program must be revised to use ADO range limits. The page "Document Large 
	Group" demonstrates how to do this.