Platform SDK: Active Directory, ADSI, and Directory Services

Example Code for Performing a Query in a Domain

[C++]

The following code fragment contains two functions that perform a query against a specified root object and displays all groups and groups by type:

////////////////////////////////////////////////////////////////////////////////////////////////////
/*  QueryAndOutputGroups()   -         Gets an IDirectorySearch Interface on the passed root
                                       Performs several sample searches using IDirectorySearch
 
    Parameters
 
        IDirectoryObject * pDirObjectRoot - The root from where searches will be performed
*/
void QueryAndOutputGroups(IDirectoryObject * pDirObjectRoot)
{
    HRESULT hr;
    DisplayConsoleMsgWaitForEnter(L"To look at the new Active Directory structure, use\n"
                                  L"IDirectorySearch, to perform several querys on the directory\n"
                                  L" NOTE: All of the samples object that this program\n creates"
                                  L" begin with the text 'UGExercise'.\n\n" 
                                  L"Hit ENTER to perform a subtree search of ALL the groups.\n" );
 
    /////////////////////////////////////////////////
    // Search for  groups
 
    // Interface Pointers
    IDirectorySearch *pDSSearch=NULL;
 
 
    // The attributes that are needed
    LPWSTR pszAttr[] ={  L"Name", L"ADsPath" };
    DWORD dwAttrNameSize = sizeof(pszAttr)/sizeof(LPWSTR);
 
    // Preferences on Search
    // Do a DEEP SUBTREE search for all accounts
    ADS_SEARCHPREF_INFO arSearchPrefs[1];
    DWORD dwNumPrefs;
 
    arSearchPrefs [0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE ; 
    arSearchPrefs [0].vValue.dwType = ADSTYPE_INTEGER;
    arSearchPrefs [0].vValue.Integer = ADS_SCOPE_SUBTREE;
 
    dwNumPrefs = 1;   
 
    hr = pDirObjectRoot->QueryInterface(IID_IDirectorySearch,(void**)&pDSSearch);
 
    if (SUCCEEDED(hr))
    {
 
        ////////////////////////////////////////////////
        // Search for all the groups
        puts("<<<<<<<<<<<<<<<<<<<<<ALL GROUPS>>>>>>>>>>>>>>>>>");
        hr = SimpleDirectorySearch(pDSSearch,
                                   L"(objectCategory=group)",
                                   pszAttr,dwAttrNameSize,
                                   arSearchPrefs,
                                   dwNumPrefs);
 
        ////////////////////////////////////////////////
        // Search for all the GLOBAL groups
 
        DisplayConsoleMsgWaitForEnter(
            L"Hit ENTER to perform a subtree search of all the GLOBAL groups\n"); 
        puts("<<<<<<<<<<<<<<<<<<<<<ALL GLOBAL Groups>>>>>>>>>>>>>>>>>"); 
        hr = SimpleDirectorySearch(pDSSearch,
                                    BuildGroupTypeQueryString(lmrOR,ADS_GROUP_TYPE_GLOBAL_GROUP),
                                    pszAttr,dwAttrNameSize,arSearchPrefs,
                                    dwNumPrefs);
 
        ////////////////////////////////////////////////
        // Search for all the DOMAIN LOCAL  groups
 
        DisplayConsoleMsgWaitForEnter(
            L"Hit ENTER to perform a subtree search of all the DOMAIN LOCAL groups\n"); 
        puts("<<<<<<<<<<<<<<<<<<<<<ALL Domain Local Groups>>>>>>>>>>>>>>>>>");
        hr = SimpleDirectorySearch(pDSSearch,
                                   BuildGroupTypeQueryString(lmrOR,ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP),
                                   pszAttr,dwAttrNameSize,
                                   arSearchPrefs,
                                   dwNumPrefs);
 
        if (bUseUniversalGroups)
        {
            ////////////////////////////////////////////////
            // Search for all the UNIVERSAL  groups
            DisplayConsoleMsgWaitForEnter(
                L"Hit ENTER to perform a subtree search of all the UNIVERSAL groups\n"); 
            puts("<<<<<<<<<<<<<<<<<<<<<ALL Universal Groups>>>>>>>>>>>>>>>>>");
            hr = SimpleDirectorySearch(pDSSearch,
                                       BuildGroupTypeQueryString(lmrOR,
                                       ADS_GROUP_TYPE_UNIVERSAL_GROUP),
                                       pszAttr,dwAttrNameSize,
                                       arSearchPrefs,
                                       dwNumPrefs);
        }
 
        ////////////////////////////////////////////////
        // Search for all the Security Enabled  groups
 
        DisplayConsoleMsgWaitForEnter(
            L"Hit ENTER to perform a subtree search of all Security Enabled groups\n"); 
        puts("<<<<<<<<<<<<<<<<<<<<<ALL Security Enabled Groups>>>>>>>>>>>>>>>>>");
        hr = SimpleDirectorySearch(pDSSearch,
                                   BuildGroupTypeQueryString(lmrOR,ADS_GROUP_TYPE_SECURITY_ENABLED),
                                   pszAttr,dwAttrNameSize,
                                   arSearchPrefs,
                                   dwNumPrefs);
 
        ////////////////////////////////////////////////
        // Search for all the Security Enabled LOCAL groups
 
        DisplayConsoleMsgWaitForEnter(
            L"Hit ENTER to perform a subtree search of all Security Enabled LOCAL groups\n"); 
        puts("<<<<<<<<<<<<<<<<<<<<<ALL Security Enabled Domain Local Groups>>>>>>>>>>>>>>>>>"); 
        hr = SimpleDirectorySearch(pDSSearch,
                                   BuildGroupTypeQueryString(lmrAND,ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP | ADS_GROUP_TYPE_SECURITY_ENABLED),
                                   pszAttr,dwAttrNameSize,
                                   arSearchPrefs,
                                   dwNumPrefs);
 
        ////////////////////////////////////////////////
        // Search for all the DOMAIN LOCAL groups whose 
        // name begins with 'UGExercise'
 
        DisplayConsoleMsgWaitForEnter(
            L"Hit ENTER to perform a subtree search of all DOMAIN LOCAL  groups that begin with the text \'UGExercise\'\n"); 
        puts("<<<<<<<<<<<<<<<<<<<<<ALL Domain Local Groups Beginnig with \'UGExercise\' >>>>>>>>>>>>>>>>>");
 
        // Build a string for the Query - this helper
        // aids in taking the BITMASK passed to it and 
        // converting it into a string
        WCHAR * szwGTQuery = BuildGroupTypeQueryString(lmrOR,ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP );
        WCHAR   szwQuery[512];
 
        // Add the bit value to the LDAP query string
        // Look for all objects which have 
        // DOMAIN LOCAL and a groupType == the domain local bitmask
        // built previously with BuildGroupTypeQueryString()
        wsprintf(szwQuery,L"(&(cn=UGExercise*)%s)",szwGTQuery);
        OutputDebugString(szwQuery);
        OutputDebugString(L"\r\n");
 
        // Perform the search using the query string built previously (szwQuery)
        hr = SimpleDirectorySearch(pDSSearch,szwQuery,pszAttr,dwAttrNameSize,arSearchPrefs,dwNumPrefs);
 
        ////////////////////////////////////////////////
        // Search for ALL the groups whose 
        // name begins with 'UGExercise'
 
        DisplayConsoleMsgWaitForEnter(
            L"Hit ENTER to perform a subtree search of ALL groups that begin with the text \'UGExercise \'\n"); 
 
        puts("<<<<<<<<<<<<<<<<<<<<<ALL Groups Beginning with \'UGExercise \' >>>>>>>>>>>>>>>>>");
        hr = SimpleDirectorySearch(pDSSearch,
                                   L"(&(cn=UGExercise*)(objectCategory=group))",
                                   pszAttr,dwAttrNameSize,
                                   arSearchPrefs,
                                   dwNumPrefs);
 
        // Release the Search interface
        pDSSearch->Release();
        pDSSearch= NULL;
    }
    else
        puts("ERROR: pDirObjectRoot->QueryInterface(IID_IDirectorySearch,(void**)&pDSSearch); FAILED!");
 
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/*  SimpleDirectorySearch()   - Uses IDirectorySearch to search the directory
                                results are printed to the console window
    Parameters
 
        IDirectorySearch *pDSSearch         - IDirectorySearch interface from the object 
                                              which will serve as the root of the search
        LPWSTR pszSearchFilter              - LDAP Search filter
        LPWSTR pszAttr[]                    - Array of Attribute names to retrieve
        DWORD dwAttrNameSize                - Number of elements in pszAttr
        PADS_SEARCHPREF_INFO pSearchPrefs   - ADSI Array of preferences
        DWORD dwNumPrefs                    - Number of elements in pSearchPrefs
*/
HRESULT SimpleDirectorySearch(IDirectorySearch *pDSSearch,LPWSTR pszSearchFilter, LPWSTR pszAttr[],DWORD dwAttrNameSize, 
                                PADS_SEARCHPREF_INFO pSearchPrefs,DWORD dwNumPrefs  )
{
    wprintf(L"\nSearch Filter =%s\n",pszSearchFilter);
    // COL for iterations
    ADS_SEARCH_COLUMN col;
    HRESULT hr;
 
    // Interface Pointers
    IADs    *pObj = NULL;
    IADs    * pIADs = NULL;
 
    // Handle used for searching
    ADS_SEARCH_HANDLE hSearch;
 
    // if the preferences were passed in, call IDirectorySearch::SetSearchPreference()
    if (dwNumPrefs &&  pSearchPrefs)
    {
        hr = pDSSearch->SetSearchPreference( pSearchPrefs, dwNumPrefs);
        if (FAILED(hr))
            return hr;
    }
    // Execute the search using the passed search filter, the 
    // attributes and the address of the search handle
    hr = pDSSearch->ExecuteSearch(pszSearchFilter,pszAttr ,dwAttrNameSize, &hSearch );
 
    if ( SUCCEEDED(hr) )
    { 
 
    // Call IDirectorySearch::GetNextRow() to retrieve the next row 
    //of data
        while( pDSSearch->GetNextRow( hSearch) != S_ADS_NOMORE_ROWS )
        {
 
            // loop through the array of passed column names,
            // print the data for each column
            for (DWORD x = 0; x < dwAttrNameSize; x++)
            {
 
                // Get the data for this column
                hr = pDSSearch->GetColumn( hSearch, pszAttr[x], &col );
 
                if ( SUCCEEDED(hr) )
                {
 
                    // Print the data for the column and free the column
                    wprintf(L"%s: %s\r\n",pszAttr[x],col.pADsValues->CaseIgnoreString); 
                    pDSSearch->FreeColumn( &col );
                }
                else
                    wprintf(L"<%s property NOT available>",pszAttr[x]);
            }
            puts("------------------------------------------------");
        }
 
        // Close the search handle to clean up
        pDSSearch->CloseSearchHandle(hSearch);
    } 
    return hr;
}
[Visual Basic]

The following subroutine performs a query against a specified root object and display all groups and groups by type:

'************************************
'  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://Microsoft1/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