Platform SDK: Active Directory, ADSI, and Directory Services |
The following code finds all users in the forest by querying the global catalog using ADO:
Dim Con As ADODB.Connection Dim ocommand As ADODB.Command Dim gc As IADs On Error Resume Next 'Maximum number of items to list on a msgbox. MAX_DISPLAY = 5 'ADO Connection object Set Con = CreateObject("ADODB.Connection") If (Err.Number <> 0) Then BailOnFailure Err.Number, "on CreateObject" End If Con.Provider = "ADsDSOObject" If (Err.Number <> 0) Then BailOnFailure Err.Number, "on Provider" End If Con.Open "Active Directory Provider" If (Err.Number <> 0) Then BailOnFailure Err.Number, "on Open" End If 'ADO Command object Set ocommand = CreateObject("ADODB.Command") If (Err.Number <> 0) Then BailOnFailure Err.Number, "on CreateObject" End If ocommand.ActiveConnection = Con If (Err.Number <> 0) Then BailOnFailure Err.Number, "on Active Connection" End If Set gc = GetObject("GC:") For Each child In gc Set entpr = child Next If (Err.Number <> 0) Then BailOnFailure Err.Number, "on GetObject for GC" End If show_items entpr.ADsPath, "foo" ocommand.CommandText = "<" & entpr.ADsPath & ">;(&(objectCategory=person)(objectClass=user));distinguishedName,name;subTree" If (Err.Number <> 0) Then BailOnFailure Err.Number, "on CommandText" End If Set rs = ocommand.Execute If (Err.Number <> 0) Then BailOnFailure Err.Number, "on Execute" End If strText = "Found " & rs.RecordCount & " Users in Forest:" intNumDisplay = 0 intCount = 0 ' Navigate the record set rs.MoveFirst While Not rs.EOF intCount = intCount + 1 strText = strText & vbCrLf & intCount & ") " For i = 0 To rs.Fields.Count - 1 If rs.Fields(i).Type = adVariant And Not (IsNull(rs.Fields(i).Value)) Then strText = strText & rs.Fields(i).Name & " = " For j = LBound(rs.Fields(i).Value) To UBound(rs.Fields(i).Value) strText = strText & rs.Fields(i).Value(j) & " " Next Else strText = strText & rs.Fields(i).Name & " = " & rs.Fields(i).Value & vbCrLf End If Next intNumDisplay = intNumDisplay + 1 'Display in msgbox if there are MAX_DISPLAY items to display If intNumDisplay = MAX_DISPLAY Then Call show_items(strText, "Users in forest") strText = "" intNumDisplay = 0 End If rs.MoveNext Wend show_items strText, "foo" ''''''''''''''''''''''''''''''''''''''' 'Display subroutines ''''''''''''''''''''''''''''''''''''''' Sub show_items(strText, strName) MsgBox strText, vbInformation, "Search GC for users" & strName End Sub Sub BailOnFailure(ErrNum, ErrText) strText = "Error 0x" & Hex(ErrNum) & " " & ErrText MsgBox strText, vbInformation, "ADSI Error" WScript.Quit End Sub
The following code fragment contains a function that finds all users in the forest by querying the global catalog:
HRESULT FindAllUsersInGC() { HRESULT hr = E_FAIL; HRESULT hrGC = S_OK; VARIANT var; ULONG lFetch; // Interface Pointers IDirectorySearch *pGCSearch = NULL; IADsContainer *pContainer = NULL; IUnknown *pUnk = NULL; IEnumVARIANT *pEnum = NULL; IDispatch *pDisp = NULL; IADs *pADs = NULL; //Bind to global catalog hr = ADsOpenObject(L"GC:", NULL, NULL, ADS_SECURE_AUTHENTICATION, //Use Secure Authentication IID_IADsContainer, (void**)&pContainer); if (SUCCEEDED(hr)) { hr = pContainer->get__NewEnum( &pUnk ); if (SUCCEEDED(hr)) { hr = pUnk->QueryInterface( IID_IEnumVARIANT, (void**) &pEnum ); if (SUCCEEDED(hr)) { // Now Enumerate--there should be only one item. hr = pEnum->Next( 1, &var, &lFetch ); if (SUCCEEDED(hr)) { while( hr == S_OK ) { if ( lFetch == 1 ) { pDisp = V_DISPATCH(&var); hr = pDisp->QueryInterface( IID_IDirectorySearch, (void**)&pGCSearch); hrGC = hr; } VariantClear(&var); hr = pEnum->Next( 1, &var, &lFetch ); }; } } if (pEnum) pEnum->Release(); } if (pUnk) pUnk->Release(); } if (pContainer) pContainer->Release(); if (FAILED(hrGC)) { if (pGCSearch) pGCSearch->Release(); return hrGC; } //Create search filter LPOLESTR pszSearchFilter = L"(&(objectCategory=person)(objectClass=user))"; //Search entire subtree from root. ADS_SEARCHPREF_INFO SearchPrefs; SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; SearchPrefs.vValue.dwType = ADSTYPE_INTEGER; SearchPrefs.vValue.Integer = ADS_SCOPE_SUBTREE; DWORD dwNumPrefs = 1; // COL for iterations ADS_SEARCH_COLUMN col; // Handle used for searching ADS_SEARCH_HANDLE hSearch; // Set the search preference hr = pGCSearch->SetSearchPreference( &SearchPrefs, dwNumPrefs); if (FAILED(hr)) return hr; // Set attributes to return CONST DWORD dwAttrNameSize = 2; LPOLESTR pszAttribute[dwAttrNameSize] = {L"cn",L"distinguishedName"}; // Execute the search hr = pGCSearch->ExecuteSearch(pszSearchFilter, pszAttribute, dwAttrNameSize, &hSearch ); if ( SUCCEEDED(hr) ) { // Call IDirectorySearch::GetNextRow() to retrieve the next row //of data while( pGCSearch->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 = pGCSearch->GetColumn( hSearch, pszAttribute[x], &col ); if ( SUCCEEDED(hr) ) { // Print the data for the column and free the column // Note the requested attributes are type CaseIgnoreString. wprintf(L"%s: %s\r\n",pszAttribute[x],col.pADsValues->CaseIgnoreString); pGCSearch->FreeColumn( &col ); } else wprintf(L"<%s property is not a string>",pszAttribute[x]); } wprintf(L"------------------------------\n"); } // Close the search handle to clean up pGCSearch->CloseSearchHandle(hSearch); } if (pGCSearch) pGCSearch->Release(); return hr; }