Platform SDK: Active Directory, ADSI, and Directory Services

Example Code for Building a Query String to Search for Groups by Type/Scope

[C++]

The following code fragment contains a function that creates a query string that uses type or scope for enumerating or searching for groups:

////////////////////
// Enum Definitions
//This first enum should be defined for Beta 3 and later.
enum
    {    ADS_GROUP_TYPE_GLOBAL_GROUP    = 0x2,
    ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP    = 0x4,
    ADS_GROUP_TYPE_UNIVERSAL_GROUP    = 0x8,
    ADS_GROUP_TYPE_SECURITY_ENABLED    = 0x80000000
    };
 
// (used for telling BuildGroupTypeQueryString() how to build the string)
enum ELDAPMatchingRule
{
    lmrAND,
    lmrOR
};
////////////////////////////////////////////////////////////////////////////////////////////////////
/*  BuildGroupTypeQueryString()   - Builds a Query String for searching on groupType
 
    Parameters
 
        ELDAPMatchingRule elmrRule      - Specifies whether the passed bitmask is ANDed or ORed
        DWORD dwGroupTypeBits           - Bitflags for groupType
 
*/
WCHAR * BuildGroupTypeQueryString(ELDAPMatchingRule elmrRule, DWORD dwGroupTypeBits)
{
    static WCHAR wszRet [255];
    wszRet[0] = 0l;
    /* 
        The LDAP_MATCHING RULE is defined as follows:
 
        LDAP_MATCHING_RULE_BIT_OR 1.2.840.113556.1.4.804
        LDAP_MATCHING_RULE_BIT_AND 1.2.840.113556.1.4.803
 
        These strings are used to describe the bits in dwGroupTypeBits.
        Specifying an "and" (using LDAP_MATCHING_RULE_BIT_AND) causes 
        the query to mean a bit-wise "and" for the bits in dwGroupTypeBits.
        Alternatively, specifying LDAP_MATCHING_RULE_BIT_OR denotes a bit-wise
        "or" of the flags present in dwGroupTypeBits
    */
    switch (elmrRule)
    {
        case lmrAND:
        wsprintf(wszRet,L"(groupType:1.2.840.113556.1.4.803:=%d)",dwGroupTypeBits);
        break;
        case lmrOR:
        wsprintf(wszRet,L"(groupType:1.2.840.113556.1.4.804:=%d)",dwGroupTypeBits);
        break;
    }
    OutputDebugStringW(wszRet);
    OutputDebugStringW(L"\r\n");
    return wszRet;
}
[Visual Basic]

When using Visual Basic®, use the ADO SQL syntax for specifying Group Type.

Definitions for bit values:

Public Const ADS_GROUP_TYPE_GLOBAL_GROUP = &H2
Public Const ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP = &H4
Public Const ADS_GROUP_TYPE_UNIVERSAL_GROUP = &H8
Public Const ADS_GROUP_TYPE_SECURITY_ENABLED = &H80000000

Query Strings:

ALL GLOBAL GROUPS

"GroupType=" & Str(ADS_GROUP_TYPE_GLOBAL_GROUP) & " or " & "GroupType=" & Str(ADS_GROUP_TYPE_GLOBAL_GROUP Or ADS_GROUP_TYPE_SECURITY_ENABLED)

ALL DOMAIN LOCAL GROUPS (With and without Security)

"GroupType=" & Str(ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP) & " or " & "GroupType=" & Str(ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP Or ADS_GROUP_TYPE_SECURITY_ENABLED)

ALL SECURITY ENABLED GROUPS

"GroupType=" & Str(ADS_GROUP_TYPE_SECURITY_ENABLED)

The following code fragment searches for groups based on type using the BuildGroupTypeQueryString subroutine:

