Platform SDK: Active Directory, ADSI, and Directory Services

How to Specify Comparison Values

Each attribute type has a syntax that determines the type of comparison values that you can specify in a search filter for that attribute.

The following sections describe what is required for each attribute syntax. For more information on attribute syntaxes, see Syntaxes for Active Directory Attributes.

Boolean
The value specified in a filter must be one of the following string values:

TRUE

FALSE

Examples of Boolean

Filter specifying showInAdvancedViewOnly set to TRUE:

(showInAdvancedViewOnly=TRUE)

Filter specifying showInAdvancedViewOnly set to FALSE:

(showInAdvancedViewOnly=FALSE)
Integer and Enumeration
The value specified in a filter must be a decimal Integer. Hexadecimal values must be converted to decimal.

Note that the LDAP matching rule controls can be used to perform bit-wise comparisons.

Matching rules have the following syntax:

attributename:ruleOID:=value

where attributename is the lDAPDisplayName of the attribute, ruleOID is the OID for the matching rule control, and value is the value you want to use for comparison.

Active Directory supports the following matching rules.
Matching rule OID Description
1.2.840.113556.1.4.803 LDAP_MATCHING_RULE_BIT_AND

The matching rule is true only if all bits from the property match the value. This rule is like the bit-wise AND operator.

1.2.840.113556.1.4.804 LDAP_MATCHING_RULE_BIT_OR

The matching rule is true if any bits from the property match the value. This rule is like the bit-wise OR operator.


Examples of Integer and Enumeration

Filter specifying groupType of Universal group (ADS_GROUP_TYPE_UNIVERSAL_GROUP is 0x00000008).

(groupType=8)

Filter specifying groupType of security-enabled Universal group (ADS_GROUP_TYPE_SECURITY_ENABLED is 0x80000000). So, ADS_GROUP_TYPE_SECURITY_ENABLED | ADS_GROUP_TYPE_UNIVERSAL_GROUP is 0x80000008 and converted to decimal value is 2147483650.

(groupType=2147483650)

Bit-wise comparisons

Filter specifying groupType with the ADS_GROUP_TYPE_SECURITY_ENABLED bit set:

(groupType:1.2.840.113556.1.4.804:=2147483648) )

The following query string searches for Universal distribution groups (that is, Universal groups without ADS_GROUP_TYPE_SECURITY_ENABLED flag):

(&(objectCategory=group)((&(groupType:1.2.840.113556.1.4.804:=8)(!(groupType:1.2.840.113556.1.4.803:=2147483650)))))
OctetString
The value specified in a filter is the data to be found. The data must be represented as an encoded byte string where each byte is preceded by a \ character.

Use the ADsEncodeBinaryData function to create an encoded string representation of binary data.

Note that wildcards are allowed.

Example of OctetString

Filter containing encoded string for schemaIDGUID with GUID value (in StringFromGUID2 format) of {BF967ABA-0DE6-11D0-A285-00AA003049E2}:

(schemaidguid=\BAz\96\BF\E6\0D\D0\11\A2\85\00\AA\000I\E2)

Filter containing encoded string for objectGUID with GUID value (in StringFromGUID2 format) of {FB4B7B35-E0AF-11D2-868C-00C04F8607E2}:

(objectguid=5\7BK\FB\AF\E0\D2\11\86\8C\00\C0O\86\07\E2)

The following code fragment prints the encoded string for the GUID guidmyTestAttributeDNString:

static const GUID guidmyTestAttributeDNString = 
  { 
  /* 9cb304e4-d60d-11d2-81a7-00c04fb98c1a */
    0x9cb304e4,
    0xd60d,
    0x11d2,
    {0x81, 0xa7, 0x00, 0xc0, 0x4f, 0xb9, 0x8c, 0x1a}
  };
 
LPOLESTR szTestBuffer = NULL;
HRESULT hrTemp = E_FAIL;
 
hrTemp = ADsEncodeBinaryData((LPBYTE)&guidmyTestAttributeDNString,
                              sizeof(GUID), &szTestBuffer);
if (SUCCEEDED(hrTemp))
    wprintf(L"%s\n",szTestBuffer);
 
if(szTestBuffer)
    FreeADsMem(szTestBuffer);
Sid
The value specified in a filter is the encoded byte string representation of the SID. See the discussion of encoded byte strings in the preceding discussion of the OctetString syntax.

Example of SID

