4.9. Searching with a Bitwise Filter

Problem

You want to search against an attribute that contains a bit flag and you need to use a bitwise filter.

Solution

Using a graphical user interface

  1. Follow the directions in Recipe 4.5 for searching for objects.

  2. For the Filter, enter the bitwise expression, such as the following, which will find all universal groups:

    (&(objectclass=group)(objectCategory=group)(groupType:1.2.840.113556.1.4.804:=8))
  3. Click Run.

Using a command-line interface

The following query finds universal groups using a bitwise OR filter:

> dsquery * cn=users,dc=rallencorp,dc=com -scope subtree -attr "name" -filter[RETURN]
"(&(objectclass=group)(objectCategory=group)(groupType:1.2.840.113556.1.4.804:=8) )"

The following query finds disabled user accounts using a bitwise AND filter:

> dsquery * cn=users,dc=rallencorp,dc=com -attr name -scope subtree -filter[RETURN]
"(&(objectclass=user)(objectcategory=person)(useraccountcontrol:1.2.840.113556.1.4.[RETURN]
803:=514))"

Using VBScript

' The following query finds all disabled user accounts
strBase   =  "<LDAP://cn=users,dc=rallencorp,dc=com>;"
strFilter = "(&(objectclass=user)(objectcategory=person)" & _ 
            "(useraccountcontrol:1.2.840.113556.1.4.803:=514));" 
strAttrs  = "name;"
strScope  = "subtree"

set objConn = CreateObject("ADODB.Connection")
objConn.Provider = "ADsDSOObject"
objConn.Open "Active Directory Provider"
set objRS = objConn.Execute(strBase & strFilter & strAttrs & strScope)
objRS.MoveFirst
while Not objRS.EOF
    Wscript.Echo objRS.Fields(0).Value
    objRS.MoveNext
wend

Discussion

Many attributes in Active Directory are composed of bit flags. A bit flag is often used to encode properties about an object into a single attribute. For example, the groupType attribute on group objects is a bit flag that is used to determine the group scope and type.

The userAccountControl attribute on user and computer objects is used to describe a whole series of properties, including account status (i.e., enabled or disabled), account lockout, password not required, smartcard authentication required, etc.

The searchFlags and systemFlags attributes on attributeSchema objects define, among other things, whether an attribute is constructed, indexed, and included as part of Ambiguous Name Resolution (ANR).

To search against these types of attributes, you need to use bitwise search filters. There are two types of bitwise search filters you can use, one that represents a logical OR and one that represents logical AND. This is implemented within a search filter as a matching rule. A matching rule is simply a way to inform the LDAP server (in this case, a domain controller) to treat part of the filter differently. Here is an example of what a matching rule looks like:

(userAccountControl:1.2.840.113556.1.4.803:=514)

The format is (attributename:MatchingRuleOID:=value). As I mentioned, there are two bitwise matching rules, which are defined by OIDs. The logical AND matching rule OID is 1.2.840.113556.1.4.803 and the logical OR matching rule OID is 1.2.840.113556.1.4.804. These OIDs instruct the server to perform special processing on the filter. A logical OR filter will return success if any bit specified by value, is stored in attributename. Alternatively, the logical AND filter will return success if all bits specified by value, match the value of attributename. Perhaps an example will help clarify this.

To create a normal user account, you have to set userAccountControl to 514. The number 514 was calculated by adding the normal user account flag of 512 together with the disabled account flag of 2 (512 + 2 = 514). If you use the following logical OR matching rule against the 514 value, as shown here:

(useraccountcontrol:1.2.840.113556.1.4.804:=514)

then all normal user accounts (flag 512) OR disabled accounts (flag 2) would be returned. This would include enabled user accounts (from flag 512), disabled computer accounts (from flag 2), and disabled user accounts (from flag 2). In the case of userAccountControl, flag 2 can apply to both user and computer accounts and, hence, why both would be included in the returned entries.

One way to see the benefits of bitwise matching rules is that they allow you to combine a bunch of comparisons into a single filter. In fact, it may help to think that the previous OR filter I just showed could also be written using two expressions:

(|(useraccountcontrol:1.2.840.113556.1.4.804:=2) (useraccountcontrol:1.2.840.113556.
1.4.804:=512))

Just as before, this will match userAccountControl attributes that contain either the 2 or 512 flags.

For logical AND, similar principles apply. Instead of any of the bits in the flag being a possible match, ALL of the bits in the flag must match for it to return a success. If we changed our userAccountControl example to use logical AND, it would look like this:

(useraccountcontrol:1.2.840.113556.1.4.803:=514)

In this case, only normal user accounts that are also disabled would be returned. The same filter could be rewritten using the & operator instead of | as in the following:

(&(useraccountcontrol:1.2.840.113556.1.4.803:=2) 
  (useraccountcontrol:1.2.840.113556.1.4.803:=512))

An important subtlety to note is that when you are comparing only a single bit-flag value, the logical OR and logical AND matching rule would return the same result. So if we wanted to find any normal user accounts we could search on the single bit flag of 512 using either of the following:

(useraccountcontrol:1.2.840.113556.1.4.803:=512)

(useraccountcontrol:1.2.840.113556.1.4.804:=512)

See Also

MSDN: Enumerating Groups by Scope or Type in a Domain, MSDN: Determining Which Properties Are Non-Replicated, Constructed, Global Catalog, and Indexed, and MS KB 305144 (How to Use the UserAccountControl Flags to Manipulate User Account Properties)

Get Active Directory Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.