;; 
;;=====================================================================================----- 
;; 
;;FUNCTION       GetLDAPData() 
;; 
;;ACTION         Return an array of data from Active Directory using the LDAPQuery UDF 
;;		 (DEPENDENCY). Used to quickly populate list of user, group, computer, 
;;               OU, or Site names. 
;; 
;;AUTHOR         Glenn Barnas 
;; 
;;VERSION        1.0  - 2013/08/02 
;; 
;;HISTORY        1.0  - 2013/08/02 - Initial Release 
;; 
;;SYNTAX         GetLDAPData(Type [, Qualifier] [, Paths] [, Depth] [, Root] [, AttList]) 
;; 
;;PARAMETERS     Type - Required - String 
;;                - One of: User, Group, Computer, OU, or Site. 
;;                Only the first character is needed. 
;; 
;;		 Qualifier - Optional - String 
;;               - A wildcard object name specification used to limit the return data set. 
;; 
;;		 Paths - Optional - String 
;;               - A semicolon-delimited list of OU paths to search,  specified in DN 
;;		 format. Each OU path must end with a comma. 
;; 
;;		 Depth - Optional - String 
;;               - Specifies the level of query recursion 
;;		    BASE - Returns one object from the base 
;;		    ONELEVEL - Returns objects only from the specified OU 
;;		    SUBTREE - Returns objects from the OU and all child OUs (default) 
;; 
;;		 Root - Optional - String 
;;               - An alternate domain definition. When specifying an alternate domain 
;;               for Sites, the format must be "CN=configuration,DC=domain,DC=tld". 
;; 
;;		 AttList - Optional - String 
;;               - Attribute name or array of attributes to return instead of the 
;;		 default object name. When an array is specified, the function returns 
;;		 an array instead of a single element. Valid ONLY for User objects. 
;; 
;;REMARKS        This is generally used to obtain a list of objects used to populate 
;;		 a drop-down list, but can be used anywhere that only the CN values 
;;               of the objects queried are needed. 
;; 
;;RETURNS        Array, Empty String if no data found. 
;;               A single-dimension array with the values queried. An empty string and 
;;		 ERROR 2 is returned if no data is returned by the query. When an attribute 
;;		 array is specified for user queries, an array of arrays is returned instead 
;;               of a simple array. 
;; 
;;DEPENDENCIES   fnLDAPQuery() 
;; 
;;TESTED WITH    W2K, WXP, W2K3, W2K8, W2K12 
;; 
;;EXAMPLES       ; return all user IDs in the "USA" OU 
;;               $aUsers = GetLDAPData('U', , 'OU=USA,') 
;;               $aAttributes = 'aDSPath', 'SamAccountName', 'displayName' 
;;               ; return array containing arrays of requested attributes 
;;               $aData =  GetLDAPData('U', , , , , $aAttributes) 
;; 
Function GetLDAPData($_Type, OPTIONAL $_Qual, OPTIONAL $_Path, OPTIONAL $_Depth, OPTIONAL $_Root, OPTIONAL $_Attrs)
 
  Dim $_Error  					; Error result 
  Dim $_aAttributes[0]				; LDAP Attribute List 
  Dim $_Filter					; LDAP Filter 
  Dim $_aResults				; Result array from fnLDAPQuery 
  Dim $_aPath					; array of OU paths 
  Dim $_ADsRoot					; Domain definition 
  Dim $_aTmp , $_aRTmp 				; Single-dim array of data to return, Record array 
  Dim $_C, $_R, $_Or				; counter & Offset vars 
  Dim $_Dns					; DNS component of DN string 
 
 
  $_Error = 0
  $_Dns   = ''
 
  ; get the default (local) root path 
  $_ADsRoot = GetObject("LDAP://rootDSE").Get("defaultNamingContext")
 
  ; use an alternate root path if defined 
  $_ADsRoot = IIf($_Root, $_Root, $_ADsRoot)
 
  ; if the ADsRoot value is in DNS/DN format, split it into DNS and DN strings 
  If InStr($_ADsRoot, '/') > 0
    $_aTmp = Split($_ADsRoot, '/')
    $_Dns = $_aTmp[0] + '/'
    $_ADsRoot = $_aTmp[1]
  EndIf
 
  $_Type = Left($_Type, 1)			; strip to single char 
  $_Qual = IIf($_Qual, $_Qual, '*')		; default to global wildcard if no qualifier defined 
 
 
  Select
   Case $_Type = 'U'				; USER 
    Select
     Case VarType($_Attrs) > 8192		; non-empty array - specify custom attribute list 
        $_aAttributes = $_Attrs
     Case VarType($_Attrs) > 0			; non-empty var - specify custom attribute 
        $_aAttributes[0] = $_Attrs
     Case 1
        $_aAttributes[0] = 'sAMAccountName'
     EndSelect
 
    $_aPath = Split($_Path, ';')
    For Each $_Path in $_aPath
 
      $_Filter = '(&(objectCategory=person)(objectClass=user)(cn=' + $_Qual + '))'
      $_aResults = LDAPQuery($_aAttributes,'LDAP://' + $_Dns + $_Path + $_ADsRoot, $_Filter, 'Name', $_Depth)
      $_Error = IIf(@ERROR, @ERROR, $_Error)
 
      If Ubound($_aResults) >= 0		; have data 
        If Ubound($_aResults, 2) > 0		; multiple attributes to return 
          $_Or = 1 + UBound($_aTmp)
          ReDim Preserve $_aTmp[Ubound($_aResults) + $_Or]
          For $_R = 0 to UBound($_aResults)
            ReDim $_aRTmp[UBound($_aResults, 2)]
            For $_C = 0 to UBound($_aResults, 2)
              $_aRTmp[$_C] = $_aResults[$_R, $_C]
            Next
            $_aTmp[$_R + $_Or] = $_aRTmp
          Next
        Else					; single attribute to return 
          $_Or = 1 + UBound($_aTmp)
          ReDim Preserve $_aTmp[Ubound($_aResults) + $_Or]
          For $_R = 0 to Ubound($_aResults)
            $_aTmp[$_R + $_Or] = $_aResults[$_R, 0]
          Next
        EndIf
      Else
        $GetLDAPData = ''
        Exit 2				; no data found 
      EndIf
    Next
    $GetLDAPData = $_aTmp
 
   Case $_Type = 'G'			; GROUP 
    $_aPath = Split($_Path, ';')
    For Each $_Path in $_aPath
      $_aAttributes = 'Name'
      $_Filter = '(&(objectClass=group)(cn=' + $_Qual + '))'
      $_aResults = LDAPQuery($_aAttributes,'LDAP://' + $_Dns + $_Path + $_ADsRoot, $_Filter, 'Name', $_Depth)
      $_Error = IIf(@ERROR, @ERROR, $_Error)
      If Ubound($_aResults) >= 0
        $_Or = 1 + UBound($_aTmp)
        ReDim Preserve $_aTmp[Ubound($_aResults) + $_Or]
        For $_R = 0 to Ubound($_aResults)
          $_aTmp[$_R + $_Or] = $_aResults[$_R, 0]
        Next
      Else
        $GetLDAPData = ''
        Exit 2
      EndIf
    Next
    $GetLDAPData = $_aTmp
 
   Case $_Type = 'C'			; COMPUTER 
    $_aPath = Split($_Path, ';')
    For Each $_Path in $_aPath
      $_aAttributes = 'Name'
      $_Filter = '(&(objectClass=computer)(cn=' + $_Qual + '))'
      $_aResults = LDAPQuery($_aAttributes,'LDAP://' + $_Dns + $_Path + $_ADsRoot, $_Filter, 'Name', $_Depth)
      $_Error = IIf(@ERROR, @ERROR, $_Error)
      If Ubound($_aResults) >= 0
        $_Or = 1 + UBound($_aTmp)
        ReDim Preserve $_aTmp[Ubound($_aResults) + $_Or]
        For $_R = 0 to Ubound($_aResults)
          $_aTmp[$_R + $_Or] = $_aResults[$_R, 0]
        Next
      Else
        $GetLDAPData = ''
        Exit 2
      EndIf
    Next
    $GetLDAPData = $_aTmp
 
   Case $_Type = 'O'			; OU 
    $_aPath = Split($_Path, ';')
    For Each $_Path in $_aPath
      $_aAttributes = 'Name'
      $_Filter = '(objectClass=organizationalUnit)'
      $_aResults = LDAPQuery($_aAttributes,'LDAP://' + $_Dns + $_Path + $_ADsRoot, $_Filter, 'Name', 'ONELEVEL')
      $_Error = IIf(@ERROR, @ERROR, $_Error)
      If Ubound($_aResults) >= 0
        $_Or = 1 + UBound($_aTmp)
        ReDim Preserve $_aTmp[Ubound($_aResults) + $_Or]
        For $_R = 0 to Ubound($_aResults)
          $_aTmp[$_R + $_Or] = $_aResults[$_R, 0]
        Next
      Else
        $GetLDAPData = ''
        Exit 2
      EndIf
    Next
    $GetLDAPData = $_aTmp
 
   Case $_Type = 'S'			; SITE 
    $_ADsRoot = GetObject("LDAP://rootDSE").Get("ConfigurationNamingContext")
    $_ADsRoot = IIf($_Root, $_Root, $_ADsRoot)
    $_aAttributes = 'Name'
    $_Filter = '(&(objectClass=Site)(Name=*))'
    $_aResults = LDAPQuery($_aAttributes,'LDAP://cn=Sites,' + $_Dns + $_ADsRoot, $_Filter, 'Name')
    $_Error = @ERROR
    If Ubound($_aResults) >= 0
      Dim $_aTmp[Ubound($_aResults)]
      For $_R = 0 to Ubound($_aResults)
        $_aTmp[$_R] = $_aResults[$_R, 0]
      Next
      $GetLDAPData = $_aTmp
      Else
        $GetLDAPData = ''
        Exit 2
    EndIf
 
  EndSelect
 
  Exit $_Error
 
EndFunction