3.6 Active Directory components providers


3.6 Active Directory components providers

3.6.1 Active Directory Service providers

There are three Active Directory providers, as shown in Table 3.49.

Table 3.49: The Active Directory Providers Capabilities

Provider Name

to Provider Namespace

Class Provider

Instance Provider

Method Provider

Property Provider

Event Provider

Event Consumer Provider

Support Get

Support Put

Support Enumeration

Support Delete

Windows Server 2003

Windows XP

Windows 2000 Server

Windows 2000 Professional

Windows NT 4.0

Active Directory LDAP Providers

Microsoft|DSLDAPCIassAssociafionsProvider|V1.0

Root/directory/LDAP

X

X

X

X

X

X

X

Microsoft|DSLDAPCIassProvider|V1.0

Root/directory/LDAP

X

X

X

X

X

X

X

Microsoft|DSLDAPInstanceProvider|V1.0

Root/directory/LDAP

X

X

X

X

X

X

X

X

X

To work with these providers, it is best to have an understanding of the Active Directory Schema, since WMI reflects its logical structure. All classes provided by the Active Directory class provider are mapped from the Active Directory schema classes. By accessing the Root\Directory\LDAP namespace, it is possible to reference any class and object in the Active Directory. Basically, we can say that the Active Directory providers mirror classes and instances from the Active Directory into this specific CIM repository namespace. To perform this mapping, the Active Directory Service providers follow naming rules to preserve the relationships that exist between the Active Directory classes and instances. Two mappings are realized: one for the Active Directory classes and one for the Active Directory instances.

Let's take the Active Directory user class as an example. Defined in the Active Directory schema, the Active Directory user class is created from a class hierarchy starting from a Root class called top (see Figure 3.26, on the left side). To obtain the user class, several subclasses are created. This creation is called a derivation of classes, where the parent class is called a superclass. First, the top class is derived to obtain the person class. Next, the person class is derived to obtain the organizationalPerson class, which is in turn also derived to obtain the user class. Each class brings its set of Active Directory attributes. Each subclass inherits the set of attributes from the superclasses.

click to expand
Figure 3.26: The Active Directory WMI classes mapped to the Active Directory classes.

In Active Directory, the user class is defined as a structural class, which allows the creation of user instances from it. However, the top, person, and organizationalPerson classes are abstract classes in Active Directory and are used as parent templates to create their respective subclasses. As mentioned previously, classes in Active Directory are mapped to their equivalent WMI classes in the Root\Directory\LDAP namespace. In case of an abstract class, the WMI equivalent abstract class always uses the LDAP display name of the Active Directory class starting with the "ds_" prefix (Figure 3.26, on the right side). For example, for the Active Directory organizationalPerson class, we will have a corresponding ds_organizationalPerson WMI class. Since this Active Directory class is an abstract class, the WMI equivalent class is also an abstract class and has the abstract WMI qualifier set. When the Active Directory class is a non-abstract class (such as the user class, which is a structural class), the mapping is made to two WMI classes:

  • A first class prefixed with the "ads_" prefix and implemented as a WMI abstract class (abstract qualifier is set). For the user class, we will have an ads_user WMI abstract class.

  • A second class prefixed with the "ds_" prefix and implemented as a WMI dynamic instance class (provider qualifier is set). For the user class, we will have a ds_user WMI dynamic instance class.

In both Figures 3.27 and 3.28, you will notice the presence of other qualifiers representing Active Directory attributes defined in the schema and used to create the user class definition (i.e., governsID, objectClassCategory, IDAPDisplayName, etc.). In the same way, the syntax used by Active Directory is also mapped to WMI. Table 3.50 shows the syntax mapping.

Table 3.50: The Active Directory/WMI Syntax Mapping

Active Directory syntax

WMI data type

WMI property value

Access-Point

CIM_STRING

Mapped from the value of the string.

Boolean

CIM_BOOLEAN

Mapped directly to the appropriate Boolean value.

Case Insensitive String

CIM_STRING

Mapped from the value of the string.

Case Sensitive String

CIM_STRING

Mapped from the value of the string.

Distinguished Name

CIM_STRING

Mapped from the value of the string.

DN-Binary

Embedded object of class DN_With_Binary

Mapped to instances of the DN With Binary class.

DN-String

Embedded object of class DN_With_String

Mapped to instances of the DN_With_String class.

Enumeration

CIM_SINT32

Mapped directly to the integervalue.

IA5-String

CIM_STRING

Mapped from the value of the string.

Integer

CIM_SINT32

Mapped directly to the integer value.

NT Security Descriptor

Embedded object of Class Uint8Array

Mapped to instances of the Uint8Array class.

Numeric String

CIM_STRING

Mapped from the value of the string.

Object Id

CIM_STRING

Mapped from the string representation of the OID; for example, "1.3.3.4."

Octet String

Embedded object of Class Uint8Array

Mapped to instances of the Uint8Array class.

OR Name

CIM_STRING

Mapped from the value of the string.

Presentation-Address

CIM_STRING

Mapped from the value of the string.

Print Case String

CIM_STRING

Mapped from the value of the string.

Replica Link

Embedded object of class Uint8Array

Mapped to instances of the Uint8Array class..

SID

Embedded object of Class Uint8Array

Mapped to instances of the Uint8Array class.

Time

CIM_DATETIME

Converted to the CIM_DATETIME representation and mapped.

Undefined

N/A

N/A

Unicode String

CIM_STRING

Mapped from the value of the string.

UTC Coded Time

CIM_DATETIME

Converted to the CIM_DATETIME representation and mapped.

click to expand
Figure 3.27: The WMI ads_user abstract class qualifiers.

click to expand
Figure 3.28: The WMI ds_user dynamic instance class qualifiers.

The end result is that WMI exposes Active Directory classes as WMI classes (see Figure 3.29).

click to expand
Figure 3.29: Some of the Active Directory classes as seen from WMI.

When a user object is created in Active Directory, it is always created in a container. The default container for user objects is the "Users" container, but it could be any other supported container, such as an organizational unit or a domain. In the Active Directory schema, the containers that can hold user objects are defined with the possSuperiors and systemPossSuperiors attributes of the Active Directory user class definition. These attributes reference the class (with their names) representing the supported containers—for example, the domainDNS class for the domain container or the builtinDomain class for the Users container. We see here that there is a relationship between the user class and the supported Active Directory container class definition. WMI represents this relationship with the DS_LDAP_Class_Containment association class (see Figure 3.30).

click to expand
Figure 3.30: The DS_LDAP_Class_Containment associations.

In the same way, once user objects are instantiated, they are contained in an existing container. We will retrieve the same kind of relationship between the user objects and the containers but at the instance level instead of the class level. WMI represents this relation with the use of the DS_LDAP_Instance_Containment association class. (See Figure 3.31.)

click to expand
Figure 3.31: The DS_LDAP_Instance_Containment associations.

These two association classes, along with the RootDSE WMI class, are listed in Table 3.51. The RootDSE WMI class represents the RootDSE LDAP object available from any LDAP v3 directory.

Table 3.51: The Active Directory Providers Classes

Name

Type

Comments

DS_LDAP_Class_Containment

Association

This class models the possible superiors of a DS class.

DS_LDAP_Instance_Containment

Association

This class models the parent-child container relationship of instances in the DS.

RootDSE

Dynamic

This is the class used to model the LDAP RootDSE object.

Every WMI instance representing an Active Directory object uses the Active Directory ADSI path of the object. The ADSI path is represented in the WMI class definition with the ADSIPath WMI Key property. For example, the ADSIPath property for a user object called "LISSOIR Alain" and located in the "Users" containers of an Active Directory domain called LissWare.Net will be:

 LDAP://CN=LISSOIR Alain,CN=Users,DC=LissWare,DC=Net 

There is one exception for the RootDSE WMI class, since it provides information about the capabilities of an LDAP server. This WMI class is a singleton class, since the RootDSE LDAP object is unique per LDAP server.

Everything we said about the user class and its WMI equivalents ads_user and ds_user WMI classes can be applied to any other class defined in the Active Directory schema. The logic is always the same. This is why a good understanding of the Active Directory schema mechanisms and definitions is helpful to navigate the WMI representation.

As seen in Table 3.49, the Microsoft|DSLDAPInstanceProvider|V1.0 supports the "Get," "Put," "Enumeration," and "Delete" operations. This clearly means that we can manipulate Active Directory object instances through WMI. With the previous script samples, we have seen how to create, update, and delete existing WMI instances. To manipulate the WMI Active Directory object instances there are no exceptions; the rules and the scripting techniques are exactly the same. However, because the Microsoft|DSLDAPClassProvider|V1.0 only supports "Get" and "Enumeration" operations, it is not possible to create new classes in Active Directory with WMI. Therefore, it means we must create all Active Directory schema extensions with the Active Directory Service Interfaces (ADSI).

3.6.1.1 Creating and updating objects in Active Directory

Although technically feasible with WMI to create, update, or delete Active Directory object instances, it is more efficient to use ADSI to perform these typical operations. As a basic example, we can create an Active Directory user with WMI, as illustrated in Sample 3.53.

Sample 3.53: Creating an Active Directory user object with WMI