'************************************
'  QueryAndOutputGroups()   -           Performs several sample searches using ADO
'
'
'    Parameters
'
'        oDirObjectRoot As IDirectoryObject - The root from where searches will be performed
'
Sub QueryAndOutputGroups(oDirObjectRoot As IDirectoryObject)
 
    '*******************************
    ' Search for all the groups
    DisplayMessage " "
    DisplayMessage "<<<<<<<<<<<<<<<<<<<<<ALL GROUPS>>>>>>>>>>>>>>>>>" 'cn = 'UG*' objectCategory
    SimpleDirectorySearch oDirObjectRoot, "objectCategory = 'group'", ADS_SCOPE_SUBTREE
    
    '*****************************************
    ' Search for all the GLOBAL groups
    DisplayMessage " "
    DisplayMsgWaitForInput "Hit OK to perform a subtree search of all the GLOBAL groups"
    DisplayMessage " "
    DisplayMessage "<<<<<<<<<<<<<<<<<<<<<ALL GLOBAL Groups>>>>>>>>>>>>>>>>>"
    SimpleDirectorySearch oDirObjectRoot, "GroupType=" & Str(ADS_GROUP_TYPE_GLOBAL_GROUP) & " or " & _
                            "GroupType=" & Str(ADS_GROUP_TYPE_GLOBAL_GROUP Or ADS_GROUP_TYPE_SECURITY_ENABLED), _
                            ADS_SCOPE_SUBTREE
 
    '*****************************************
    ' Search for all the DOMAIN LOCAL  groups
    DisplayMessage " "
    DisplayMsgWaitForInput "Hit OK to perform a subtree search of all the DOMAIN LOCAL groups"
    DisplayMessage " "
    DisplayMessage "<<<<<<<<<<<<<<<<<<<<<ALL Domain Local Groups>>>>>>>>>>>>>>>>>"
    SimpleDirectorySearch oDirObjectRoot, "GroupType=" & Str(ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP) & " or " & _
                            "GroupType=" & Str(ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP Or ADS_GROUP_TYPE_SECURITY_ENABLED), _
                            ADS_SCOPE_SUBTREE
 
    '        #ifdef USE_UNIVERSAL_GROUPS
 
    '*****************************************
    ' Search for all the UNIVERSAL  groups
    DisplayMessage " "
    DisplayMsgWaitForInput "Hit OK to perform a subtree search of all the UNIVERSAL groups"
    DisplayMessage " "
    DisplayMessage "<<<<<<<<<<<<<<<<<<<<<ALL Universal Groups>>>>>>>>>>>>>>>>>"
    SimpleDirectorySearch oDirObjectRoot, "GroupType=" & Str(ADS_GROUP_TYPE_UNIVERSAL_GROUP) & " or " & _
                            "GroupType=" & Str(ADS_GROUP_TYPE_UNIVERSAL_GROUP Or ADS_GROUP_TYPE_SECURITY_ENABLED), _
                            ADS_SCOPE_SUBTREE
    '        #End If
 
    '*****************************************
    ' Search for all the Security Enabled  groups
    DisplayMessage " "
    DisplayMsgWaitForInput "Hit OK to perform a subtree search of all Security Enabled groups"
    DisplayMessage " "
    DisplayMessage "<<<<<<<<<<<<<<<<<<<<<ALL Security Enabled Groups>>>>>>>>>>>>>>>>>"
    SimpleDirectorySearch oDirObjectRoot, "GroupType=" & Str(ADS_GROUP_TYPE_SECURITY_ENABLED) & " or " & _
                            "GroupType=" & Str(ADS_GROUP_TYPE_SECURITY_ENABLED Or ADS_GROUP_TYPE_SECURITY_ENABLED), _
                            ADS_SCOPE_SUBTREE
 
    '*****************************************
    ' Search for all the Security Enabled LOCAL groups
    DisplayMessage " "
    DisplayMsgWaitForInput "Hit OK to perform a subtree search of all Security Enabled LOCAL groups"
    DisplayMessage " "
    DisplayMessage "<<<<<<<<<<<<<<<<<<<<<ALL Security Enabled Domain Local Groups>>>>>>>>>>>>>>>>>"
    SimpleDirectorySearch oDirObjectRoot, "GroupType=" & Str(ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP Or _
                            ADS_GROUP_TYPE_SECURITY_ENABLED), _
                            ADS_SCOPE_SUBTREE
 
    '*****************************************
    ' Search for all the DOMAIN LOCAL groups whose
    ' name begins with 'UGExercise'
    DisplayMessage " "
    DisplayMsgWaitForInput "Hit OK to perform a subtree search of all DOMAIN LOCAL  groups that begin with the text 'UGExercise'"
    DisplayMessage " "
    DisplayMessage "<<<<<<<<<<<<<<<<<<<<<ALL Domain Local Groups Beginnig with 'UGExercise' >>>>>>>>>>>>>>>>>"
 
    SimpleDirectorySearch oDirObjectRoot, "cn='UGExercise*' and (GroupType=" & _
                            Str(ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP) & " or GroupType=" & _
                            Str(ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP Or ADS_GROUP_TYPE_SECURITY_ENABLED) & _
                            ")", ADS_SCOPE_SUBTREE
 
    '*****************************************
    ' Search for ALL the groups whose
    ' name begins with 'UGExercise'
    DisplayMessage " "
    DisplayMsgWaitForInput "Hit OK to perform a subtree search of ALL groups that begin with the text 'UGExercise '"
    DisplayMessage " "
    DisplayMessage "<<<<<<<<<<<<<<<<<<<<<ALL Groups Beginning with 'UGExercise' >>>>>>>>>>>>>>>>>"
 
    SimpleDirectorySearch oDirObjectRoot, " cn='UGExercise*' and objectCategory='group'", ADS_SCOPE_SUBTREE
 