Filter containing encoded string for objectSid with SID string value of S-1-5-21-1935655697-308236825-1417001333:

(ObjectSid=\01\04\00\00\00\00\00\05\15\00\00\00\11\C3\5Fs\19R\5F\12u\B9uT)
DN
The entire distinguished name that you want to match must be supplied.

Wildcards are not allowed.

Note that the objectCategory property also allows you to specify the lDAPDisplayName of the class set on the property. See the example that follows.

Examples of DN

Filter specifying a member containing CN=TestUser,DC=Microsoft,DC=COM:

(member=CN=TestUser,DC=Microsoft,DC=COM)

Two equivalent filters specifying an objectCategory set to CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=Microsoft,DC=COM:

(objectCategory=CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=Microsoft,DC=COM)
 
(objectCategory=attributeSchema)
INTEGER8
The value specified in a filter must be a decimal Integer. Hexadecimal values must be converted to decimal.

Examples of Integers

Filter specifying a creationTime set to a FILETIME of 3/10/99 3:31:32 PM:

(creationTime=125655822921406250)

The following functions create an exact match (=) filter for a large integer attribute and verify the existence of the attribute in the schema and its syntax:

HRESULT CreateExactMatchFilterLargeInteger(
                 LPOLESTR szAttribute,
                 INT64 liValue,
                 LPOLESTR *pszFilter
                 )
{
HRESULT hr = E_FAIL;
 
if ((!szAttribute)||(!pszFilter))
    return E_POINTER;
 
// Check that attribute exists and has 
// Integer8 (Large Integer) syntax.
 
hr = CheckAttribute(szAttribute, L"Integer8");
if (S_OK==hr) {
    LPOLESTR szTempFilter = new OLECHAR[MAX_PATH];
    swprintf(szTempFilter, L"%s=%I64d", szAttribute, liValue);
 
    // Allocate buffer for the filter string.
    // Caller must free the buffer using CoTaskMemFree.
    *pszFilter = (OLECHAR *)CoTaskMemAlloc (
                       sizeof(OLECHAR)*(wcslen(szTempFilter)+1));
    if (*pszFilter) {
        wcscpy(*pszFilter, szTempFilter);
        hr = S_OK;
    }
    else
        hr=E_FAIL;
}
return hr;
}
 
 
HRESULT CheckAttribute(
             LPOLESTR szAttribute,
             LPOLESTR szSyntax
            )
{
HRESULT hr = E_FAIL;
BSTR bstr;
IADsProperty *pObject = NULL;
LPOLESTR szPath = new OLECHAR[MAX_PATH];
 
if ((!szAttribute)||(!szSyntax))
    return E_POINTER;
 
swprintf(szPath,L"LDAP://schema/%s",szAttribute);
hr = ADsOpenObject(szPath,
           NULL,
           NULL,
           ADS_SECURE_AUTHENTICATION, //Use Secure Authentication
           IID_IADsProperty,
           (void**)&pObject);
if (SUCCEEDED(hr)) {
    hr = pObject->get_Syntax(&bstr);
    if (SUCCEEDED(hr)) {
        if (0==_wcsicmp(bstr, szSyntax)) 
            hr = S_OK;
        else
            hr = S_FALSE;
    }
    SysFreeString(bstr);
}
if (pObject)
    pObject->Release();
return hr;
}
PrintableString
Attributes that have these syntaxes are supposed to adhere to specific character sets (see Syntaxes for Active Directory Attributes). Currently, Active Directory does not enforce those character sets but it may enforce them in the future.

The value specified in a filter is a string. The comparison is case-sensitive.

(myAttribute=TheValue)
GeneralizedTime
The value specified in a filter is a string that represents the date in the following form:
YYYYMMDDHHMMSS.0Z

Z means no time differential. Note that Active Directory stores date/time as Greenwich mean time (GMT) time. If you specify a time with no time differential, you are specifying the time in GMT time.

If you are not in the GMT time zone, you can use a differential value (instead of specifying Z) to specify a time according to your time zone and then add the differential between your zone and GMT. The differential is based on the following: GMT=Local+differential.

To specify a differential, use the following format:

YYYYMMDDHHMMSS.0[+/-]HHMM

Examples of GeneralizedTime

Filter specifying a whenCreated time set to 3/23/99 8:52:58 PM:

(whenCreated=19990323205258.0Z)

Filter specifying a whenCreated time set to 3/23/99 8:52:58 PM New Zealand Standard Time (differential is 12 hours):