start example

  1:<?xml version="1.0"?>  .:  8:<package>  9:  <job> 13:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\TinyErrorHandler.vbs" /> 14: 15:    <object prog  reference="true"/> 16:    <object prog  /> 17: 18:    <script language="VBscript"> 19:    <![CDATA[ 23:    Const cUserID = "WMIUser" 24:    Const cComputerName = "LocalHost" 25:    Const cWMINameSpace = "Root/directory/LDAP" 26:    Const cWMIClass = "ds_user" 27: 28:    Const ADS_UF_ACCOUNTDISABLE = &h000002 36:    objWMILocator.Security_.AuthenticationLevel = wbemAuthenticationLevelDefault 37:    objWMILocator.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate 38:    Set objWMIServices = objWMILocator.ConnectServer(cComputerName, cWMINameSpace, "", "") 41:    Set objWMIClass = objWMIServices.Get (cWMIClass) 44:    Set objWMIInstance = objWMIClass.SpawnInstance_ 45: 46:    objWMIInstance.DS_sAMAccountName = cUserID 47:    objWMIInstance.ADSIPath = "LDAP://CN=" & cUserID & '',CN=Users,DC=LissWare,DC=Net" 48: 49:    objWMIInstance.Put_   (wbemChangeFlagCreateOrUpdate Or wbemFlagReturnWhenComplete) 52:    WScript.Echo ''Active Directory user  successfully  created." 53: 54:    objWMIInstance.Refresh_ 55: 56:    objWMINamedValueSet.Add "__PUT_EXTENSIONS", True 57:    objWMINamedValueSet.Add "__PUT_EXT_CLIENT_REQUEST", True 58:    ObjWMINamedValueSet.Add "_PUT_EXT_PROPERTIES", Array ("DS_userAccountControl", _ 59:                                                          "DS_description") 60: 61:    objWMIInstance.DS_userAccountControl = objWMIInstance.DS_userAccountControl And _ 62:                                           (NOT ADS_UF_ACCOUNTDISABLE) 63:    objWMIInstance.DS_description = Array ("Active Directory user created with WMI.") 64: 65:    objWMIInstance.Put_ wbemChangeFlagUpdateOnly Or wbemFlagReturnWhenComplete,   _ 66:                        objWMINamedValueSet ..: 69:    WScript.Echo ''Active Directory user successfully updated." ..: 75:    ]]> 76:    </script> 77:  </job> 78:</package> 

end example

The technique to create a user instance in Active Directory with WMI is the same as any other instance creation. However, to completely demonstrate the instance creation and update techniques, Sample 3.53 is divided into two parts:

  • The first part (lines 41 through 52) creates the WMI instance representing the Active Directory user object. As with any other instance creation, the code creates a new instance of the desired class (lines 41 and 44). Next, it assigns various properties required to create the new Active Directory user instance (lines 46 and 47). Although the ADSIPath property is mandatory to create the new instance (since Adsipath is defined as a Key property of the DS_user WMI class in the CIM repository), the DS_sAMAccountName property is not required by WMI to create the new user instance. This may look amazing, since it is a mandatory attribute of the Active Directory user class, but, actually, if the DS_sAMAccountName value assignment is missing in the script, WMI generates a random value for it, as shown in Figure 3.32.


    Figure 3.32: An Active Directory user created with WMI.

  • The second part (lines 54 through 69) updates the previously created Active Directory user object. To update the existing Active Directory user, the script refreshes the instance information in order to get the latest information available from Active Directory (line 54), since some attributes are updated during the object creation (i.e., modify-TimeStamp, userAccountControl, objectGUID, objectSID, etc.). Under Windows 2000, since the Refresh_ method is not available from an SWBemObject object, it is necessary to retrieve the created instance instead. Next, Sample 3.53 initializes an SWBemNamedValueSet object to perform a partial-instance update (lines 56 through 59). This partial-instance update updates two specific Active Directory attributes: the userAccountControl attribute (to enable the user object, since by default newly created users in Active Directory are disabled) and the description attribute (lines 61 through 63). The partial-instance update is mandatory, because saving the complete instance back to Active Directory will attempt to set some attributes that can only be set by the system, which means that the WMI call will fail to update the existing user object (lines 65 and 66). Once completed, the updated attributes are committed back by WMI to Active Directory.

The end result is the creation of an enabled Active Directory user with a specific description. Note that it is possible to commit the description attribute during the user creation (during the first part of the script). However, to enable the user, it is always necessary to create the user first and change its state by modifying the userAccountControl attribute next.

Although an Active Directory user creation is possible with WMI, it is clear that the ADSI scripting technique is more suitable for this type of task. However, there are situations where it could be useful to use the WMI technique to update a WMI instance representing an Active Directory object. As an example, this could be the case during WMI events notifying Active Directory objects creation. Once a user is created, WMI could detect its creation with a WQL event query and update the created Active Directory object with some information coming from a database (i.e., telephone-Number, postalAddress, etc.). In such a case, the WQL query would be as follows:

  1:   C:\>GenericEventAsyncConsumer.wsf "Select * From __InstanceCreationEvent Within 5                               Where TargetInstance ISA 'DS_user'" /NameSpace:Root\Directory\LDAP  2: Microsoft (R) Windows Script Host Version 5.6  3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. 4:  5:   Waiting for events...  6:  7:   BEGIN - OnObjectReady.  8:   Tuesday, 11 June, 2002 at 15:47:04: '__InstanceCreationEvent has been triggered.  9:     SECURITY_DESCRIPTOR (wbemCimtypeUint8) = (null) 10:     TargetInstance (wbemCimtypeObject) 11:       *ADSIPath (wbemCimtypeString) = LDAP://CN=Alain LISSOIR,CN=Users,DC=LissWare,DC=NET 12:       DS_accountExpires (wbemCimtypeSint64) = 9223372036854775807 ..: 33:       DS_badPasswordTime (wbemCimtypeSint64) = 0 34:       DS_badPwdCount (wbemCimtypeSint32) = 0 ..: 41:       DS_cn (wbemCimtypeString) = Alain LISSOIR ..: 62:       DS_displayName (wbemCimtypeString) = Alain LISSOIR 63:       DS_displayNamePrintable (wbemCimtypeString) = (null) 64:       DS_distinguishedName (wbemCimtypeString) = CN=Alain LISSOIR,CN=Users,DC=LissWare,DC=NET 65:       DS_division (wbemCimtypeString) = (null) 66:       DS_dLMemDefault (wbemCimtypeSint32) = (null) 67:       DS_dLMemRejectPerms (wbemCimtypeString) = (null) 68:       DS_dLMemRejectPermsBL (wbemCimtypeString) = (null) 69:       DS_dLMemSubmitPerms (wbemCimtypeString) = (null) 70:       DS_dLMemSubmitPermsBL (wbemCimtypeString) = (null) ..: ..: ..: 

3.6.1.2 Searching in Active Directory

To query Active Directory via LDAP, four key elements are required to formulate the query:

  • The base object in which the search will start: This could be an object container in the Active Directory, such as an organizationalUnit

     OU=Brussels,DC=LissWare,DC=Net 

    or a naming context, such as the defaultNamingContext, SchemaNamingContext.

     CN=Configuration,DC=LissWare,DC=Net CN=Schema,CN=Configuration,DC=LissWare,DC=Net 

  • The filter determines which elements have to be selected (based on conditions) from the Active Directory. Any accessible characteristics of an object can be used to make a query. Some examples are:

     (|(objectClass=domainDNS)(objectClass=organizationalUnit)) 

    This will return the list of all objects using the class domainDNS or organizationalUnit. Note the "|" sign for the "or" statement.

     (&(objectClass=user)(objectCategory=person)) 

    This will return the list of all objects using the class user for which the objectCategory is equal to person. Actually, this will provide a list of all users available in the selected naming context. In this example, the objects of the class contact will be discarded, even if they are also using an objectCategory equal to person. Note the "&" sign for the "And" statement. To get both contact and user objects, the following syntax can be used:

     (&(|(objectClass=user)(objectClass=contact))(objectCategory=person)) 

    or, to make things simpler (because an object class user or contact is an object category equal to person), use:

     (objectCategory=person) 

    In the first version note the possibility to combine search conditions "|" and "&."

  • The attributes of the retrieved objects that are required. This can be any attribute associated with the retrieved objects (cn, name, given-Name, sn, etc.).

  • How deep the search has to run in the Active Directory.

    Base:

    A Base search is limited to the base object selected. If the base object has children, they will not be included in the search. Only elements that are direct members of the base object are examined.

    OneLevel:

    A OneLevel search is restricted to the immediate children of a base object but excludes the base object itself. This scope is perfectly adapted for a search inside the schemaNamingContext.

    SubTree:

    A SubTree search includes the entire subtree below the base object.

To locate users residing in the Organizational Unit called "Brussels," having a first name (givenName) equal to "Alain," the following LDAP query filter must be used:

 (&(objectclass=user)(givenName=Alain)) 

with the following base search:

 OU=Brussels,DC=LissWare,DC=Net 

and the following search level:

 OneLevel 

This LDAP query operation can be executed with the LDP.Exe utility available from the Windows 2000 or Windows Server 2003 Support Tools. The query result can be seen in Figure 3.33.

click to expand
Figure 3.33: Querying Active Directory with LDAP from LDP.

Because WMI is connected to Active Directory, it is possible to obtain a similar result with a WQL data query:

 Select * From DS_user Where DS_givenName='Alain' 

However, there is no way to specify a base search. In this case, the search will be executed from the top of the domain tree (DC=LissWare,DC=Net). If a search must be performed in a context other than the Active Directory domain context (i.e., Configuration context), a DN_Class instance must be created. We will examine this technique later in this book, when monitoring the FSMO roles (see Sample 3.55, "Making the Configuration and Schema context accessible").

