Managing Windows trusts has always been difficult, despite the tools (e.g., nltest.exe) that the Windows resource kits provide to verify that trusts are in place. Windows Server 2003, however, exposes trust information through the new Trustmon Windows Management Instrumentation (WMI) provider. Thus, any WMI consumer application—such as a Windows Script Host (WSH) script, Windows .NET Framework application, or enterprise-management software product—can exploit the Trustmon classes to retrieve information about existing trusts. You can also use WMI Query Language (WQL) event queries to monitor trusts and trigger alerts.
The Trustmon Provider
The Trustmon WMI provider supports three WMI classes in the root\microsoftactivedirectory namespace: Microsoft_TrustProvider, Microsoft_DomainTrustStatus, and Microsoft_LocalDomainInfo. These three classes expose information about the trust relationships between domains.
Microsoft_TrustProvider is a singleton class that includes properties that control how the Microsoft_DomainTrustStatus class will enumerate the status of domain trusts. (A singleton class has only one instance of the managed object it represents on the examined system. For example, the Win32_WMISetting WMI class is a singleton class because a Windows system has only one instance of the WMI settings.) The Trustmon provider verifies trusts during the enumeration of the Microsoft_DomainTrustStatus class according to the parameters specified in the Microsoft_TrustProvider instance. The Microsoft_LocalDomainInfo class, also a singleton class, gathers information about the local domain.
For more information about the Trustmon provider, its classes, and their properties, go to "Trustmon Provider" (http://msdn.microsoft.com/library/en-us/wmisdk/wmi /trustmon_provider.asp). For more information about trusts, see "Windows 2003 Forest Trusts," May 2003, http://www.winnetmag.com/windows security, InstantDoc ID 38436.
The WMITrust Script
I've written a script, WMITrust.wsf, that uses the Trustmon provider classes to let a Windows 2003 administrator manage trusts from the command line. In addition to being a management tool, the script illustrates the scripting techniques required to use the Trustmon classes. The script uses command-line parameters that match the Trustmon classes' capabilities. Note that none of the classes expose any WMI methods, so the script leverages only properties at the command line. I don't have room to show the entire WMITrust script here, but you can download it at http://www.winnetmag.com/windowsscripting, InstantDoc ID 41196.
During WMITrust's initialization phase, the script references three VBScript files that contain helper functions. DecodeTrustsFunction.vbs contains three functions that decipher Microsoft_DomainTrustStatus class property values:
- DecodeTrustsFunction() decodes the TrustDirection property.
- DecodeTrustType() decodes the TrustType property.
- DecodeTrustAttributes() decodes the TrustAttributes property.
DisplayFormattedPropertyFunction.vbs contains the DisplayFormattedProperty() function, which displays the WMI information on screen. TinyErrorHandler.vbs contains the ErrorHandler() function, which handles execution errors. You can download the three VBScript files along with WMITrust.
During this initialization phase, the script also creates an SWbemLocator object to execute the WMI connection and an SWbemDateTime object to manipulate properties that contain a date and time value. (For more information about these objects, see "SWbemLocator" at http://msdn.microsoft.com/library/en-us/wmisdk/wmi/swbemlocator.asp and "SWbemDateTime" at http://msdn.microsoft.com/library/en-us/wmisdk/wmi/swbemdatetime.asp.) The script then defines some constants for the default computer and WMI namespace before parsing the command line with the WSH 5.6 XML parsing technique that I describe in "Secure Script Execution with WSH 5.6," August 2002, http://www.winnetmag.com/windowsscripting, InstantDoc ID 25644.
After initialization, WMITrust connects to WMI locally or remotely. Note that you must connect to a domain controller (DC) because only DCs handle the trust relationships between domains. To run the script remotely, you must use the /Machine switch to specify the name of the remote DC and the /User and /Password switches to specify credentials; for example
WMITrust /DomainInfo+ /Machine:MyRemoteDC /User:ALissoir /Password:MyPassword
When you run WMITrust with the /DomainInfo+ parameter, the script retrieves information about the local domain. Figure 1 shows the output I received when I started the script with the /DomainInfo+ parameter in the LissWare.Net domain. You can see the name of the DC used for the WMI connection (DCname property), the domain DNS name (DNSname property), and the Forest Tree name (TreeName property).
Requesting the domain information also shows the Microsoft_TrustProvider instance's property values. The TrustListLifetime property defines the time in minutes to cache the last trust enumeration. (The default value is 20.) The TrustStatusLifetime property defines the time in minutes to cache the last request for the trust status. (The default value is 3.) The TrustCheckLevel property lets you set one of four types of enumeration to use when enumerating domains. (The default value is 1.) The ReturnAll Boolean property determines whether the browse operation returns both the trusting domains and the trusted domains (True, the default value) or just the trusted domains (False).
Callout A in Listing 1 shows the code that produces the Figure 1 output. The script gets the Microsoft_LocalDomainInfo and Microsoft_TrustProvider instances. Singleton class instances are always retrieved by using the at (@) character. Then, the script uses two For Each loops (one for each instance) to enumerate and display the class property values.
Figure 2, page 14, shows that the LissWare.Net domain has two trust relationships: an intraforest transitive trust with the Emea.LissWare.Net domain and an interforest trust with the ForeignForest.Com domain. In the latter trust relationship, LissWare.Net is the trusted (aka account) forest and ForeignForest.Com is the trusting (aka resource) forest. If I run WMITrust with the /Check switch on a DC in the LissWare.Net domain, I see the results that Figure 3 shows. Note that the script lists all LissWare.Net domain trusts. You can see that the LissWare.Net domain has a bidirectional trust with the Emea.LissWare.Net domain and an inbound trust with the ForeignForest.Com domain.
When you use the /Check switch, you can also update the Microsoft_
TrustProvider instance property values by using the /StatusLifeTime switch (which updates the TrustStatusLifetime property), the /ListLifeTime switch (which updates the TrustListLifetime property), and the /TrustedOnly switch (which updates the ReturnAll property). A sample command is
WMITrust /Check:EnumOnly /StatusLifeTime:6 /ListLifeTime:40 /TrustedOnly-
After changing the values, you must restart the WMI service if you want the new values to take effect immediately.
The code at callout B in Listing 1 handles the Microsoft_TrustProvider class. The script first retrieves the Microsoft_TrustProvider singleton class instance. If you specified on the command line any of the switches that update Microsoft_TrustProvider, the script assigns the specified values to the respective Microsoft_TrustProvider properties. If you turned on the /TrustedOnly switch (/TrustedOnly+), a logical Not operation sets the Return- All property to False to tell the WMI provider to return only the trusted domains (and not the trusting domains). Next, the script saves the Microsoft_TrustProvider instance back to the system by using the Put_ method exposed by the SWbemObject object that represents the Microsoft_TrustProvider instance. (For more information about the SWbemObject object, see "SWbemObject" at http://msdn.microsoft.com/library/en-us/wmisdk/wmi/swbemobject.asp.)
After the update process, the code at callout C enumerates the list of trusts. To do so, the script retrieves a collection of Microsoft_DomainTrustStatus class instances. If the collection contains at least one instance, the script enumerates and displays the instance's properties. A Select Case statement handles the necessary decoding functions based on the property name.
Monitoring Windows 2003 Trusts
The WMITrust script retrieves information about trusts and can change the Trustmon provider properties, but it doesn't monitor trust status. To detect a trust status change, you can use a WQL event query such as
Select * FROM __InstanceModificationEvent Within 5 Where TargetInstance ISA 'Microsoft_DomainTrustStatus'
To submit this query, you can use GenericEventAsyncConsumer.wsf, a script that I wrote expressly for the purpose of submitting such queries. For more information about how GenericEventAsyncConsumer submits an event query, see "Exchange 2000 SP2 WMI Updates," January 2003, http://www.winnetmag.com/microsoftexchangeoutlook, InstantDoc ID 27211. With the help of this script, a WQL event query detecting a trust status change would generate the output that Figure 4 shows. (I've edited the output to show only the relevant information.) GenericEventAsyncConsumer displays the Microsoft_DomainTrustStatus instance before and after a DC had disappeared because of a shutdown or crash. The second set of TrustIsOk, TrustStatus, and TrustStatusString property values show that the trust is broken.
Windows 2003 dramatically improves the OS's management capabilities, including bumping up the number of WMI providers to 80 (from 29 in Windows 2000 Server). The Trustmon WMI provider is just one of these providers, but it's an important one. Windows 2003 has new trust features to support multiforest environments, making it a key area to manage, and the new ability to monitor trusts is a great asset for systems administrators.