| 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;
}