3.6.1.3 Monitoring Active Directory group memberships

Everybody knows the importance of Active Directory group memberships, right? It is clear that some Active Directory groups are more sensitive than others from a security point of view. For example, you wouldn't want to see just anyone added to the "Enterprise Admins" group without appropriate control, would you? No, of course you wouldn't! Well, with the Active Directory provider and a WQL event query, it is possible to get a WMI event notification when a modification is made to a group or any other object of Active Directory. The WQL event query to use should be as follows:

 Select * From _InstanceModificationEvent Within 10 Where TargetInstance ISA 'ds_group' AND                                                          Target Instance.ds_name='Enterprise Admins' 

Directly inspired from Samples 6.18 through 6.21 ("Monitoring, managing, and alerting script for the Windows services") in the appendix, Sample 3.54 is an immediate application of this WQL Event query example.

Sample 3.54: Monitoring, managing, and alerting script for the Windows Group modifications

start example

   1:<?xml version="1.0"?>   .:   8:<package>   9:  <job>  ..:  13:    <runtime>  ..:  18:    </runtime>  19:  20:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\TinyErrorHandler.vbs" />  21    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\PauseScript.vbs" />  22:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\GenerateHTML.vbs" />  23:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\SendMessageExtendedFunction.vbs" />  24:  25:    <object progobjWMILocator'' reference="true''/>  26:    <object progobjWMIInstanceSinkContext''/>  27:    <object progobjWMIDateTime'' />  28:  29:    <script language="VBscript">  30:    <![CDATA[  ..:  34:    ' ----------------------------------------------------------------------------------------  35:    Const cComputerName = "LocalHost"  36:    Const cWMINameSpace = "Root/Directory/LDAP''  37:    Const cWMIQuery = "Select * From __InstanceModificationEvent Within 10                                                             Where TargetInstance ISA 'ds_group' "  38:  39:    Const cTargetRecipient = "Alain.Lissoir@LissWare.Net''  40:    Const cSourceRecipient = "WMISystem@LissWare.Net"  41:  42:    Const cSMTPServer = "10.10.10.3"  43:    Const cSMTPPort = 25  44:    Const cSMTPAccountName = ""  45:    Const cSMTPSendEmailAddress = ""  46:    Const cSMTPAuthenticate = 0' 0=Anonymous, 1=Basic, 2=NTLM  47:    Const cSMTPUserName = ""  48:    Const cSMTPPassword = ""  49:    Const cSMTPSSL = False  50:    Const cSMTPSendUsing = 2            ' 1=Pickup, 2=Port, 3=Exchange WebDAV  ..:  67:    '----------------------------------------------------------------------------------------  68:    ' Parse the command line parameters  69:    If WScript.Arguments.Unnamed.Count = 0 Then  70:       WScript.Arguments.ShowUsage()  71:       WScript.Quit  72:    Else  73:       For intIndice = 0 To WScript.Arguments.Unnamed.Count - 1  74:           ReDim Preserve strGroupName(intIndice)  75:           strGroupName(intIndice) = Ucase (WScript.Arguments.Unnamed.Item(intIndice))  76:       Next  77:    End If  78:  79:    strUserID = WScript.Arguments.Named("User")  80:    If Len(strUserID) = 0 Then StrUserID = ""  81:  82:    strPassword = WScript.Arguments.Named("strPassword")  83:    If Len(strPassword) = 0 Then strPassword = ""  84:  85:    strComputerName = WScript.Arguments.Named("Machine")  86:    If Len(strComputerName) = 0 Then StrComputerName = cComputerName  87:  88:    Set objWMISink = WScript.CreateObject ("WbemScripting.SWbemSink", "SINK_")  89:  90:    objWMILocator.Security_.AuthenticationLevel = wbemAuthenticationLevelDefault  91:    objWMILocator.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate  92:    Set objWMIServices = objWMILocator.ConnectServer(strComputerName, cWMINameSpace, _  93:                                                     strUserID, strPassword)  ..:  96:    For intIndice = 0 To UBound (strGroupName)  97:        If Len(strWMIQuery) = 0 Then  98:           strWMIQuery = "TargetInstance.ds_name='" & StrGroupName(intIndice) & "''  99:        Else 100:           strWMIQuery = strWMIQuery & " Or " & _ 101:                         "TargetInstance.ds_name='" & _ 102:                         strGroupName(intIndice) & "'" 103:       End If 104: 105:       WScript.Echo "Adding '" & StrGroupName(intIndice) & _ 106:                    "' to subscription to monitor this Active Directory group.' 107:    Next 108: 109:    strWMIQuery = cWMIQuery & " And (" & strWMIQuery & ")" 110: 111:    objWMIServices.ExecNotificationQueryAsync objWMISink, strWMIQuery ...: 114:    WScript.Echo vbCRLF & "Waiting for events..." 115: 116:    PauseScript "Click on 'Ok' to terminate the script ..." 117: 118:    WScript.Echo vbCRLF & "Cancelling event subscription ..." 119:    objWMISink.Cancel 124:    WScript.Echo "Finished." 125: 126:    ' ----------------------------------------------------------------------------------------------------------- 127:    Sub SINK_OnObjectReady (objWbemObject, objWbemAsyncContext) ...: 133:        Wscript.Echo 134:        Wscript.Echo "BEGIN - OnObjectReady." 135:        WScript.Echo FormatDateTime(Date, vbLongDate) & " at " & _ 136:                     FormatDateTime(Time, vbLongTime) & ": '" & _ 137:                     objWbemObject.Path_.Class & "' has been triggered." 138: 139:        Select Case objWbemObject.Path_.Class 140:               Case "_InstanceModificationEvent" 141:                    Set objWMIInstance = objWbemObject 142:               Case "_AggregateEvent" 143:                    Set objWMIInstance = objWbemObject.Representative 144:               Case Else 145:                    Set objWMIInstance = Null 146:        End Select 147: 148:       If Not IsNull (objWMIInstance) Then 149:          If SendMessage (cTargetRecipient, _ 150:                          cSourceRecipient, _ 151:                          "'"& objWMIInstance.TargetInstance.ds_name & _ 152:                          "' group modification - " & _ 153:                             FormatDateTime(Date, vbLongDate) & _ 154:                             " at " & 155:                             FormatDateTime(Time, vbLongTime), _ 156:                          GenerateHTML (objWMIInstance.PreviousInstance, _ 157:                                        objWMIInstance.TargetInstance) , _ 158:                          "") Then 159:             WScript.Echo "Failed to send email to '" & cTargetRecipient & "' ..." 160:          End If 161:       End If ...: 165:       Wscript.Echo "END - OnObjectReady." 166: 167:    End Sub 168: 169:    ]]> 170:    </script> 171:  </job> 172:</package> 

end example

As usual, the script structure is always the same. The script starts with the command-line parameter definitions (skipped lines 13 through 18) and parsing (lines 69 through 86). The script requires only one parameter on the command line, which lists one or more Active Directory group names to monitor. For example, to monitor modifications on the "Enterprise Admins" and "Domain Admins" group, the command line will be:

 C:\>GroupMonitor.Wsf "Enterprise Admins" "Domain Admins" 

The groups given on the command line are stored in an array (lines 75 through 78). Once the WMI connection is established (lines 90 through 93), the WQL query is constructed in a loop between lines 96 and 107. For the two sample groups given on the command line, the resulting WQL query will be:

 Select * From __InstanceModificationEvent Within 10 Where TargetInstance ISA 'ds_group' And               (TargetInstance.ds_name='Enterprise Admins' Or TargetInstance.ds_name='Domain Admins') 

Next, the WQL query is submitted for asynchronous notifications (line 111), and the script enters an idle state. Once a modification is made to one of the given groups, the event sink routine (lines 127 through 167) is invoked, and the script immediately sends an email alert by reusing the SendMessage() function (included at line 23) and the GenerateHTML() function (included at line 22). The PreviousInstance and the TargetInstance properties containing object instances are formatted in HTML and stored in a MIME body mail message.

3.6.1.4 Monitoring the FSMO roles

By using the event instrumentation provided by WMI, it is also possible to monitor the Domain Controllers Flexible Single Master Operations (FSMO) role modifications. However, this monitoring requires a small setup at the level of the Root\directory\LDAP namespace. By default, the Active Directory provider accesses any Active Directory object instances located in the default naming context, which is the Windows Domain where the accessed Domain Controller resides. However, to monitor all FSMO roles, it is necessary to access the Active Directory Configuration and Schema naming contexts, since the attributes containing the relevant information are spread among the different Active Directory naming contexts. Table 3.52 lists the different FSMO roles and their respective naming context locations.

Table 3.52: The Active FSMO Roles and Their Location in Active Directory

FSMO Role

Naming Context

WMI Class

Object distinguishedName

WMI Property

PDC Emulator

Domain

ds_domaindns

DC=LissWare, DC=Net

ds_fSMORoleOwner

Infrastructure Master

Domain

ds_infrastructureupdate

CN=Infrastructure, DC=LissWare, DC=Net

ds_fSMORoleOwner

RID Master

Domain

ds_ridmanager

CN=RID Manager$,CN=System,DC=LissWare,DC=Net

ds_fSMORoleOwner

Domain Naming

Configuration

ds_crossrefcontainer

CN=Partitions,CN=Configuration,DC=LissWare,DC=Net

