How to get more than 1000 group members including foreign SAMs (VBScript)

Hi all,

We may have a group in our Active Directory with members from a foreign domain. We may try to retrieve all those members with ADSI and a code like this: Using IADs::GetInfoEx for Range Retrieval. The issue with this code is that we will only be able to see the SID of foreign principals (i.e. CN=S-1-5-21-1234567890...-123,CN=ForeignSecurityPrincipals,DC=domain,DC=com), which may not be very useful for us.

The following sample (based on above Range Retrieval sample) will retrieve all members in a group (including foreign principals) and show their sAMAccountName:

 ' PARAMETERS.
'
strFileName = "c:\List.txt"
strGroupDN = "CN=groupName,CN=Users,DC=domainName,DC=com"

' Bind to the group with the current credentials.
'
Set oGroup = GetObject("LDAP://" & strGroupDN)

' Create file for results.
'
Set fs = CreateObject("Scripting.FileSystemObject")
Set usersFile = fs.CreateTextFile(strFileName, True)

' For compatibility with all operating systems, the number of objects
' retrieved by each query should not exceed 999. The number of objects
' to retrieve should be as close as possible to 999 to reduce the number
' of round trips to the server necessary to retrieve the objects.
rangeStep = 999
lowRange = 0
highRange = lowRange + rangeStep

Do
  ' Use the "member;range=<lowRange>-<highRange>" syntax.
  '
  strCommandText = "member;range=" & lowRange & "-" & highRange
  usersFile.WriteLine(vbCrLf & "Current search command: " & _
  strCommandText & vbCrLf)

  ' Load the specified range of members into the local cache. This 
  ' will throw an error if the range exceeds the properties contained 
  ' in the object. The "On Error GoTo quit" error handler will cause 
  ' the loop to terminate when this happens.
  '
  On Error Resume Next
  oGroup.GetInfoEx Array(strCommandText), 0
  If Err.Number = &H80072020 Then
    Exit Do
  End If
  On Error Goto 0

  ' Enumerate the retrieved members.
  '
  oMembers = oGroup.Get("member")
  If vbArray And VarType(oMembers) Then
    For Each oMember In oMembers
      ' Add the member.
      '            
      Set oUser = GetObject("LDAP://" & oMember)            
      If (oUser.Class = "foreignSecurityPrincipal") Then

        usersFile.WriteLine(GetForeignSAM(oUser))
      Else
        usersFile.WriteLine(oUser.sAMAccountName)
      End If 
      nRetrieved = nRetrieved + 1
    Next
  Else
    ' oGroup.Get returned only one member, so add it to the list.
    '
    Set oUser = GetObject("LDAP://" & oMembers)            
    If (oUser.Class = "foreignSecurityPrincipal") Then

      usersFile.WriteLine(GetForeignSAM(oUser))
    Else
      usersFile.WriteLine(oUser.sAMAccountName)
    End If 

    nRetrieved = nRetrieved + 1
  End If

  ' Increment the high and low ranges to query for the next block of 
  ' objects.
  '
  lowRange = highRange + 1
  highRange = lowRange + rangeStep
Loop While True

MsgBox "File """ & strFileName &  """ created"


'-----------------------------------------------------------------------
' HELPER FUNCTIONS
'-----------------------------------------------------------------------
function GetForeignSAM (oUser)
  ' CONSTANTS.
  '
  ADS_SID_RAW = 0
  ADS_SID_HEXSTRING = ADS_SID_RAW + 1
  ADS_SID_SAM = ADS_SID_HEXSTRING + 1
  ADS_SID_UPN = ADS_SID_SAM + 1
  ADS_SID_SDDL = ADS_SID_UPN + 1
  ADS_SID_WINNT_PATH = ADS_SID_SDDL + 1

  ' Get the SID
  '

  ' Now, resolve the SID into its sAMAcountName.
  '
  set oADsSID = CreateObject("ADsSID")
  oADsSID.SetAs ADS_SID_RAW, oUser.Get("objectSid")

  ' Requesting the Sam Account Name
  '
  GetForeignSAM = oADsSID.GetAs(ADS_SID_SAM)     

end function

Note: ADsSID object is implemented in ADsSecurity.dll.

I hope this helps.

Regards,

 

Alex (Alejandro Campos Magencio)