End Sub
 
'////////////////////////////////////////////////////////////////////////////////////////////////////
'   SimpleDirectorySearch()   - Uses ADO to search the directory
'                               Results are displayed in the list box
'    Parameters
'
'        oDirObjectRoot As IDirectoryObject  - Root of the search
'        ByVal sSearchFilter As String       - LDAP Search filter
'        ByVal lScope As Integer             - Scope for Searching possible values are:
'                                                ADS_SCOPE_BASE
'                                                ADS_SCOPE_ONELEVEL
'                                                ADS_SCOPE_SUBTREE
'
'        (See IDirectorySearch and ADS_SCOPEENUM in the docs for more info)
'
Sub SimpleDirectorySearch(oDirObjectRoot As IDirectoryObject, ByVal sSearchFilter As String, ByVal lScope As Integer)
 
    Dim iIndex As Integer
    iIndex = 0
    Dim v, j, i
 
    Dim con As New Connection, rs As New Recordset
    Dim Com As New Command
    Dim oIADs As IADs
    Dim sAdsPathRoot As String
 
    ' Get the LDAP path to the passed in object
    sAdsPathRoot = GetAdsPath(oDirObjectRoot)
 
    'Open a Connection object
    con.Provider = "ADsDSOObject"
 
    '---------------------------------------------------------------------
    ' To be authenticated using alternate credentials
    ' use connection properties of User ID and Password
    '---------------------------------------------------------------------
    ' con.Properties("User ID") = "Administrator"
    ' con.Properties("Password") = ""
 
    ' Open the connection
    con.Open "Active Directory Provider"
 
    ' Create a command object on this connection
    Set Com.ActiveConnection = con
 
    ' set the query string using SQL Dialect
    Com.CommandText = "select name,AdsPath from '" & sAdsPathRoot & "' where " & sSearchFilter & " ORDER BY NAME"
 
    ' Tell the user what the search filter is
    DisplayMessage "Search Filter = " & Com.CommandText
 
    '---------------------------------------------------
    ' Or you can use LDAP Dialect, for example,
    '---------------------------------------------------
    ' Ex Com.CommandText = "<LDAP://Microsoftsvr1/dc=Microsoft,DC=com>;(objectClass=*);name"
    ' For LDAP Dialect, the valid search scope are base, oneLevel and subtree
    ' Com.CommandText = "<" & adDomainPath & ">;(objectClass=*);name;subtree"
    ' For LDAP Dialect (<LDAP:...>), there is no way to specify sort order in the string,
    ' However, you can use this SORT ON property to specify sort order.
    ' for SQL Dialect you can use ORDER BY in the SQL Statement
    ' Ex. Com.Properties("Sort On") = "Name"
 
    'Set the preferences for Search
    Com.Properties("Page Size") = 1000
    Com.Properties("Timeout") = 30 'seconds
    Com.Properties("searchscope") = lScope
    Com.Properties("Chase referrals") = ADS_CHASE_REFERRALS_EXTERNAL
    Com.Properties("Cache Results") = False ' do not cache the result, it results in less memory requirements
 
    'Execute the query
    Set rs = Com.Execute
    
    ' Tell the user how many rows
    DisplayMessage "Returned " & Str(rs.RecordCount) & " rows"
 
    ' Navigate the record set
    If Not rs.EOF Then
        rs.MoveFirst
    End If
 
    On Error Resume Next
    While Not rs.EOF
        ' Display the LDAP path for the row
        DisplayMessage rs.Fields("AdsPath")
        rs.MoveNext
    Wend
 
End Sub