ds_fSMORoleOwner

Schema owner

Schema

ds_dmd

CN=Schema,CN=Configuration,DC=LissWare,DC=Net

ds_fSMORoleOwner

To enable access from WMI to the ds_crossRefContainer Active Directory object instance located in the Configuration naming context and to the ds_dMD Active Directory object instance located in the Schema naming context, an instance of the DN_class and the DSClass_To_DNInstance WMI classes first must be created in the Root\directory\LDAP namespace. This can be done with the help of a MOF file, as illustrated in Sample 3.55.

Sample 3.55: Making the Configuration and Schema context accessible

start example

  1:  #pragma namespace("\\\\.\\Root\\directory\\ldap")  3:  Instance of DN_Class 4:  5:      {  6:      DN = "LDAP://CN=Configuration,DC= LissWare,DC=Net";  7:      };  8:  9:  Instance of DSClass_To_DNInstance 10: 11:      { 12:      DSClass = "ds_crossRefContainer" ; 13: 14:      RootDNForSearchAndQuery = "DN_Class.DN=\"LDAP://CN=Configuration,DC= LissWare,DC=Net\""; 15:      }; 16: 17: 18:  Instance of DN_Class 19: 20:      { 21:      DN = "LDAP://CN=Schema,CN=Configuration,DC= LissWare,DC=Net" ; 22:      }; 23: 24:  Instance of DSClass_To_DNInstance 25: 26:      { 27:      DSClass = "ds_dMD"; 28: 29:      RootDNForSearchAndQuery = 30:            "DN_Class.DN=\"LDAP://CN=Schema,CN=Configuration,DC=LissWare,DC=Net\""; 31:      }; 

end example

The DSClass_To_DNInstance is an association class performing the association of an instance defining an Active Directory naming context and a WMI class representing the Active Directory class of the object instance to locate in that naming context. For example, to locate a ds_crossRefContainer instance in the Active Directory Configuration naming context, an instance of the DSClass_To_DNInstance association class must be created (lines 9 through 15) with its properties initialized as follows:

  • The DSClass property is assigned with the ds_crossRefContainer class instance name (line 12).

  • The RootDNForSearchAndQuery property is assigned with the WMI path of the WMI instance representing the Active Directory Configuration context (line 14). The instance representing the Active Directory Configuration context is created with the DN_Class WMI class (lines 3 through 7).

The same rule applies for the ds_dMD class, which has its instance located in the Active Directory Schema naming context (lines 18 through 31). Once the MOF file is loaded in the CIM repository with MOF-COMP.EXE, the monitoring of the FSMO roles can take place. The logic is implemented in Sample 3.56.

Sample 3.56: Monitoring, managing, and alerting script for the FSMO role modifications

start example

   1:<?xml version="1.0"?>   .:   8:<package>   9:  <job>  ..:  13:    <runtime>  ..:  17:    </runtime>  18:  19:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\TinyErrorHandler.vbs" />  20:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\PauseScript.vbs" />  21:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\GenerateHTML.vbs" />  22:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\SendMessageExtendedFunction.vbs" />  23:  24:    <object progobjWMILocator' reference= " true "/>  25:    <object prog />  26:    <object prog />  27:    <object prog />  28:    <object prog />  29:    <object prog />  30:    <object progid= "WbemScripting. SWbemDateTime "  />  31:  32:    <script language="VBscript">  33:    <![CDATA[  ..:  72:    ' ------------------------------------------------------------------------------------  73:    ' Parse the command line parameters  74:    strUserID = WScript.Arguments.Named("User")  75:    If Len(strUserID) = 0 Then StrUserID = ""  76:  77:    strPassword = WScript.Arguments.Named("strPassword")  78:    If Len(strPassword) = 0 Then strPassword = ""  79:  80:    strComputerName = WScript.Arguments.Named("Machine")  81:    If Len(strComputerName) = 0 Then StrComputerName = cComputerName  82:  83:    Set objWMISink = WScript.CreateObject ("WbemScripting.SWbemSink", "SINK_")  84:  85:    objWMILocator.Security_.AuthenticationLevel = wbemAuthenticationLevelDefault  86:    objWMILocator.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate  87:    Set objWMIServices = objWMILocator.ConnectServer(strComputerName, cWMINameSpace, _  88:                                                     strUserID, strPassword)  ..:  91:    objPDCFSMOSinkContext.Add "FSMO", "PDC"  92:    objWMIServices.ExecNotificationQueryAsync objWMISink, _  93:                                              cPDCFSMOWMIQuery, _  94:                                              ' _  95:                                              ' _  96:                                              ' _  97:                                              objPDCFSMOSinkContext  98:    If Err.Number Then ErrorHandler (Err)  99:    WScript.Echo "Monitoring PDC FSMO role ..." 100: 101:    objINFFSMOSinkContext.Add "FSMO", "INFRASTRUCTURE" 102:    objWMIServices.ExecNotificationQueryAsync objWMISink, _ 103:                                              cINFFSMOWMIQuery, 104:                                              ' _ 105:                                              ' _ 106:                                              ' _ 107:                                             objINFFSMOSinkContext 108:    If Err.Number Then ErrorHandler (Err) 109:    WScript.Echo "Monitoring INFRASTRUCTURE FSMO role ..." 110: 111:    objRIDFSMOSinkContext.Add "FSMO", "RID" 112:    objWMIServices.ExecNotificationQueryAsync objWMISink, _ 113:                                              cRIDFSMOWMIQuery, _ 114:                                              ' _ 115:                                              ' _ 116:                                              ' _ 117:                                              objRIDFSMOSinkContext 118:    If Err.Number Then ErrorHandler (Err) 119:    WScript.Echo ''Monitoring RID FSMO role ..." 120: 121:    objDOMFSMOSinkContext.Add "FSMO", "DOMAIN NAMING" 122:    objWMIServices.ExecNotificationQueryAsync objWMISink, _ 123:                                              cDOMFSMOWMIQuery, _ 124:                                              ' _ 125:                                              ' _ 126:                                              ' _ 127:                                              objDOMFSMOSinkContext 128:    If Err.Number Then ErrorHandler (Err) 129:    WScript.Echo "Monitoring DOMAIN NAMING FSMO role ..." 130: 131:    objSCHFSMOSinkContext.Add "FSMO", "SCHEMA" 132:    objWMIServices.ExecNotificationQueryAsync objWMISink, _ 133:                                              cSCHFSMOWMIQuery, _ 134:                                              ' _ 135:                                              ' _ 136:                                              ' _ 137:                                              objSCHFSMOSinkContext 138:    If Err.Number Then ErrorHandler (Err) 139:    WScript.Echo "Monitoring SCHEMA FSMO role ..." 140: 141:    WScript.Echo vbCRLF & "Waiting for events..." 142: 143:    PauseScript "Click on 'Ok' to terminate the script ..." 144: 145:    WScript.Echo vbCRLF & ''Cancelling event subscription ..." 146:    objWMISink.Cancel ...: 151:    WScript.Echo "Finished." 152: 153:     ' ------------------------------------------------------------------------------------- 154:    Sub SINK_OnObjectReady (objWbemObject, objWbemAsyncContext) ...: 203:    End Sub 204: 205:    ]]> 206:    </script> 207:  </job> 208:</package> 

end example

The logic and structure of Sample 3.56 is basically the same as Sample 3.54 ("Monitoring, managing, and alerting script for the Windows Group modifications"). However, instead of executing one WQL event query, Sample 3.56 executes five WQL event queries (one per FSMO role):

For the PDC Emulator FSMO:

 Select * From __InstanceModificationEvent Within 10          Where TargetInstance ISA 'ds_domaindns' And          PreviousInstance.DS_fSMORoleOwner <> TargetInstance.DS_fSMORoleOwner" 

For the Infrastructure Master FSMO:

 Select * From __InstanceModificationEvent Within 10          Where TargetInstance ISA 'ds_infrastructureupdate' And          PreviousInstance.DS_fSMORoleOwner <> TargetInstance.DS_fSMORoleOwner" 

For the RID Master FSMO:

 Select * From _InstanceModificationEvent Within 10          Where TargetInstance ISA 'ds_ridmanager' And          PreviousInstance.DS_fSMORoleOwner <> TargetInstance.DS_fSMORoleOwner" 

For the Domain Naming Master FSMO:

 Select * From _InstanceModificationEvent Within 10          Where TargetInstance ISA  ds_crossrefcontainer  And          PreviousInstance.DS_fSMORoleOwner <> TargetInstance.DS_fSMORoleOwner" 

For the Schema Owner FSMO:

 Select * From _InstanceModificationEvent Within 10          Where TargetInstance ISA 'ds_dmd' And          PreviousInstance.DS_fSMORoleOwner <> TargetInstance.DS_fSMORoleOwner" 

Once the WMI connection is established (lines 85 through 88), the five

WQL event queries are submitted to WMI (lines 91 through 139). Note that each WQL query makes use of a WMI context, since the same event sink subroutine is used to capture all WMI events. This routine has the exact same logic and structure as Sample 3.54 ("Monitoring, managing, and alerting script for the Windows Group modifications").

3.6.1.5 Debugging Active Directory providers

If you experience trouble managing Active Directory objects with the WMI Active Directory providers, it is possible to trace the provider's activity in a log file. The configuration of a registry key set activates the trace logging. The registry keys are located at:

 HKLM\SOFTWARE\Microsoft\WBEM\PROVIDERS\Logging\DSProvider 

