Searching Active Directory for User Accounts

Microsoft® Windows® 2000 Scripting Guide

A critical part of scripting user account management is searching the Active Directory database. Some of the user account management tasks that involve searching Active Directory include:

  • Verifying that a user account does not already exist before attempting to create one.

  • Finding all user account objects that do not contain a value for a particular attribute.

  • Reading the value of an attribute from all user accounts before modifying the value.

  • Setting an attribute of all user account objects that meet a specific criterion to the same value.

The query interfaces available to VBScript are the ActiveX® Data Object (ADO) interfaces. These interfaces use OLE DB to read information from the Active Directory database. The information returned by the ADO interfaces is read-only; you cannot use ADO from VBScript to modify the result set returned by a query. However, after the result set is returned, you can use ADSI interfaces and methods to modify values and then write the values back to the Active Directory database. For an illustration of this technique, see "Modifying Multiple User Accounts by Using the Result Set from a Search," later in this section.

A typical query using ADO almost always includes three objects:

  • Connection

  • Command

  • RecordSet

All of the tasks in this section use these objects to search the Active Directory.

The Connection object loads the OLE DB provider, ADsDSOObject, to establish a link to the Active Directory database through the ADSI search interface, IDirectorySearch.

After the link is established, the Command object initiates the query. The query passes through ADsDSOObject to IDirectorySearch, which then uses an LDAP query function to query the Active Directory database. The RecordSet object receives the data returned from the query.

The CommandText property of the Command object is used to specify the query to run against Active Directory. The CommandText property uses either LDAP or SQL dialect to define the query. With one exception, all examples in this section use the LDAP search dialect to assign a query string to the CommandText property. For information about the SQL dialect for performing an Active Directory search, see the Active Directory Programmers Guide link on the Web Resources kit.

LDAP search dialect consists of four parts:

  • Search base

  • One or more search filters

  • One or more attributes

  • Search scope

Search base specifies where in Active Directory to begin the search. Search filters specify the criteria for the search. Attributes specify the data that should be returned, and search scope specifies where in the Active Directory database to start and finish the search.

note Note

  • For more information about constructing and running queries of the Active Directory database, see "ADSI Scripting Primer" in this book.

Search Base

The search base of a query string consists of three parts: angle brackets surrounding the expressions, a moniker, and a distinguishedName. The syntax for the search base is:


The moniker is either LDAP or GC, and the distinguishedName specifies the starting point of the search. For example, if you want to query the contents of the Management OU in the domain for attributes contained in the global catalog, the search base is:


Using the LDAP moniker instructs the query to perform a search using a full replica of the Active Directory database in a domain and, depending on the query, possibly all subdomains. In contrast, using the GC moniker instructs the query to search a global catalog server, which contains a partial replica of its domain and all of its child domains. Consequently, if you query a global catalog server in the root domain, the query contains data from all domains in the forest. Therefore, if all attributes that you want to query are contained in the global catalog, it is more efficient to query this data source than to search one or more full replicas of the Active Directory database in the forest.

Rather then hard code the search base into a query string, you can retrieve the rootDomainNamingContext from the RootDSE object. For information about retrieving this value using a script, see "ADSI Scripting Primer" in this book.


Search filters are an optional but important part of the LDAP search dialect used by the OLE DB provider to query the Active Directory database. A search filter consists of the name of a filter property, an operator, and a value. Each search filter is enclosed in parentheses, and search filters can be combined.

When combining search filters, preface the filter clause with an AND operator (&), an OR operator (|), or a NOT operator (!) and surround the entire filter clause in parentheses. There are a number of user account search filter examples in the remainder of this section. For more details about search filter syntax, see "ADSI Scripting Primer" in this book.

To limit a search to a specific type of object, specify either the objectClass or objectCategory search filter property. Table 7.11shows the relationship between the user account types and the objectCategory and objectClass properties.

Table 7.11 User Account Types and the Values of objectCategory and objectClass

Account Type



User Account






The objectCategory property lets you limit the query to all user account types that were derived from a class whose defaultObjectCategory attribute is person. The objectClass property lets you limit the query to objects matching any one of the values stored in the objectClass multivalued attribute.

Before determining which filter property to use or whether both filter properties are necessary, it is important to understand which objects are returned by each filter property and value combination. Consider the following example of an OU named R&D with two user account types: User1 (user account) and ContactUser1 (contact account). Table 7.12 shows search filters that use the objectCategory and objectClass properties to limit a search to user account types.

Table 7.12 Values Returned by Filter Properties



(objectCategory = person)

User1, ContactUser1

(objectClass = top),

(objectClass = person), or

(objectClass = organizationalPerson)

User1, ContactUser1

(objectClass = user)


(objectClass = contact)


If a computer object also existed in the R&D OU, the search filter examples in rows 2 and 3 would return the computer object. This is because the objectClass attribute of a computer object is Top:person;organizationalPerson;user;computer.

The objectCategory attribute is the better choice for most searches involving user objects, not only because it limits the search to user account types but because the objectCategory filter is single-valued, indexed, and stored in the global catalog. For more information about performing efficient searches, see "ADSI Scripting Primer" in this book.

The third row in Table 7.12 shows a filter example that limits the search to the user, the user account type that is a security principal. Another way to accomplish this is to specify a filter that uses both the objectCategory and objectClass properties, as shown in the following example:


Because the objectCategory attribute is indexed and in the global catalog, using this filter first should provide an efficient method of limiting the results before the objectClass filter is evaluated. However, to use the objectCategory attribute stored in the global catalog, you must use the GC moniker in the search base.

Other attributes of user account types are commonly specified in a search filter for limiting the result set returned from a user account type query. For example, you can search on a specific sAMAccountName value to verify that a particular name does not exist in the domain. A filter to return a sAMAccountName of MyerKen is as follows: (sAMAccountName = myerken). You must specify the lDAPDisplayName of an attribute to use it in a search filter.

Search filters also support wildcards such as the * (ANY operator). See "Using Wildcards in Search Filters" later in this section for code examples that contain wildcards, and see "ADSI Scripting Primer" in this book for more information about wildcards in search filters.


The second to last part of a query that uses LDAP search dialect contains the attributes that the query should return.

Specify attributes to return by using their lDAPDisplayName. Separate each attribute by a comma, and separate the entire set of attributes from the rest of the query string by semicolons. The following code sample specifies the name, initials, sn, and mail attributes:

;name, initials, sn, mail;

Search Scope

The search scope is the last part of the query string; options for search scope are base, onelevel, or subtree:

Base. This option searches the dn specified in the search base. For example, a query for the name attribute with a search base of <GC://ou=Management,dc=NA,dc=fabrikam,dc=com> and no search filter returns the name value of the OU, Management. No child objects of the Management OU are searched.

Onelevel. This option searches the immediate children of the specified search base. For example, a query for the name attribute with a search base of <GC://ou=Management,dc=NA,dc=fabrikam,dc=com> and no search filter returns the name values of all objects in the Management OU. Any child containers in the Management OU are not searched, but the names of the child containers are included in the result set.

Subtree. This option searches the entire subtree, including the object specified in the search base. For example, a query for the name attribute with a search base of <GC://ou=Management,dc=NA,dc=fabrikam,dc=com> and no search filter returns the name values of the all objects in the Management OU and the name of the Management OU itself. All child containers in the Management OU are also searched for their name values. This is the default scope option; if you do not specify a scope option in the query, subtree is used.

note Note

  • The search scope can also be specified as a parameter of the Command objects property collection, but when LDAP search dialect is used, it is more commonly assigned as part of the CommandText property.