Table of Content > Extended Handling of AD Objects > LDAP Search Factory > How to find all members of an Active Directory group
How to find all members of an Active Directory group
In Active Directory Scripts the members of a group are searched often by binding to the regarding group object and evaluating it's API property members or LDAP attribute member - or by evaluating the 'opposite' user attribute memberOf. However, this is not exactly the same, because group memberships can be implemented not only through this attribute pair, but also in the form of 'primary groups', this is set in the user attribute primaryGroupID. So the actual group membership of a directory object consists always of two attributes! The mentioned property of the primary group is actually only needed if Mac or Posix clients log onto the domain.
By default, for new users the primary group property is set to 'domain users', so it is often not important that this group membership is missing in the basic evaluation of the member values. However, if other groups are registered as a primary group, this traditional way of membership evaluation is not accurate enough! Therefore, this article describes next to the qick-and-dirty method also how to determine a complete list of the members of a group.
To find the members of a group, we must first identify the full LDAP Distinguished Name (DN) of the regarding group object. The necessary steps for this are described in detail in the SelfADSI article 'Name Translation: How to identify the LDAP path of a user'.
For the actual search, we use the Active Directory memberOf attribute with an appropriate LDAP filter. To really find all users that you have to pay attention to the attribute primaryGroupID also. This is the relative ID (RID) of the primary group for that user - and this primary group doesn't appears in the memberOf attribute list! Fortunately, you don't have to perform a complete SID evaluation and calculation (SelfADSI article 'Microsoft Security Descriptor (SID) attributes') - you can search for the appropriate primaryGroupToken attribute of that group instead. By the way: This attribute is an operational attribute and must be requested explicitly when reading the group object.
Search Group Members - quick and dirty
First, we consider a script that evaluates the membership on the basis of a given group distinguished name (DN), the property "Primary group" is ignored - in many cases a complete list of group members can be obtained:
groupDN = "cn=GroupA,ou=Gruppen,dc=example,dc=com" 'insert your own group DN here
Set group = GetObject("LDAP://" & groupDN)
For Each memberDN In group.member
WScript.Echo memberDN
Next
Search Group Members in the own Domain
And now the careful method involving the primary group membership. This script finds all members of a group in the domain in which the current user (which the script is running) is a member. It also assumes that only the group name itself and not the distinguished name is known:
groupName = "GroupA" 'insert your own group name here
Set rootDSE = GetObject("LDAP://rootDSE") 'detect the own domain
domainDN = rootDSE.Get("defaultNamingContext")
'detect the DN and the RID of the group
ldapFilter = "(sAMAccountName=" & groupName & ")"
Set ado = CreateObject("ADODB.Connection")
ado.Provider = "ADSDSOObject"
ado.Open "ADSearch"
Set objectList = ado.Execute("<LDAP://" & domainDN & ">;" & ldapFilter & _
";distinguishedName,primaryGroupToken;subtree")
groupDN = objectList.Fields("distinguishedName")
groupRID = objectList.Fields("primaryGroupToken")
'search the members
ldapFilter = "(|(memberOf=" & groupDN & ")(primaryGroupID=" & groupRID & "))"
Set ado = CreateObject("ADODB.Connection")
ado.Provider = "ADSDSOObject"
ado.Open "ADSearch"
Set objectList = ado.Execute("<LDAP://" & domainDN & ">;" & ldapFilter & _
";distinguishedName,samAccountName,displayname,userPrincipalName;subtree")
While Not objectList.EOF
userDN = objectList.Fields("distinguishedName")
logonName = objectList.Fields("samAccountName")
On Error Resume Next
displayName = "" : displayName = objectList.Fields("displayname")
logonNameUPN = "" : logonNameUPN = objectList.Fields("userPrincipalName")
On Error Goto 0
WScript.Echo logonName & ";" & logonNameUPN & ";" & displayName & ";" & userDN
objectList.MoveNext
Wend
Search Group Members in the entire Forest
This script finds all members of a group in the entire forest in which the current user (which the script is running) is a member. The group itself has to be in the same domain as the user who runs this script. We have to do two separate searches for memberOf (performed in the entire forest) and primaryGroupID (only in the own domain). The primary group of a user must in fact always be a group of its own domain.
groupName = "GroupA" 'insert your own group name here
Set rootDSE = GetObject("LDAP://rootDSE") 'detect the own domain
domainDN = rootDSE.Get("defaultNamingContext")
Set aoi = CreateObject("ADSystemInfo") 'detect the forest search base string
gcBase = aoi.ForestDNSName
'detect the DN and the RID of the group
ldapFilter = "(sAMAccountName=" & groupName & ")"
Set ado = CreateObject("ADODB.Connection")
ado.Provider = "ADSDSOObject"
ado.Open "ADSearch"
Set objectList = ado.Execute("<LDAP://" & domainDN & ">;" & ldapFilter & _
";distinguishedName,primaryGroupToken;subtree")
groupDN = objectList.Fields("distinguishedName")
groupRID = objectList.Fields("primaryGroupToken")
'______________________________________________________ search members -> memberOf search in the entire forest
ldapFilter = "(memberOf=" & groupDN & ")"
Set objectList = ado.Execute("<GC://" & gcBase & ">;" & ldapFilter & _
";distinguishedName,samAccountName,displayname,userPrincipalName;subtree")
While Not objectList.EOF
userDN = objectList.Fields("distinguishedName")
logonName = objectList.Fields("samAccountName")
On Error Resume Next
displayName = "" : displayName = objectList.Fields("displayname")
logonNameUPN = "" : logonNameUPN = objectList.Fields("userPrincipalName")
On Error Goto 0
WScript.Echo logonName & ";" & logonNameUPN & ";" & displayName & ";" & userDN
objectList.MoveNext
Wend
'______________________________________________________ search members -> primaryGroupID search in the own domain
ldapFilter = "(primaryGroupID=" & groupRID & ")"
Set objectList = ado.Execute("<LDAP://" & domainDN & ">;" & ldapFilter & _
";distinguishedName,samAccountName,displayname,userPrincipalName;subtree")
While Not objectList.EOF
userDN = objectList.Fields("distinguishedName")
logonName = objectList.Fields("samAccountName")
On Error Resume Next
displayName = "" : displayName = objectList.Fields("displayname")
logonNameUPN = "" : logonNameUPN = objectList.Fields("userPrincipalName")
On Error Goto 0
WScript.Echo logonName & ";" & logonNameUPN & ";" & displayName & ";" & userDN
objectList.MoveNext
Wend
Gruppenmitglieder suchen in einem fremden Forest (mit Anmeldung)
This script finds all members of a specified group in the entire forest. Use the matching data for your desired Forest, or the domain where the regarding group. For this search, we need a global catalog server which is DC for the domain where the group is located. You could also use other credentials for the search (username and password):
domainDN = "DC=sub,DC=example,DC=com" 'specify the domain where the group is located
rootDN = "DC=example,DC=com" 'specify the LDAP path for the root domain
serverName = "192.168.0.66" 'specify the IP address or name of a global catalog
'this GC has to be DC of the domain where the group is
userName = InputBox("Enter user name","Credentials") 'you could also just use a static username instead, like "EXAMPLE\userXYZ"
password = InputBox("Enter password","Credentials") 'you could also just use a static password instead, like "P@ssw0rd"
groupName = "GroupA" 'insert your own group name here
'detect the DN and the RID of the group
ldapFilter = "(sAMAccountName=" & groupName & ")"
Set ado = CreateObject("ADODB.Connection")
ado.Provider = "ADSDSOObject"
ado.Properties("User ID") = userName
ado.Properties("Password") = password
ado.Properties("Encrypt Password") = True
ado.Open "ADSearch"
Set objectList = ado.Execute("<LDAP://" & serverName & "/" & domainDN & ">;" & ldapFilter & _
";distinguishedName,primaryGroupToken;subtree")
groupDN = objectList.Fields("distinguishedName")
groupRID = objectList.Fields("primaryGroupToken")
'______________________________________________________ search members -> memberOf search in the entire forest
ldapFilter = "(memberOf=" & groupDN & ")"
Set objectList = ado.Execute("<GC://" & serverName & "/" & domainDN & ">;" & ldapFilter & _
";distinguishedName,samAccountName,displayname,userPrincipalName;subtree")
While Not objectList.EOF
userDN = objectList.Fields("distinguishedName")
logonName = objectList.Fields("samAccountName")
On Error Resume Next
displayName = "" : displayName = objectList.Fields("displayname")
logonNameUPN = "" : logonNameUPN = objectList.Fields("userPrincipalName")
On Error Goto 0
WScript.Echo logonName & ";" & logonNameUPN & ";" & displayName & ";" & userDN
objectList.MoveNext
Wend
'______________________________________________________ search members -> primaryGroupID search in the domain
ldapFilter = "(primaryGroupID=" & groupRID & ")"
Set objectList = ado.Execute("<LDAP://" & serverName & "/" & domainDN & ">;" & ldapFilter & _
";distinguishedName,samAccountName,displayname,userPrincipalName;subtree")
While Not objectList.EOF
userDN = objectList.Fields("distinguishedName")
logonName = objectList.Fields("samAccountName")
On Error Resume Next
displayName = "" : displayName = objectList.Fields("displayname")
logonNameUPN = "" : logonNameUPN = objectList.Fields("userPrincipalName")
On Error Goto 0
WScript.Echo logonName & ";" & logonNameUPN & ";" & displayName & ";" & userDN
objectList.MoveNext
Wend