Note that other WMI providers, such as SNMP providers, also support activity trace logging (see Table 3.53). They use the same set of registry key names but from a different registry hive, as shown in Figure 3.34; the SNMP providers use the "WBEMSNMP" hive.

Table 3.53: Enabling the Trace Logging of a WMI Provider

Key names

Description

File

Full path and file name of the log file. The default value is %windir%\system32\wbem\logs. The Type named value must be set to "File" for this named value to be used.

Level

A 32-bit logical mask that defines the type of debugging output generated by the provider. This value is provider-dependent. The default value is 0 (zero).

MaxFileSize

Maximum file size (in bytes) of the log file. This integer value must be in the range 1024 to 2^32-1. When the file size exceeds this value, the file is renamed to -filename and a new, empty log file is created. The disk space required for the log file is twice the value of MaxFileSize. The default value is 65,535.

Type

Can be set to "File" or"Debugger". If set to "File", the trace information is written to the log file specified in the File named value. The default value is "File."

click to expand
Figure 3.34: The registry hive for the four WMI providers supporting activity logging.

Once the Active Directory WMI providers logging is started, the DSPro-vider.LOG file contains trace information and error messages for the Directory Service providers. The Level registry key is set to zero by default and can remain zero for the Active Directory providers. However, the tracing of other providers (i.e., SNMP providers) may require some values. Actually, the required values are determined by the provider implementation. To give a simple trace example, if the script (Sample 3.53, "Creating an Active Directory user object with WMI") is executed a second time, it will return an error, since the user already exists. The output will be as follows:

 C:\>CreateADUser.wsf Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. ------------------------------------------------------------ Error: &h80041001 Generic failure ------------------------------------------------------------ 

From a WMI perspective, the returned error message "Generic Failure" is not enough to determine the source of the problem. Of course, it is always possible to instantiate an SWBemLastError object, but in this particular case it will not give much more information about the problem. However, by looking at the DSProvider.LOG, it shows the following information:

    1:  CDSClassProvider :: GetClassFromCacheOrADSI()        Could not find class in Authenticated list for ds_user. Going to ADSI    2:  CDSClassProvider :: GetObjectAsync() called for ADS_user    3:  CDSClassProvider :: GetClassFromCacheOrADSI()        Could not find class in Authenticated list for ADS_user. Going to ADSI    4:  CDSClassProvider :: GetObjectAsync() called for ADS_organizationalPerson    5:  CDSClassProvider :: GetClassFromCacheOrADSI()        Could not find class in Authenti i=d list for ADS_organizationalPerson. Going to ADSI    6:  CDSClassProvider :: GetObjectAsync() called for ADS_person    7:  CDSClassProvider :: GetClassFromCacheOrADSI()        Could not find class in Authenticated list for ADS_person. Going to ADSI    8:  CDSClassProvider :: GetObjectAsync() called for DS_top    9:  CDSClassProvider :: GetClassFromCacheOrADSI()        Could not find class in Authenticated list for DS_top. Going to ADSI   10:  CWbemCache :: AddClass() Added a class DS_top to cache   11:  CDSClassProvider :: GetClassFromCacheOrADSI()        GetClassFromADSI succeeded for DS_top Added it to cache   12:  CDSClassProvider :: GetClassFromCacheOrADSI() Also added to Authenticated list : DS_top   13:  CWbemCache :: AddClass() Added a class ADS_person to cache   14:  CDSClassProvider :: GetClassFromCacheOrADSI()        GetClassFromADSI succeeded for ADS_person Added it to cache   15:  CDSClassProvider :: GetClassFromCacheOrADSI()        Also added to Authenticated list : ADS_person   16:  CWbemCache :: AddClass() Added a class ADS_organizationalPerson to cache   17:  CDSClassProvider :: GetClassFromCacheOrADSI()        GetClassFromADSI succeeded for ADS_organizationalPerson Added it to cache   18:  CDSClassProvider :: GetClassFromCacheOrADSI()        Also added to Authenticated list : ADS_organizationalPerson   19:  CWbemCache :: AddClass() Added a class ADS_user to cache   20:  CDSClassProvider :: GetClassFromCacheOrADSI()        GetClassFromADSI succeeded for ADS_user Added it to cache   21:  CDSClassProvider :: GetClassFromCacheOrADSI() Also added to Authenticated list : ADS_user   22:  CWbemCache :: AddClass() Added a class ds_user to cache   23:  CDSClassProvider :: GetClassFromCacheOrADSI()        GetClassFromADSI succeeded for ds_user Added it to cache   24:  CDSClassProvider :: GetClassFromCacheOrADSI() Also added to Authenticated list : ds_user   25:  CDSClassProvider :: GetObjectAsync() called for ds_user   26:  CDSClassProvider :: GetClassFromCacheOrADSI() Found class in Authenticated list for ds_user   27:  CDSClassProvider :: GetClassFromCacheOrADSI() Found class in cache for ds_user   28:  CDSClassProvider :: GetObjectAsync() called for ads_user   29:  CDSClassProvider :: GetClassFromCacheOrADSI() Found class in Authenticated list for ads_user   30:  CDSClassProvider :: GetClassFromCacheOrADSI() Found class in cache for ads_user   31:  CDSInstanceProviderClassFactory::CreateInstance() called   32:  CLDAPInstanceProvider :: CONSTRUCTOR   33:  CLDAPInstanceProvider :: Got Top Level Container as : DC=LissWare,DC=Net   34:  CLDAPInstanceProvider :: PutInstanceAsync() called   35:  CLDAPInstanceProvider :: PutInstanceAsync()        calledfor ds_user.ADSIPath="LDAP://CN=WMIUser,CN=Users,DC=LissWare,DC=Net"   36:  CLDAPInstanceProvider :: The 362 attributes being put are:   37:  accountExpires   38:  accountNameHistory   39:  aCSPolicyName  ...:   ...:   395:  whenCreated  396:  wWWHomePage  397:  x121Address  398:  x500uniqueIdentifier  399:  CLDAPInstanceProvider :: SetObjectAttributes FAILED with 80072035  400:  CLDAPInstanceProvider :: PutInstanceAsync()        ModifyExistingInstance FAILED for LDAP://CN=WMIUser,CN=Users,DC=LissWare,DC=Net        with 80072035 

From line 1 through 30, we see the activity generated by the Active Directory provider to create the ds_user instance. At line 31, we see the instance creation followed by the Put_ method invocation (lines 34 and 35). From line 36 through 398, we see the list of attributes that will be set. Because the user instance already exists in Active Directory, trying to set all these attributes will generate an error, since some attributes can only be set by the system itself (see section 3.6.1.1, "Creating and updating objects in Active Directory"). The end result is an error number 80072035 (line 399). By looking in the Active Directory platform SDK, we can determine that an error 8007* is a Win32 Error. In such a case the rightmost part of the error number must be converted to a decimal value, which gives 8,245 in decimal (from 2,035 in hexadecimal). If we run the command "NET HELPMSG 8245" from the command line, we will get the informational message: "The server is unwilling to process the request." This makes sense, since the script tries to perform an illegal Active Directory operation, which is an update of all attributes available from the existing user object (even with the ones that can only be updated by the system).

3.6.2 Active Directory Replication provider

The Active Directory Replication provider allows the management of the replication. With this provider and its supported classes, it is possible to retrieve information about the replication state. The provider is implemented as an instance and method provider (see Table 3.54).

Table 3.54: The Active Directory Replication Providers Capabilities

Provider Name

Provider Namespace

Class Provider

Instance Provider

Method Provider

Property Provider

Event Provider

Event Consumer Provider

Support Get

Support Put

Support Enumeration

Support Delete

Windows Server 2003

Windows XP

Windows 2000 Server

Windows 2000 Professional

Windows NT 4.0

Active Directory Replication provider

RepIProv1

Root/MicrosoftActiveDirectory

X

X

X

X

X

The Active Directory Replication provider is located in the Root\MicrosoftActiveDirectory namespace of the CIM repository and supports five classes, as listed in Table 3.55.

Table 3.55: The Active Directory Replication Providers Classes

Name

Comments

MSAD_ReplPendingOp

Describes a replication task currently executing or pending execution on the DC.

MSAD_NamingContext

Various properties of the current Naming Context.

MSAD_ReplCursor

Contains inbound replication state information with respect to all replicas of a given Naming Context. This state information indicates up to what USN X the destination server has seen all changes <= USN X originated by the source server with the given invocation ID.

MSAD_DomainController

The current domain controller properties.

MSAD_ReplNeighbor

Inbound replication state information for a Naming Context & source server pair.

