ADO program to list members of a large group.
- by AlexGomez
Hi everyone,
I'm attempting to list all the members in a Active Directory group using ADO. The problem I have is that many of these groups have over 1500 members and ADSI cannot handle more than 1500 items in a multi-valued attribute. Fortunately I came across Richard Muller's wonderful VBScript that handles more than 1500 members at http://www.rlmueller.net/DocumentLargeGroup.htm
I modified his code as shown below so that I can list ALL the groups and its memberships in a certain OU. However, I'm keeping getting the exception shown below:
"ADODB.Recordset: Item cannot be found in the collection corresponding to the requested name or ordinal."
My program appears to get stuck at:
strPath = adoRecordset.Fields("ADsPath").Value
Set objGroup = GetObject(strPath)
All I am doing above is issuing the query to get back a recordset consisting of the ADsPath for each group in the OU. It then walks through the recordset and grabs the ADsPath for the first group and store its in a variable named strPath; we then use the value of that variable to bind to the group account for that group. It really should work!
Any idea why the code below doesn't work for me? Any pointers will be great appreciated. Thanks.
Option Explicit
Dim objRootDSE, strDNSDomain, adoCommand
Dim adoConnection, strBase, strAttributes
Dim strFilter, strQuery, adoRecordset
Dim strDN, intCount, blnLast, intLowRange
Dim intHighRange, intRangeStep, objField
Dim objGroup, objMember, strName
' Determine DNS domain name.
Set objRootDSE = GetObject("LDAP://RootDSE")
'strDNSDomain = objRootDSE.Get("DefaultNamingContext")
strDNSDomain = "XXXXXXXX"
' Use ADO to search Active Directory.
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open = "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
' Specify base of search.
strBase = "<LDAP://" & strDNSDomain & ">"
' Specify the attribute values to retrieve.
strAttributes = "member"
' Filter on objects of class "group"
strFilter = "(&(objectClass=group)(samAccountName=*))"
' Enumerate direct group members.
' Use range limits to handle more than 1000/1500 members.
' Setup to retrieve 1000 members at a time.
blnLast = False
intRangeStep = 999
intLowRange = 0
IntHighRange = intLowRange + intRangeStep
Do While True
If (blnLast = True) Then
' If last query, retrieve remaining members.
strQuery = strBase & ";" & strFilter & ";" _
& strAttributes & ";range=" & intLowRange _
& "-*;subtree"
Else
' If not last query, retrieve 1000 members.
strQuery = strBase & ";" & strFilter & ";" _
& strAttributes & ";range=" & intLowRange & "-" _
& intHighRange & ";subtree"
End If
adoCommand.CommandText = strQuery
Set adoRecordset = adoCommand.Execute
adoRecordset.MoveFirst
intCount = 0
Do Until adoRecordset.EOF
strPath = adoRecordset.Fields("ADsPath").Value
Set objGroup = GetObject(strPath)
For Each objField In adoRecordset.Fields
If (VarType(objField) = (vbArray + vbVariant)) _
Then
For Each strDN In objField.Value
' Escape any forward slash characters, "/", with the backslash
' escape character. All other characters that should be escaped are.
strDN = Replace(strDN, "/", "\/")
' Check dictionary object for duplicates.
'If (objGroupList.Exists(strDN) = False) Then
' Add to dictionary object.
'objGroupList.Add strDN, True
' Bind to each group member, to find member's samAccountName
Set objMember = GetObject("LDAP://" & strDN)
' Output group cn, group samaAccountName and group member's samAccountName.
Wscript.Echo objMember.samAccountName
intCount = intCount + 1
'End if
Next
End If
Next
adoRecordset.MoveNext
Loop
adoRecordset.Close
' If this is the last query, exit the Do While loop.
If (blnLast = True) Then
Exit Do
End If
' If the previous query returned no members, then the previous
' query for the next 1000 members failed. Perform one more
' query to retrieve remaining members (less than 1000).
If (intCount = 0) Then
blnLast = True
Else
' Setup to retrieve next 1000 members.
intLowRange = intHighRange + 1
intHighRange = intLowRange + intRangeStep
End If
Loop