views:

151

answers:

0

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