Since the Active Directory Replication provider is not implemented as an event provider, there is no extrinsic event class available. This also means that the use of the WITHIN statement in a WQL event query is mandatory. For example, the MSAD_DomainController class exposes Boolean values that determine if a domain controller is registered in the Dynamic DNS or if the replicated SYSVOL volume is ready for use. To capture any modification made in an MSAD_DomainController instance that represents a domain controller, the following WQL event query can be used:

  1:   C:>GenericEventAsyncConsumer.wsf "Select * From _InstanceModificationEvent Within 10  2:                                    Where TargetInstance ISA 'MSAD_DomainController'"  3:                                    /namespace:Root\MicrosoftActiveDirectory  4:   Microsoft (R) Windows Script Host Version 5.6  5:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.  6:  7:   Waiting for events...  8:  9:   BEGIN - OnObjectReady. 10:   Sunday, 16 December, 2001 at 10:07:11: '_InstanceModificationEvent' has been triggered. 11: 12:     - __InstanceModificationEvent ----------------------------------------------------- 13: 14:       - MSAD_DomainController —————————————————————————————————————————————— 15:       CommonName: .......................... NET-DPEN6400A 16:       *DistinguishedName: .................. CN=NTDS Settings,CN=NET-DPEN6400A,CN=Servers, 17:                                             CN=Brussels,CN=Sites,CN=Configuration, 18:                                             DC=LissWare,DC=Net 19:       IsAdvertisingToLocator: .............. TRUE 20:       IsGC: ................................ TRUE 21:       IsNextRIDPoolAvailable: .............. FALSE 22:       IsRegisteredInDNS: ................... FALSE 23:       IsSysVolReady: ....................... TRUE 24:       NTDsaGUID: ........................... 8b231f02-43el-43f9-94c4-c8545e4b6d2b 25:       PercentOfRIDsLeft: ................... 98 26:       SiteName: ............................ Brussels 27:       TimeOfOldestReplAdd: ................. 01-01-1601 28:       TimeOfOldestReplDel: ................. 01-01-1601 29:       TimeOfOldestReplMod: ................. 01-01-1601 30:       TimeOfOldestReplSync: ................ 01-01-1601 31:       TimeOfOldestReplUpdRefs: ............. 01-01-1601 32: 33: 34:       - MSAD_DomainController —————————————————————————————————————————————— 35:       CommonName: .......................... NET-DPEN6400A 36:       *DistinguishedName: .................. CN=NTDS Settings,CN=NET-DPEN6400A,CN=Servers, 37:       CN=Brussels,CN=Sites,CN=Configuration, 38:       DC=LissWare,DC=Net 39:       IsAdvertisingToLocator: .............. TRUE 40:       IsGC: ................................ TRUE 41:       IsNextRIDPoolAvailable: .............. FALSE 42:       IsRegisteredInDNS: ................... TRUE 43:       IsSysVolReady: ....................... TRUE 44:       NTDsaGUID: ........................... 8b231f02-43el-43f9-94c4-c8545e4b6d2b 45:       PercentOfRIDsLeft: ................... 98 46:       SiteName: ............................ Brussels 47:       TimeOfOldestReplAdd: ................. 01-01-1601 48:       TimeOfOldestReplDel: ................. 01-01-1601 49:       TimeOfOldestReplMod: ................. 01-01-1601 50:       TimeOfOldestReplSync: ................ 01-01-1601 51:       TimeOfOldestReplUpdRefs: ............. 01-01-1601 52: 53: 54:   END - OnObjectReady. 

In this output sample, we can see that the DNS registration state has passed from False (line 22) to True (line 42).

Samples 3.57 through 3.59 make use of the other classes supported by the Active Directory Replication provider (see Table 3.55). The script exposes the following command-line parameters:

 C:\>WMIADRepl.wsf Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. Usage: WMIADRepl.wsf [/ReplPendingOp[+|-]]  [/NC[+|-]] [/ReplCsr[+|-]]  [/DC[+|-]]                      [/ReplNeighbor:value] [/ExecuteKCC[+|-]] [/SyncNC:value]                      [/Machine:value] [/User:value] [/Password:value] Options: ReplPendingOp : View the replication tasks currently executing or pending execution on the DC. NC            : View the properties of the current Naming Contexts. ReplCsr       : View inbound replication state information with respect to all replicas                 of a each Naming Context. DC            : View current domain controller properties. ReplNeighbor  : View inbound replication state information for a Naming Context                 and source server pair. ExecuteKCC    : Invokes the Knowledge Consistency Checker in order to verify                 the replication topology. SyncNC        : Synchronizes a destination Naming Context with one of its sources. Machine       : Determine the WMI system to connect to. (default=LocalHost) User          : Determine the UserID to perform the remote connection. (default=none) Password      : Determine the password to perform the remote connection. (default=none) Example:       WMIADRepl.wsf /ReplPendingOp+       WMIADRepl.wsf /NC+       WMIADRepl.wsf /ReplCsr+       WMIADRepl.wsf /DC+       WMIADRepl.wsf /ReplNeighbor       WMIADRepl.wsf /ReplNeighbor:CN=Configuration,DC=LissWare,DC=Net       WMIADRepl.wsf /ReplNeighbor:CN=Schema,CN=Configuration,DC=LissWare,DC=Net       WMIADRepl.wsf /ReplNeighbor:DC=ForestDnsZones,DC=LissWare,DC=Net       WMIADRepl.wsf /ReplNeighbor:DC=Emea,DC=LissWare,DC=Net       WMIADRepl.wsf /ExecuteKCC+       WMIADRepl.wsf /SyncNC:CN=Configuration,DC=LissWare,DC=Net       WMIADRepl.wsf /SyncNC:CN=Schema,CN=Configuration,DC=LissWare,DC=Net       WMIADRepl.wsf /SyncNC:DC=ForestDnsZones,DC=LissWare,DC=Net       WMIADRepl.wsf /SyncNC:DC=Emea,DC=LissWare,DC=Net 

Basically, the script enumerates the various instances of the classes.

Sample 3.57: Viewing and managing the Active Directory Replication state (Part I)

