26.7 Querying AD with WMI

Up to now, we've shown how WMI can be a powerful resource to aid in managing components of individual computers. You may be wondering what impact WMI will have on Active Directory? It can, in fact, play as big a role in automating the management of Active Directory as you want. Also, over time, WMI's importance with respect to monitoring Active Directory will continue to grow as Microsoft develops new providers.

First we are going to review how you can use WMI and the Active Directory provider to access and query objects in Active Directory. We will then cover some specific WMI providers that Microsoft has made available in Windows Server 2003; these providers help you monitor certain aspects of Active Directory, such as trusts and replication. In the next chapter, we will cover the WMI DNS provider and how you can manage Microsoft DNS servers with it. To start with, let's look at the Active Directory provider.

The Active Directory provider uses the root\directory\ldap namespace. Within that namespace, every Active Directory schema class and attribute is mapped to corresponding WMI classes or properties. Each abstract class (e.g., top) is mapped to a WMI class with "ds_" prefixed on the name. Each nonabstract class (e.g., structural and auxiliary) is mapped to two classes. One has "ads_" prefixed, and the other has "ds_" prefixed. The "ads_" classes conform to the class hierarchy defined by the subClassOf attribute for each class. The "ds_" classes for nonabstract (e.g., structural) classes are descendants of their cooresponding "ads_" class. Perhaps an example would help illustrate this hierarchy:


In this example, we showed the class hierarchy for the Active Directory "computer" object class as it is mapped to WMI. The attribute mappings are more straightforward. Each Active Directory attribute has a corresponding property in WMI with "ds_" prefixed. So the description attribute would map to the ds_description property in WMI. An additional property was added called ADSIPath, which is the ADsPath, and is the key for each Active Directory object in WMI. We highly recommend installing and using the WMI CIM Studio to browse the root\directory\ldap namespace. The organization of classes and objects will become apparent.

We can use the techniques shown so far to query and manipulate Active Directory objects. We can retrieve all the instances of a particular Active Directory class (via InstancesOf) or perform WQL query based on certain criteria. In the following example, we search for all user objects that have a last name equal to "Allen".

strComputer = "."
Set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\directory\LDAP")
Set objUsers = objWMI.ExecQuery("SELECT * FROM ds_user where ds_sn = 'Allen' ")
if objUsers.Count = 0 then
   Wscript.Echo "No matching objects found"
   for each objUser in objUsers
      WScript.Echo "First Name: " & objUser.ds_givenName
      WScript.Echo "Last Name: " & objUser.ds_sn
      WScript.Echo ""
end if

Since WMI is typically used to manage computers, we can leverage Active Directory as a repository of computer objects and perform certain functions on a set of computers that match our criteria. In the next code sample, we do a WQL query for all computers that are running "Windows Server 2003", connect to each one, and print the date each machine was last rebooted.

on error resume next
strComputer = "."
Set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\directory\LDAP")
Set objComps = objWMI.ExecQuery("SELECT * FROM ds_computer " & _
                            "where ds_OperatingSystem = 'Windows Server 2003' ")
if objComps.Count = 0 then
   Wscript.Echo "No matching objects found"
   for each objComp in objComps
      WScript.Echo objComp.ds_name
      Set objRemoteWMI = GetObject("winmgmts:\\" & objComp.ds_name & "\root\cimv2")
      if Err <> 0 then
         WScript.Echo "  Could not connect"
         ' Perform whatever functions necessary on objRemoteWMI
         Set objOSes = objRemoteWMI.InstancesOf("Win32_OperatingSystem")
         for each objOS in objOSes
            strTime = objOS.LastBootUpTime
            strYear = Left(strTime, 4) 
            strMon = Mid(strTime, 5, 2) 
            strDay = Mid(strTime, 7, 2) 
            WScript.Echo "  Last Reboot: " & strYear & "/" & strMon & "/" & strDay
      end if
      WScript.Echo ""
      Set objRemoteWMI = Nothing
end if

In the code, we retrieve each matching computer object and then construct a WMI moniker to connect to that machine. From there, we enumerate the Win32_OperatingSystem object and print out the LastBootUpTime property. Note that we could perform essentially any function we want, including querying disks and the event log, modifying the registry, and so on. Also, we could instantiate a WbemScripting.SWbemLocator object if we need to log on to the computers with alternate credentials other than those the script is running under.

    Part II: Designing an Active Directory Infrastructure
    Part III: Scripting Active Directory with ADSI, ADO, and WMI