(whenCreated=19990323205258.0+1200)

Calculating Time Zone Differential

The following function returns the differential between the current local time zone and GMT. The value returned is a string in the following format:

[+/-]HHMM

For example, Pacific Standard Time would be -0800.

HRESULT GetLocalTimeZoneDifferential ( 
                     LPOLESTR *pszDifferential
                   )
{
HRESULT hr = E_FAIL;
DWORD dwReturn = 0L;
TIME_ZONE_INFORMATION timezoneinfo;
LONG lTimeDifferential = 0;
LONG lHours = 0;
LONG lMinutes = 0;
LPOLESTR szString = new OLECHAR[MAX_PATH];
dwReturn  = GetTimeZoneInformation(&timezoneinfo);
switch (dwReturn)
{
  case TIME_ZONE_ID_STANDARD:
    lTimeDifferential = timezoneinfo.Bias + timezoneinfo.StandardBias;
    //Bias is in minutes--calculate the hours for HHMM format.
    lHours = -(lTimeDifferential/60);
    //Bias is in minutes--calculate the minutes for HHMM format.
    lMinutes = lTimeDifferential%60L;
      swprintf(szString, L"%+03d%02d",lHours,lMinutes);
    hr = S_OK;
    break;
  case TIME_ZONE_ID_DAYLIGHT:
    lTimeDifferential = timezoneinfo.Bias + timezoneinfo.DaylightBias;
    //Bias is in minutes--calculate the hours for HHMM format.
    //Need to take the additive inverse.
    //Bias is based on GMT=Local+Bias.
    //We need a differential based on GMT=Local-Bias.
    lHours = -(lTimeDifferential/60);
    //Bias is in minutes--calculate the minutes for HHMM format.
    lMinutes = lTimeDifferential%60L;
      swprintf(szString, L"%+03d%02d",lHours,lMinutes);
    hr = S_OK;
    break;
  case TIME_ZONE_ID_INVALID:
  default:
    hr = E_FAIL;
    break;
}
 
if (SUCCEEDED(hr))
{
  *pszDifferential = (OLECHAR *)CoTaskMemAlloc (sizeof(OLECHAR)*(wcslen(szString)+1));
  if (*pszDifferential)
  {
  wcscpy(*pszDifferential, szString);
  //Call must free using CoTaskMemFree
  hr = S_OK;
  }
  else
    hr=E_FAIL;
}
 
return hr;
}
UTCTime
The value specified in a filter is a string that represents the date in the following form:
YYMMDDHHMMSSZ

Z means no time differential. Note that Active Directory stores date/time as GMT time. If you specify a time with no time differential, you are specifying the time in GMT time.

Note that the seconds (SS) value is optional.

If you are not in the GMT time zone, you can use a differential value (instead of specifying Z) to specify a time according to your time zone and then add the differential between your zone and GMT. The differential is based on the following: GMT=Local+differential.

To specify a differential, use the following format:

YYMMDDHHMMSS[+/-]HHMM

Examples of UTCTime

Filter specifying a myTimeAttrib time set to 3/23/99 8:52:58 PM:

(myTimeAttrib=990323205258Z)

Filter specifying a myTimeAttrib time set to 3/23/99 8:52:58 PM without seconds specified:

(myTimeAttrib=9903232052Z)

Filter specifying a myTimeAttrib time set to 3/23/99 8:52:58 PM New Zealand Standard Time (differential is 12 hours). This is equivalent to 3/23/99 8:52:58 AM GMT.

(myTimeAttrib=990323205258+1200)
DirectoryString
The value specified in a filter is a string. DirectoryString can contain Unicode characters. The comparison is case-insensitive.
(myAttribute2=THEVALUE)
OID
The entire OID that you want to match must be supplied.

Wildcards are not allowed.

Note that the objectCategory property also allows you to specify the lDAPDisplayName of the class set on the property. See the example below.

Examples of OID

Filter specifying governsID for volume class:

(governsID=1.2.840.113556.1.5.36)

Two equivalent filters specifying systemMustContain property containing uNCName, which has an OID of 1.2.840.113556.1.4.137:

(SystemMustContain=uNCName)
 
(SystemMustContain=1.2.840.113556.1.4.137)
Other Syntaxes
The following syntaxes are evaluated in a filter in the same manner as an octet string. See the discussion of the OctetString syntax earlier in this topic.