start example

   1:<?xml version="1.0"?>   .:   8:<package>   9:  <job>  ..:  13:    <runtime>  ..:  42:    </runtime>  43:  44:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\DisplayFormattedPropertyFunction.vbs" />  45:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\TinyErrorHandler.vbs" />  46:  47:    <object prog  reference="true"/>  48:   <object prog  />  49:  50:    <script language="VBscript">  51:    <![CDATA[  ..:  55:    Const cComputerName = "LocalHost"  56:    Const cWMINameSpace = "Root/MicrosoftActiveDirectory"  57:  58:    Const cExecKCCTaskID = 0  59:    Const cExecKCCFlags = 0  60:    Const cSyncNCOptions = 16  ..:  87:    ' -----------------------------------------------------------------  88:    ' Parse the command line parameters  89:    If WScript.Arguments.Named.Count = 0 Then  90:       WScript.Arguments.ShowUsage()  91:       WScript.Quit  92:    End If ...: 121:    strComputerName = WScript.Arguments.Named("Machine") 122:    If Len(strComputerName) = 0 Then strComputerName = cComputerName 123: 124:    objWMILocator.Security_.AuthenticationLevel = wbemAuthenticationLevelDefault 125:    objWMILocator.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate 126: 127:    Set objWMIServices = objWMILocator.ConnectServer(strComputerName, cWMINameSpace, _ 128:                                                     strUserID, strPassword) ...: 131:    ' -- ReplPendingOp ------------------------------------------------------------------------ 132:    If boolReplPendingOp Then 133:       Set objWMIInstances = objWMIServices.InstancesOf ("MSAD_ReplPendingOp") 134:       If Err.Number Then ErrorHandler (Err) 135: 136:       If objWMIInstances.Count Then 137: 138:          WScript.Echo "- " & objWMIInstance.NamingContextDN & " " & String (60, "-") 139: 140:          For Each objWMIInstance In objWMIInstances 141:              Set objWMIPropertySet = objWMIInstance.Properties_ 142:              For Each objWMIProperty In objWMIPropertySet 143:                  DisplayFormattedProperty objWMIInstance, _ 144:                         objWMIProperty.Name, _ 145:                      objWMIProperty.Name, _ 146:                      Null 147:             Next 148:             Set objWMIPropertySet = Nothing 149:             WScript.Echo 150:          Next 151:       Else 152:          WScript.Echo "No information available." & vbCRLF 153:       End If 154:    End If 155: 156:    ' —- NC ------------------------------------------------------------------------------ 157:    If boolNC Then 158:       Set objWMIInstances = objWMIServices.InstancesOf ("MSAD_NamingContext") 159:       If Err.Number Then ErrorHandler (Err) 160: 161:       WScript.Echo "EXISTING NAMING CONTEXT " & String (84, " = ") & vbCRLF 162:       WScript.Echo Space (36) & "Naming Context Full replica" 163:       WScript.Echo String (98, "-") 164: 165:       For Each objWMIInstance In objWMIInstances 166:          WScript.Echo String (50 - Len (objWMIInstance.DistinguishedName), " ") & _ 167:                       objWMIInstance. DistintguishedName & " " & _ 168:                       String (15 - Len (objWMIInstance.IsFullReplica), " ") & _ 169:                       objWMIInstance.IsFullReplica 170:       Next 171:       WScript.Echo 172:    End If 173: 174:   ' —- ReplCsr -------------------------------------------------------------------------- 175:    If boolReplCsr Then 176:       Set objWMIInstances = objWMIServices.InstancesOf ("MSAD_ReplCursor") 177:       If Err.Number Then ErrorHandler (Err) 178: 179:       If objWMIInstances.Count Then 180:          For Each objWMIInstance In objWMIInstances 181:              WScript.Echo "- " & objWMIInstance.NamingContextDN & " " & String (60, "-") 182: 183:              Set objWMIPropertySet = objWMIInstance.Properties_ 184:              For Each objWMIProperty In objWMIPropertySet 185:                  DisplayFormattedProperty objWMIInstance, _ 186:                         objWMIProperty.Name, _ 187:                         objWMIProperty.Name, _ 188:                         Null 189:              Next 190:              Set objWMIPropertySet = Nothing 191:              WScript.Echo 192:          Next 193:       Else 194:          WScript.Echo "No information available." & vbCRLF 195:       End If 196:    End If 197: 198:    ' —- DC ------------------------------------------------------------------------------ 199:    If boolDC Then 200:       Set objWMIInstances = objWMIServices.InstancesOf ("MSAD_DomainController") 201:       If Err.Number Then ErrorHandler (Err) 202: 203:       If objWMIInstances.Count Then 204:          For Each objWMIInstance In objWMIInstances 205:             Set objWMIPropertySet = objWMIInstance.Properties_ 206:             For Each objWMIProperty In objWMIPropertySet 207:                 DisplayFormattedProperty objWMIInstance, _ 208:                        objWMIProperty.Name, _ 209:                        objWMIProperty.Name, - 210:                        Null 211:             Next 212:             Set objWMIPropertySet = Nothing 213:             WScript.Echo 214:         Next 215:      Else 216:         WScript.Echo "No information available." & vbCRLF 217:      End If 218:   End If 219: ...: ...: ...: 

end example

Once the command-line parameters are parsed (lines 87 through 122) and the WMI connection established (lines 124 through 128), the script retrieves miscellaneous instances based on the command-line parameters. If the command line includes the /ReplPendingOp+ switch, the section from line 132 through 154 is executed (see Sample 3.58). This section retrieves information about the replication tasks currently executing or pending execution on the Domain Controller by requesting all instances of the MSAD_ ReplPendingOp class (line 133). Next, the script retrieves the properties of each instance (lines 140 through 150).

Sample 3.58: Viewing the inbound replication state information for a Naming Context (Part II)

start example

 ...: ...: ...: 219: 220:    ' -- ReplNeighbor -------------------------------------------------------------- 221:    If boolReplNeighbor Then 222:       If Len (strReplNeighbor) Then 223:          Set objWMIInstances = objWMIServices.ExecQuery("Select * FromMSAD_ReplNeighbor " & _ 224:                                                         "Where NamingContextDN='" & _ 225:                                                         strReplNeighbor & "'") 226:          If Err.Number Then ErrorHandler (Err) 227: 228:          If objWMIInstances.Count = 1 Then 229:             For Each objWMIInstance In objWMIInstances 230: 231:                 WScript.Echo "- " & objWMIInstance.NamingContextDN & " " & String (60, "-") 232: 233:                 Set objWMIPropertySet = objWMIInstance.Properties. 234:                 For Each objWMIProperty In objWMIPropertySet 235:                     DisplayFormattedProperty objWMIInstance, _ 236:                            objWMIProperty.Name, _ 237:                            objWMIProperty.Name, _ 238:                            Null 239:                 Next 240:                 Set objWMIPropertySet = Nothing 241:                 WScript.Echo 242:             Next 243:          Else 244:             WScript.Echo "No information available." & vbCRLF 245:          End If 246:       Else 247:          Set objWMIInstances = objWMIServices.InstancesOf ("MSAD_ReplNeighbor") 248:          If Err.Number Then ErrorHandler (Err) 249: 250:          If objWMIInstances.Count Then 251:          WScript.Echo "INBOUND REPLICATION STATE'' & String (188, "=") & vbCRLF 252:          WScript.Echo "                                    Naming Context" & _ 253:                       "           Source DSA            Site SyncProg"  & _ 254:                       " SyncNext IsDeleted LastSync ModSyncFailures SyncFailure" & _ 255:                       "       TimeOfLastSync    TimeOfLastSuccess" & _ 256:                       "  USNAttr USNObject" 257:          WScript.Echo String (213, "-") 258: 259:          For Each objWMIInstance In objWMIInstances 260:              objWMIDateTime.Value = objWMIInstance.TimeOfLastSyncAttempt 261:              strTimeOfLastSyncAttempt = objWMIDateTime.GetVarDate (False) 262:              objWMIDateTime.Value = objWMIInstance.TimeOfLastSyncSuccess 263:              strTimeOfLastSyncSuccess = objWMIDateTime.GetVarDate (False) 264: 265:              WScript.Echo String (50-Len(objWMIInstance.NamingContextDN)," ") & _ 266:                   objWMIInstance.NamingContextDN & " " & _ 267:                      String (20-Len(objWMIInstance.SourceDsaCN)," ") & _ 268:                      objWMIInstance. SourceDsaCN & " " & _ 269:                      String (15-Len(objWMIInstance.SourceDsaSite)," ") & _ 270:                      objWMIInstance.SourceDsaSite & " " & _ 271:                      String (8-Len(objWMIInstance.FullSyncInProgress)," ") & _ 272:                      objWMIInstance.FullSyncInProgress & " " & _ 273:                      String (-Len(objWMIInstance.FullSyncNextPacket)," ") & _ 274:                      objWMIInstance.FullSyncNextPacket & " " & _ 275:                      String (9-Len(objWMIInstance.IsDeletedSourceDsa)," ") & _ 276:                      objWMIInstance.IsDeletedSourceDsa & " " & _ 277:                      String (8-Len(objWMIInstance.LastSyncResult)," ") & _ 278:                      objWMIInstance.LastSyncResult & " " & _ 279:                      String(15-Len(objWMIInstance.ModifiedNumConsecutiveSyncFailures)," ") & _ 280:                      objWMIInstance.ModifiedNumConsecutiveSyncFailures & " " & _ 281:                      String (11-Len(objWMIInstance.NumConsecutiveSyncFailures)," ") & _ 282:                      objWMIInstance.NumConsecutiveSyncFailures & " " & _ 283:                      String (20-Len(strTimeOfLastSyncAttempt)," ") & _ 284:                      strTimeOfLastSyncAttempt  & " " & _ 285:                      String (20-Len(strTimeOfLastSyncSuccess)," ") & _ 286:                      strTimeOfLastSyncSuccess & " " & _ 287:                      String (8-Len(objWMIInstance.USNAttributeFilter)," ") & _ 288:                      objWMIInstance.USNAttributeFilter & " " & _ 289:                      String (9-Len(objWMIInstance.USNLastObjChangeSynced)," ") & _ 290:                      objWMIInstance.USNLastObjChangeSynced 291:             Next 292:             WScript.Echo 293:          Else 294:              WScript.Echo "No information available." & vbCRLF 295:          End If 296:       End If 297:    End If 298: ...: ...: ...: 

end example

The script proceeds exactly in the same way for all classes supported by the Active Directory Replication provider. The script uses:

  • The MSAD_NamingContext class to retrieve properties of the current Naming Context available (lines 157 through 172). A sample output would be:

      1:   C:\>WMIADRepl.wsf /NC+  2:   Microsoft (R) Windows Script Host Version 5.6  3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.  4:  5:   EXISTING NAMING CONTEXT ============================================================  6:  7:                                    Naming Context    Full replica  8:   ----------------------------------------------------------------------------------  9:             DC=DomainDnsZones,DC=LissWare,DC=Net             True 10:             DC=ForestDnsZones,DC=LissWare,DC=Net             True 11:    CN=Schema,CN=Configuration,DC=LissWare,DC=Net             True 12:              CN=Configuration,DC=LissWare,DC=Net             True 13:                               DC=LissWare,DC=Net             True 14:                       DC=Emea,DC=LissWare,DC=Net             False 15: 16:   Completed. 

  • The MSAD_ReplCursor class to retrieve inbound replication state information with respect to all replicas of a given Naming Context (lines 175 through 196). A sample output would be:

      1:   C:\>WMIADRepl.wsf /ReplCsr+  2:   Microsoft (R) Windows Script Host Version 5.6  3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.  4:  5:   - DC=DomainDnsZones,DC=LissWare,DC=Net --------------------------------------------------------------  6:   *NamingContextDN: ........................ DC=DomainDnsZones,DC=LissWare,DC=Net  7:   SourceDsaDN: ............................. CN=NTDS Settings,CN=NET-DPEN6400A,CN=Servers,  8:                                              CN=Brussels,CN=Sites,CN=Configuration,  9                                               DC=LissWare,DC=Net 10:   *SourceDsaInvocationID: .................. 8b231f02-43el-43f9-94c4-c8545e4b6d2b 11:   TimeOfLastSuccessfulSync: ................ 16-12-2001 17:26:48 12:   USNAttributeFilter: ...................... 12212 13: 14:   - DC=ForestDnsZones,DC=LissWare,DC=Net -------------------------------------------------------------- 15:   *NamingContextDN: ........................ DC=ForestDnsZones,DC=LissWare,DC=Net 16:   SourceDsaDN: ............................. CN=NTDS Settings,CN=NET-DPEN6400A,CN=Servers, 17:                                              CN=Brussels,CN=Sites, 18:                                              CN=Configuration,DC=LissWare,DC=Net 19:   *SourceDsaInvocationID: .................. 8b231f02-43el-43f9-94c4-c8545e4b6d2b 20:   TimeOfLastSuccessfulSync: ................ 16-12-2001 17:26:48 21:   USNAttributeFilter: ...................... 12212 

  • The MSAD_DomainController class to retrieve the domain controller properties (lines 199 through 218). A sample output would be:

      1:   C:\>WMIADRepl.wsf /DC+  2:   Microsoft (R) Windows Script Host Version 5.6  3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.  4:  5:   CommonName: .............................. NET-DPEN6400A  6:   *DistinguishedName: ...................... CN=NTDS Settings,CN=NET-DPEN6400A,CN=Servers,  7:                                              CN=Brussels,CN=Sites,CN=Configuration,  8:                                              DC=LissWare,DC=Net  9:   IsAdvertisingToLocator: .................. TRUE 10:   IsGC: .................................... TRUE 11:   IsNextRIDPoolAvailable: .................. FALSE 12:   IsRegisteredlnDNS: ....................... TRUE 13:   IsSysVolReady: ........................... TRUE 14:   NTDsaGUID: ............................... 8b231f02-43el-43f9-94c4-c8545e4b6d2b 15:   PercentOfRIDsLeft: ....................... 98 16:   SiteName: ................................ Brussels 17:   TimeOfOldestReplAdd: ..................... 01-01-1601 18:   TimeOfOldestReplDel: ..................... 01-01-1601 19:   TimeOfOldestReplMod: ..................... 01-01-1601 20:   TimeOfOldestReplSync: .................... 01-01-1601 21:   TimeOfOldestReplUpdRefs: ................. 01-01-1601 22: 23:   Completed. 

You will notice the presence of several Boolean values, which indicate the state of the examined domain controller (i.e., IsAdvertisingToLocator, IsGC, IsNextRIDPoolAvailable, IsRegisteredInDNS, IsSysVolReady).

Sample 3.58 displays information from the MSAD_ReplNeighbor class. It retrieves the inbound replication state information for a Naming Context and source server pair.

The script can display the information in two different ways. If no specific naming context is specified with the /ReplNeighbor switch, the script displays the information for all naming contexts available (lines 247 through 296). If a naming context is given on the command line, only the information related to that naming context is displayed (lines 223 through 245). A sample output would be:

  1:   C:\>WMIADRepl.wsf /ReplNeighbor:CN=Configuration,DC=LissWare,DC=Net  2:   Microsoft (R) Windows Script Host Version 5.6  3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.  4:  5:   - CN=Configuration,DC=LissWare,DC=Net ---------------------------------------------------  6:   AsyncIntersiteTransportObjGuid: .......... 00000000-0000-0000-0000-000000000000  7:   CompressChanges: ......................... TRUE  8:   DisableScheduledSync: .................... FALSE  9:   Domain: .................................. LissWare.Net 10:   DoScheduledSyncs: ........................ TRUE 11:   FullSyncInProgress: ...................... FALSE 12:   FullSyncNextPacket: ...................... FALSE 13:   IgnoreChangeNotifications: ............... FALSE 14:   IsDeletedSourceDsa: ...................... FALSE 15:   LastSyncResult: .......................... 0 16:   ModifiedNumConsecutiveSyncFailures: ...... 0 17:   *NamingContextDN: ........................ CN=Configuration,DC=LissWare,DC=Net 18:   NamingContextObjGuid: .................... ba172143-2bc0-4d55-be69-711a8f927419 19:   NeverSynced: ............................. FALSE 20:   NoChangeNotifications: ................... TRUE 21:   NumConsecutiveSyncFailures: .............. 0 22:   ReplicaFlags: ............................ 805306448 23:   SourceDsaAddress: ........................ 14612935-967d-402f-b5b1-0ae412edaec4. 24:                                             _msdcs.LissWare.Net 25:   SourceDsaCN: ............................. NET-DPEP6400 26:   SourceDsaDN: ............................. CN=NTDS Settings,CN=NET-DPEP6400,CN=Servers, 27:                                              CN=Seattle,CN=Sites,CN=Configuration, 28:                                              DC=LissWare,DC=Net 29:   SourceDsaInvocationID: ................... 905e62c2-6f20-4333-ae8b-c6829e12d5b9 30:   *SourceDsaObjGuid: ....................... 14612935-967d-402f-b5b1-0ae412edaec4 31:   SourceDsaSite: ........................... Seattle 32:   SyncOnStartup: ........................... FALSE 33:   TimeOfLastSyncAttempt: ................... 16-12-2001 17:38:05 34:   TimeOfLastSyncSuccess: ................... 16-12-2001 17:38:05 35:   TwoWaySync: .............................. FALSE 36:   UseAsyncIntersiteTransport: .............. FALSE 37:   USNAttributeFilter: ...................... 5810 38:   USNLastObjChangeSynced: .................. 5810 39:   Writeable: ............................... TRUE 40: 41:   Completed. 

The class MSAD_DomainController exposes an interesting method called ExecuteKCC, which forces the execution of the Knowledge Consistency Checker (KCC). The MSAD_DomainController class exposing the ExecuteKCC method is a wrapper of the DsReplicaConsistencyCheck() API. Therefore, its method uses the same parameters as the API (see Table 3.56). These parameters are defined in constants at lines 58 and 59 (see Sample 3.57).

Table 3.56: The ExecuteKCC Method Parameters

Parameter name

Values

Description

TaskID

DS_KCC_TASKID_UPDATE_TOPOLOGY

0

Identifies the task the KCC should execute. DS_KCC_TASKID_UPDATE_TOPOLOGY is the only supported value at this time.

Flags

DS_KCC_FLAG_ASYNC_OP

1

DS_KCC_FLAG_ASYNC_OP. If specified, the server returns immediately, rather than waiting for the consistency check to complete.

To force the KCC execution, the script command line would be as follows:

 1:   C:\>WMIADRepl.wsf /ExecuteKCC+ 2:   Microsoft (R) Windows Script Host Version 5.6 3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. 4: 5:   KCC execution requested. 6: 7:   Completed. 

Another interesting method is the SyncNamingContext method exposed by the MSAD_ReplNeighbor class. With this method it is possible to force the replication of a specific Active Directory naming context. The MSAD_ ReplNeighbor class exposing the SyncNamingContext method is a wrapper of the DsReplicaSync() API. Therefore, the method requires the same parameters as the API (see Table 3.57). These parameters are defined in constants at line 60 (see Sample 3.57).

Table 3.57: The SyncNamingContext Method Parameters

Parameter name

Values

Description

Options

DS_REPSYNC_ASYNCHRONOUS_OPERATION

0x1

Perform this operation asynchronously. Required when using DS_REPSYNC_ALL_SOURCES

DS_REPSYNC_WRITEABLE

0x2

Writeable replica. Otherwise, read-only.

DS_REPSYNC_PERIODIC

0x4

This is a periodic sync request as scheduled by the admin.

DS_REPSYNC_INTERSITE_MESSAGING

0x8

Use intersite messaging.

DS_REPSYNC_ALL_SOURCES

0x10

Sync from all sources.

DS_REPSYNC_FULL

0x20

Sync starting from scratch (i.e., at the first USN).

DS_REPSYNC_URGENT

0x40

This is a notification of an update that was marked urgent.

DS_REPSYNC_NO_DISCARD

0x80

Don't discard this synchronization request, even if a similar sync is pending.

DS_REPSYNC_FORCE

0x100

Sync even if link is currently disabled.

DS_REPSYNC_ADD_REFERENCE

0x200

Causes the source DSA to check if a reps-to is present for the local DSA source sends change notifications (aka the destination). If not, one is added. This ensures that source sends change notifications.

To force a naming context replication, the script command line would be as follows:

 C:\>WMIADRepl.wsf /SyncNC:CN=Configuration,DC=LissWare,DC=Net Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. Naming Context 'CN=Configuration,DC=LissWare,DC=Net' synchronization requested. Completed. 

The use of these two methods is shown in Sample 3.59. Lines 300 through 312 illustrate the ExecuteKCC method invocation, while lines 315 through 329 show the SyncNamingContext method invocation.

Sample 3.59: Triggering the KCC and forcing a Naming Context replication (Part III)

start example

 ...: ...: ...: 299:    ' - ExecuteKCC -------------------------------------------------------------------------- 300:    If boolExecuteKCC Then 301:       Set objWMIInstances = objWMIServices.InstancesOf ("MSAD_DomainController") ...: 304:       If objWMIInstances.Count = 1 Then 305:          For Each objWMIInstance In objWMIInstances 306:              objWMIInstance.ExecuteKCC cExecKCCTaskID, cExecKCCFlags 307:          Next 308:          WScript.Echo "KCC execution requested." & vbCRLF 309:       Else 310:          WScript.Echo "No information available." & vbCRLF 311:       End If 312:    End If 313: 314:    ' -- Sync --------------------------------------------------------------------------------- 315:    If boolSyncNC Then 316:       Set objWMIInstances = objWMIServices.ExecQuery ("Select * From MSAD_ReplNeighbor " & _ 317:                                                       "Where NamingContextDN='" & _ 318:                                                       strSyncNC & "'") ...: 321:       If objWMIInstances.Count = 1 Then 322:          For Each objWMIInstance In objWMIInstances 323:              objWMIInstance.SyncNamingContext cSyncNCOptions 324:          Next 325:          WScript.Echo "Naming Context '" & StrSyncNC & "' synchronization requested." & vbCRLF 326:       Else 327:          WScript.Echo "No corresponding context to synchronize." & vbCRLF 328:       End If 329:    End If 330: 331:    WScript.Echo "Completed." ...: 337:    ]]> 338:    </script> 339:  </job> 340:</package> 

end example

Note the scripting technique used to retrieve the naming context to synchronize (lines 316 through 318). The script executes a WQL data query with the naming context given on the command line to locate its corresponding WMI instance.




Leveraging WMI Scripting
Leveraging WMI Scripting: Using Windows Management Instrumentation to Solve Windows Management Problems (HP Technologies)
ISBN: 1555582990
EAN: 2147483647
Year: 2003
Pages: 82
Authors: Alain Lissoir

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net