Table of Content > The Global Catalog > Searching Objects in the Global Catalog
Searching Objects in the Global Catalog
In the tutorial article "Searching for LDAP Directory Objects with ADO" was described how to search for directory objects in a script in general. On this page, we want to focus on LDAP search operations in the global catalog. Please remember: There is only read access to the global catalog, and only a subset of the attributes is provided there. So in our LDAP search filter, we can use only those attributes which are included in the global catalog!
Standard Search in the Global Catalog
We use a normal LDAP search operation where the LDAP path name is changed, so that the TCP-Port-Nummer 3268 is used. Additionally, we have to set another LDAP Search base - this has to be the DNS name of the root domain in your AD forest (this is the domain which was installed in the AD forest as the first domain).
So
if we have a forest with the root domain named 'cerrotorre.de', and we want to have a list of all DCs in the forest, the search would look like this:
filterStr = "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))" 'search for DCs
Set ado = CreateObject("ADODB.Connection") 'create new ADO connection
ado.Provider = "ADSDSOObject" 'use the ADSI interface
ado.Open "AD-Search" 'use any name for the connection
Set adoCmd = CreateObject("ADODB.Command") 'create new ADO command
adoCmd.ActiveConnection = ado 'assignment to an existing ADO connection
adoCmd.Properties("Page Size") = 1000 'set the Paged Results value to 1000 (AD standard)
adoCmd.Properties("Cache Results") = True
adoCmd.CommandText = "<GC://cerrotorre.de>;" & filterStr & ";ADsPath;subtree"
Set objectList = adoCmd.Execute 'perform search
While Not objectList.EOF
Set dc = GetObject(objectList.Fields("ADsPath")) 'connect to the DC objects which were found
WScript.Echo dc.dnsHostName 'output: FQDN of the DCs
objectList.MoveNext 'jump to the next search result entry
Wend
Please note that the usual LDAP base string (for example 'OU=accounts,DC=slefadsi,DC=org') is replaced by the DNS name of the root domain (here 'cerrotorre.de'). The GC needed for this search is detected automatically by internal ADSI API calls.
GC Search using special credentials
The common method of searching the directory always works when a logged
on user wants to access objects of his own domain respectively his own
Active Directory forest. However, it might quite often be necessary to access a directory
service where you are not an currently authenticated user. In that case we have to use additional search parameters for the credentials. And: The bind variation OpenDSObject allows to pass the username
and password and thus the logon to e.g. foreign forests is possible.
Set dso = GetObject("LDAP:") 'we need this later for the OpenDSObject call
userName = "DOMAIN\userXYZ" 'set your own credentials here
password = "P@ssw0rd"
filterStr = "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))" 'search for DCs
Set ado = CreateObject("ADODB.Connection") 'create new ADO connection
ado.Provider = "ADSDSOObject" 'use the ADSI interface
ado.Properties("User ID") = userName
ado.Properties("Password") = password
ado.Open "AD-Search" 'use any name for the connection
Set adoCmd = CreateObject("ADODB.Command") 'create new ADO command
adoCmd.ActiveConnection = ado 'assignment to an existing ADO connection
adoCmd.Properties("Page Size") = 1000 'set the Paged Results value to 1000 (AD standard)
adoCmd.Properties("Cache Results") = True
adoCmd.CommandText = "<GC://cerrotorre.de>;" & filterStr & ";ADsPath;subtree"
Set objectList = adoCmd.Execute 'perform search
While Not objectList.EOF
Set dc = dso.OpenDSObject(objectList.Fields("ADsPath"), userName, password, 1) 'connect to the DCs which were found
WScript.Echo dc.dnsHostName 'output :FQDN of the DCs
objectList.MoveNext 'jump to the next search result entry
Wend
In this example the search returns the distinguished names of all domain controllers in the forest. We connect to them with an OpenDSObject call, the last parameter (1) acts as a logon-flag,
ensuring a secure Kerberos logon.
Prerequisite is, of course, that the station where you start this script can resolve the domain name of the forest root domain ('cerrotorre.de' in this example) to an IP address of an DC in this domain. Using the SRV records stored in the DNS, a global catalog server can be detected with internal ADSI API functions.
GC Search over LDAP SSL
You can also use LDAP-SSL to search the global catalog. Simply use the TCP-Port-Nummer 3269 (instead of 3268) to initiate the connection. However, this is working only if a valid SSL certificate was installed on the server before.
The example demonstrate how to search for all disabled user accounts in the forest over an SSL search operation:
filterStr = "(&(sAMAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=2))" 'search for disabled accounts
Set ado = CreateObject("ADODB.Connection") 'create new ADO connection
ado.Provider = "ADSDSOObject" 'use the ADSI interface
ado.Open "AD-Search" 'use any name for the connection
Set adoCmd = CreateObject("ADODB.Command") 'create new ADO command
adoCmd.ActiveConnection = ado 'assignment to an existing ADO connection
adoCmd.Properties("Page Size") = 1000 'set the Paged Results value to 1000 (AD standard)
adoCmd.Properties("Cache Results") = True
adoCmd.CommandText = "<LDAP://cerrotorre.de:3269>;" & filterStr & ";ADsPath;subtree"
Set objectList = adoCmd.Execute 'perform search
While Not objectList.EOF
Set user = GetObject(objectList.Fields("ADsPath")) 'connect to the user objects which were found
WScript.Echo user.sAMAccountName & vbcrlf & " " & user.distinguishedName 'output: show the disabled users
objectList.MoveNext 'jump to the next search result entry
Wend
GC Search when the own domain name / forest
is unknown
In many cases you want to develop scripts that run in different Active Directory environments.
Think about a script that e.g. displays any information about certain objects
within the own domain or is responsible for specific changes. In order
that this script runs in any domains, you could let pass the domain name
as parameter. But it is more sophisticated to automatically identify the
current domain name by querying the Active Directory itself through severless
binding.
The relevant information can be read in a special directory entry, available
on every domain controller: the rootDSE (Root
Directory Service Entry).
So this is an example to search for all disabled user accounts in the forest where the script is launched:
Set aoi = CreateObject("ADSystemInfo")
rootDNS = aoi.ForestDNSName
filterStr = "(&(sAMAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=2))" 'search for disabled accounts
Set ado = CreateObject("ADODB.Connection") 'create new ADO connection
ado.Provider = "ADSDSOObject" 'use the ADSI interface
ado.Open "AD-Search" 'use any name for the connection
Set adoCmd = CreateObject("ADODB.Command") 'create new ADO command
adoCmd.ActiveConnection = ado 'assignment to an existing ADO connection
adoCmd.Properties("Page Size") = 1000 'set the Paged Results value to 1000 (AD standard)
adoCmd.Properties("Cache Results") = True
adoCmd.CommandText = "<GC://" & rootDNS & ">;" & filterStr & ";ADsPath;subtree"
Set objectList = adoCmd.Execute 'perform search
While Not objectList.EOF
Set user = GetObject(objectList.Fields("ADsPath")) 'connect to the user objects which were found
WScript.Echo user.sAMAccountName & vbcrlf & " " & user.distinguishedName 'output: show the disabled users
objectList.MoveNext 'jump to the next search result entry
Wend