;; 
;;=====================================================================================----- 
;; 
;;FUNCTION       LDAPQuery() 
;; 
;;ACTION         Uses ADODB to retrieve information from Active Directory.  
;; 
;;AUTHOR         Christopher Shilt 
;; 
;;CONTRIBUTORS   Christophe Melin, Jens Meyer 
;; 
;;VERSION        1.0  - 2005/06/20 
;; 
;;HISTORY        1.0  - 2005/06/20 - Initial Release 
;; 
;;SYNTAX         LDAPQuery(WHAT, [FROM], [FILTER], [ORDER BY], [SCOPE], [USER], [PASSWORD])  
;; 
;;PARAMETERS      
;;                WHAT - Required - String 
;;                - Attribute (or array of attributes) to retrieve.  
;;  
;;                FROM - Optional - String 
;;                - Specifies the ADsPath of the base of the search.  
;;                For example, the ADsPath of the Users container in an Active  
;;                Directory domain might be 'LDAP://CN=Users,DC=Fabrikam,DC=COM'.  
;;		  For remote domain: 'LDAP://fabrikam.com/CN=Users,DC=Fabrikam,DC=COM'. 
;;  
;;                FILTER - Optional - String 
;;                - Specifies the query filter. You can also add wildcards  
;;                and conditions to an LDAP search filter. The following examples  
;;                show substrings that can be used to search the directory.  
;;  
;;                Get all users:  
;;                    "(objectClass=Users)"  
;;                Get all users with a common name equal to "bob":  
;;                    "(&(objectClass=Users)(cn=bob))"  
;;                Get all users with a common name beginning with "bob":  
;;                    "(&(objectClass=Users)(cn=bob*))"  
;;                Get all users containing "bob" somewhere in the common name:  
;;                    "(&(objectClass=Users)(cn=*bob*))"  
;;                Get all users with "bob" as the common name and "dull" as the surname:  
;;                    "(&(objectClass=Users)(cn=bob)(sn=dull))"  
;;  
;;                ORDER BY - Optional - String 
;;                - An optional statement that generates a server-side  
;;                sort. Active Directory supports the sort control, but it can  
;;                impact server performance if the results set is large. Active  
;;                Directory supports only a single sort key. You can use the  
;;                optional ASC and DESC keywords to specify ascending or descending  
;;                sort order; the default is ascending.  
;;  
;;                Order by surname with a ascending sort order:  
;;                    "sn"  
;;                Order by surname with a descending sort order:  
;;                    "sn DESC"  
;;  
;;                SCOPE - Optional - String 
;;                - Specifies the scope of a directory search.  
;;  
;;                * BASE - Limits the search to the base object. The result contains,  
;;                    at most, one object.   
;;                * ONELEVEL - Searches one level of the immediate children, excluding  
;;                    the base object.   
;;                * SUBTREE (DEFAULT) - Searches the whole subtree, including all 
;;                    the children and the base object itself.  
;;  
;;                USER - Optional - String 
;;                - Specifies the user to connect to the directory.  
;;  
;;                PASSWORD - Optional - String 
;;                - Specifies the password to connect to the directory.  
;;  
;; 
;;REMARKS        See http://msdn.microsoft.com/library/en-us/adschema/adschema/attributes_all.asp  
;;               for a list of LDAP attributes that may be queried.  
;; 
;;RETURNS        A multi-diminsional array of attributes entered in the order specified 
;;               in the WHAT parameter. 
;;  
;;               Sets the value of @ERROR based on success/failure (Note: A query that 
;;               returns no data is still considered a successful query).  
;; 
;;DEPENDENCIES   none 
;; 
;;TESTED WITH    W2K, WXP, W2K3 
;; 
;;EXAMPLES        
;; 
;;  
;; ; == Return the Name and AdsPath of all users ===================   
;; $aAttributes = "Name", "AdsPath"   
;; $sADsPath = "LDAP://"+GetObject("LDAP://rootDSE").Get("defaultNamingContext")   
;; $strFilter = "(&(objectClass=User)(Name=*))"   
;;   
;; $aResults = LDAPQuery($aAttributes,$sADsPath,$strFilter,"Name")   
;; @ERROR " | " @SERROR ?   
;;   
;; For $c = 0 to Ubound($aResults)  
;;     For $r = 0 to UBound($aResults,2)  
;;         $aResults[$c,$r] ?  
;;     Next  
;;     ?  
;; Next  
;;   
;; ; == Return the Name, AdsPath and members of all groups =========   
;; $aAttributes = "Name", "AdsPath", "member"   
;; $sADsPath = "LDAP://"+GetObject("LDAP://rootDSE").Get("defaultNamingContext")   
;; $strFilter = "(&(objectClass=group)(Name=*))"   
;;   
;; $aResults = LDAPQuery($aAttributes,$sADsPath,$strFilter)   
;; @ERROR " | " @SERROR ?   
;;   
;; For $c = 0 to Ubound($aResults)  
;;     For $r = 0 to UBound($aResults,2)  
;;         "=============================" ?   
;;         If VarType($aResults[$c,$r])>8192  
;;            "  Members:" ?  
;;            For Each $rr in $aResults[$c,$r]  
;;                "   " $rr ?  
;;            Next  
;;         Else  
;;            $aResults[$c,$r] ?  
;;         EndIf             
;;     Next  
;;     ?  
;; Next  
;;  
;   
Function LDAPQuery($What,Optional $From,Optional $Filter,Optional $OrderBy,Optional $Scope, Optional $User,Optional $Pswd)
    
    Dim $oCon,$oCMD,$oRS,$sQ,$aR,$C,$R
    
    $sQ="<"+Iif($From="","LDAP://"+GetObject("LDAP://rootDSE").Get("defaultNamingContext"), $From)+">;"+$Filter+";"+Iif(VarType($What)>8192,Join($What,','),$What)+";"+Iif($Scope<>"base" AND $Scope<>"onelevel","subtree",$Scope)
    
    $oCon=CreateObject("ADODB.Connection")
    $oCon.Provider="ADsDSOObject"
    $oCon.Properties("Encrypt Password").Value=1
    $oCon.Properties("ADSI Flag").Value=1
    If $User AND $Pswd
        $oCon.Properties("User ID").Value=$User
        $oCon.Properties("Password").Value=$Pswd
    EndIf
    $oCon.Open("Active Directory Provider")
     
    $oCMD=CreateObject("ADODB.Command")
    $oCMD.ActiveConnection=$oCon
    $oCMD.CommandText=$sQ
    $oCMD.Properties("Page Size").Value=1000
    $oCMD.Properties("Timeout").Value=30
    $oCMD.Properties("Cache Results").Value=0
    
    If InStr($OrderBy,"distinguishedName")
        $oRS=CreateObject("ADODB.Recordset")
        $oRS.CursorLocation=3
        $oRS.Sort=$OrderBy
        $oRS.Open($sQ,$oCon,0,1,1)
    Else
        If $OrderBy
            $oCMD.Properties("Sort On").Value=$OrderBy
        EndIf
        $oRS=$oCMD.Execute
    EndIf
    If @ERROR Exit @ERROR EndIf
    If $oRS.BOF AND $oRS.EOF Exit @ERROR EndIf
    
    $aR = $oRS.GetRows()
    Dim $aFR[Ubound($aR,2),Ubound($aR,1)]
    For $R=0 to Ubound($aR,2)
        For $C=0 to Ubound($aR,1)
            $aFR[$R,$C]=$aR[$C,$R]
        Next
    Next
    
    $LDAPQuery=$aFR
 
EndFunction