Directory Services

Example Code for Using the Global Catalog to Find Users in a Forest

The following code example demonstrates how to search for users in a forest. This example uses ADSI with Visual Basic.

[Visual Basic]
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
'   PrintAllUsersInGlobalCatalog()
'
'   Prints to the debug window the cn and disintguishedName of all users in the
'   current forest whose givenName begins with "jeff". This is accomplished
'   by binding to the global catalog and then searching for all users
'   objects that meet the criteria.
'
'   Note - This code could be modified to print all users in the forest, but
'   on a large enterprise, it can take a long time to search for and print
'   all users. The filter in this example is only given to avoid causing a
'   lot of network traffic.
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Sub PrintAllUsersInGlobalCatalog()
	Const ADS_SECURE_AUTHENTICATION = 1

	Dim oGC As IADsContainer
	Dim oEntrprise As IADs

	' Get the enterprise object from the GC namespace.
	Set oGC = GetObject("GC:")
	For Each child In oGC
		Set oEntrprise = child
		Exit For
	Next

	' Setup ADO.
	Set oConn = CreateObject("ADODB.Connection")
	Set oComm = CreateObject("ADODB.Command")
	 
	oConn.Provider = "ADsDSOObject"
	oConn.Properties("ADSI Flag") = ADS_SECURE_AUTHENTICATION

	oConn.Open
	oComm.ActiveConnection = oConn

	' Set the search command and filter.
	oComm.CommandText = "<" & oEntrprise.ADsPath & ">;(&(objectCategory=person)(objectClass=user)(givenName=jeff*));cn,distinguishedName;subTree"

	' Execute the query.
	Set oRS = oComm.Execute

	' Print the results.
	oRS.MoveFirst
	While Not oRS.EOF
		For Each field In oRS.Fields
			Debug.Print field
		Next
	
		Debug.Print ""
		oRS.MoveNext
	Wend
End Sub

The following code example demonstrates how to search for users in a forest. This example uses ADSI with C++.

[C++]
/***************************************************************************

	PrintAllUsersInGlobalCatalog()

	Prints to the console the cn and disintguishedName of all users in the 
	current forest whose givenName begins with "jeff". This is accomplished 
	by binding to the global catalog and then searching for all users 
	objects that meet the criteria.

	Note - This code could be modified to print all usres in the forest, bit 
	on a large enterprise, it can take a long time to search for and print 
	all users. The filter in this example is only given to avoid causing a 
	lot of network traffic.

***************************************************************************/

HRESULT PrintAllUsersInGlobalCatalog()
{
	HRESULT hr;
	CComPtr<IADsContainer> spContainer;
 
	// Bind to global catalog.
	hr = ADsOpenObject(L"GC:",
				NULL,
				NULL,
				ADS_SECURE_AUTHENTICATION,
				IID_IADsContainer,
				(void**)&spContainer);
	if(FAILED(hr))
	{
		return hr;
}
 
	CComPtr<IEnumVARIANT> spEnum;
	hr = spContainer->get__NewEnum((IUnknown**)&spEnum);
	if(FAILED(hr))
	{
		return hr;
}

	// Enumerate. There should be only one item.
	CComPtr<IDirectorySearch> spGCSearch;
	CComVariant svar;
	ULONG ulFetched;

	/*
	Get the first item in the enumeration. The global catalog container will 
	only have one object in it.
	*/
	hr = spEnum->Next(1, &svar, &ulFetched);
	if(SUCCEEDED(hr) && (ulFetched == 1) && (VT_DISPATCH == svar.vt))
	{
		hr = svar.pdispVal->QueryInterface(IID_IDirectorySearch, (LPVOID*)&spGCSearch);
}

	if(FAILED(hr))
	{
		return hr;
}
	else if(NULL == spGCSearch.p)
	{
		return E_FAIL;
}
 
	ADS_SEARCHPREF_INFO SearchPrefs[2];

	// Search entire subtree from root.
	SearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
	SearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
	SearchPrefs[0].vValue.Integer = ADS_SCOPE_SUBTREE;
 
	/*
	Use paging in case there are more results than the server can provide in a 
	single page.
	*/
	SearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
	SearchPrefs[1].vValue.dwType = ADSTYPE_INTEGER;
	SearchPrefs[1].vValue.Integer = 1000;
 
	// Set the search preference.
	hr = spGCSearch->SetSearchPreference(SearchPrefs, sizeof(SearchPrefs)/sizeof(ADS_SEARCHPREF_INFO));
	if(FAILED(hr))
	{
		return hr;
}

	ADS_SEARCH_HANDLE hSearch;

	// Create the search filter.
	LPWSTR pwszSearchFilter = L"(&(objectCategory=person)(objectClass=user)(givenName=jeff*))";
 
	// Set attributes to return.
	LPWSTR rgpwszAttributes[] = {L"cn", L"distinguishedName"};
	DWORD dwNumAttributes = sizeof(rgpwszAttributes)/sizeof(LPWSTR);
 
	// Execute the search.
	hr = spGCSearch->ExecuteSearch( pwszSearchFilter,
									rgpwszAttributes,
									dwNumAttributes,
									&hSearch);
	if(FAILED(hr))
	{
		return hr;
}

	// Get the first result row.
	hr = spGCSearch->GetFirstRow(hSearch);
	while(S_OK == hr)
	{
		ADS_SEARCH_COLUMN col;

		// Enumerate the retrieved attributes.
		for(DWORD i = 0; i < dwNumAttributes; i++)
		{
			hr = spGCSearch->GetColumn(hSearch, rgpwszAttributes[i], &col);
			if(SUCCEEDED(hr))
			{
				switch(col.dwADsType)
				{
				case ADSTYPE_DN_STRING:
					wprintf(L"%s: %s\n\n", rgpwszAttributes[i], col.pADsValues[0].DNString);
					break;

				case ADSTYPE_CASE_IGNORE_STRING:
					wprintf(L"%s: %s\n\n", rgpwszAttributes[i], col.pADsValues[0].CaseExactString);
					break;

				default:
					break;
			}
			
				// Free the column.
				spGCSearch->FreeColumn(&col);
		}
	}
	
		// Get the next row.
		hr = spGCSearch->GetNextRow(hSearch);
}

	// Close the search handle to clean up.
	hr = spGCSearch->CloseSearchHandle(hSearch);

	return hr;
}