Directory Services

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

The following code example shows a query string that uses type or scope to enumerate or search for groups.

//
// Enum Definitions.
// Define the first enumeration.
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 to instruct BuildGroupTypeQueryString() how to build the string.
enum ELDAPMatchingRule
{
	lmrAND,
	lmrOR
};
////////////////////////////////////////////////////////////////////////////////////////////////////
/*  BuildGroupTypeQueryString()   - Builds a Query String for searching a groupType.
 
	Parameters
 
		ELDAPMatchingRule elmrRule	- Specifies if the passed bitmask is combined with AND or OR.
		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 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;
}

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 example shows how to search for groups based upon type using the BuildGroupTypeQueryString subroutine.

'************************************
'  QueryAndOutputGroups()   -  Performs several sample searches using ADO
'
'
'	Parameters
'
'		oDirObjectRoot As IDirectoryObject - The root from where searches are 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 "Click 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 "Click 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 "Click 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 "Click 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 "Click 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 "Click 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 with
	' names that begin with 'UGExercise'
	DisplayMessage " "
	DisplayMsgWaitForInput "Click OK to perform a subtree search of ALL groups that begin with '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"
 
	' Identify the search filter for the user.
	DisplayMessage "Search Filter = " & Com.CommandText
 
	'------------------------------
	' You can also use LDAP Dialect
	'------------------------------
	' Ex Com.CommandText = "<LDAP://Fabrikamsvr1/dc=Fabrikam,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

	' Notify the user about the number of 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