Do you have a scripting-related question or problem? You can send your question or problem to [email protected].
I have a script that uses the Microsoft Windows NT Server 4.0 Resource Kit utility dumpel.exe to load and format event-log data in Microsoft Excel. The script works well, but I'd like to programmatically sort the events by date and time in descending order instead of the default ascending order. The Excel object model provides a Sort method, but I can't figure out the correct syntax to successfully call Sort in VBScript code. I tried the script in Listing 1 without success. I also tried enclosing the parameter list in parentheses and omitting the named parameter tags without success. What am I doing wrong?
Excel's Sort method uses a concept called named parameters. Named parameters provide a mechanism in which you don't have to provide values for unused optional parameters or parameters that provide an acceptable default value. Although you can use named parameters with Visual Basic for Applications (VBA), VBScript doesn't natively support named parameters.
Because VBScript doesn't support named parameters, you must follow two guidelines to successfully use the Sort method in VBScript code. First, you must omit the parameter names that appear to the left of the := operator, which means you also delete the := operator. Second, you must provide a placeholder for all parameters, including optional parameters and parameters with default values. You code parameters with no values as blank entries.
Listing 2 contains the modified script. Listing 2 is similar to Listing 1, with a few exceptions:
- As callout A in Listing 2 shows, you define the applicable Excel constants. You must define external constants in Windows Script Host (WSH) scripts unless you use the <object> or <reference> elements that are part of the new WSH 2.0 XML-based script format.
- As callout B in Listing 2 shows, you open the Comma Separated Values (CSV) file that dumpel.exe generated.
- After activating and selecting the region you want to sort, you call Excel's Sort method. This method's syntax is
expression.Sort(Key1, Order1, _ Key2, Type, Order2, Key3, _ Order3, Header, OrderCustom, _ MatchCase, Orientation, _ SortMethod)
Although you're not using the Type, Key3, and Order3 parameters, you must provide blank placeholders for them in VBScript code. Callout C in Listing 2 shows the correct way to call the Sort method in VBScript without providing values for Type, Key3, and Order3. With these changes, the script now programmatically sorts the events by date and time in descending order, as Figure 1 shows.
At my company, each department has an IT liaison who is responsible for that department's user administration. Each liaison has an account. For example, the person responsible for user administration in the human resources (HR) department might have an account named HRLiaison. I created organizational units (OUs) for each department and now want to use VBScript and Microsoft Active Directory Service Interfaces (ADSI) to delegate rights to only User objects in the OUs. If I understand the ADSI security methods correctly, I need to specify the User object's globally unique ID (GUID) in the access control entry's (ACE's) ObjectType property to tell ADSI that I want to grant access to only that specific object type. How do I get the GUID of the User object?
Every defined class and attribute in the Active Directory (AD) schema has a mandatory property named schemaIDGUID. The GUID that you assign to an ACE's ObjectType property is the schemaIDGUID of the specific object or property you want to delegate control of.
The schemaIDGUID property is a 128-bit value that uniquely identifies every schema class and every schema attribute. However, you must set the ACE's ObjectType property to the string representation of the schemaIDGUID for the object or property you're delegating control of. In your case, the value for the ACE's ObjectType property must be the string representation of the schemaIDGUID for the User class. Delegate.vbs in Listing 3 demonstrates how to set this property.
You begin by defining the constants you need to initialize the new ACE. You then bind to the HR OU in the acme.com domain, as callout A in Listing 3 shows. Next, you retrieve the OU's Security Descriptor (SD) and discretionary access control list (DACL).
You're now ready to add a new ACE to the DACL, but you must first create the new ACE and initialize its properties with the constants you defined earlier. As callout B in Listing 3 shows, you're granting access (oAce.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT) and Read and Write permissions (oAce.AccessMask = ADS_RIGHT_GENERIC_READ Or ADS_ RIGHT_GENERIC_WRITE) to objects for the user named HRLiaison in the Acme domain (oAce.Trustee = "acme\hrliaison"). The AceFlags property specifies that child objects in the OU will inherit the ACE, and the Flags property states that the ObjectType property identifies the type of object to which the ACE will apply.
Next, you initialize the ObjectType property to the string representation of the schemaIDGUID for the User class with the code at callout C in Listing 3. The result is an ACE that grants Acme\HRLiaison Read and Write permissions of only User objects that reside in or beneath the HR OU. The script's last four lines add the new ACE to the DACL, write the DACL to the OU's SD, update the SD in the property cache, and commit the modified SD to the directory.
To retrieve the schemaIDGUID programmatically, you must access the schema. Unfortunately, you can't use VBScript alone to access this value. The directory stores the schemaIDGUID as a binary octet string. VBScript doesn't know how to interpret an octet string, let alone convert it to a string representation. The good news is that schemaIDGUID values are published; the bad news is that you'll have to hard-code the values in your script. You can find the schemaIDGUID string representations for all of AD's built-in classes and attributes in Volume 5: Active Directory Schema of the Active Directory Developer's Reference Library, which is available from Microsoft Press. (For more information, go to http://mspress.microsoft.com/books /4281.htm.)
You have another option if you prefer not to purchase a copy of the five-volume Active Directory Developer's Reference Library. You can create an ActiveX component to fetch the schemaIDGUID, then use the StringFromGUID2 Win32 API to convert the schemaIDGUID to a string. This approach requires that you have Visual Basic (VB), know how to use VB to create ActiveX components, and know how to use VB to call a Win32 API. Although this activity is beyond the scope of general scripting, I created a standard executable called ADsType .exe and an ActiveX component called ADsType.dll that you can use to fetch schemaIDGUID string representations. You can download ADsType.exe and ADsType.dll from the Code Library on the Win32 Scripting Journal Web site (http://www.win32scripting.com/).
ADsType.exe is simple to use. Start by running ADsType.exe. When the ADsType Conversion (schemaIDGUID) dialog box in which Figure 2 appears, enter the name of the target class or attribute schema object, and click the Get schemaIDGUID button. ADsType.exe will then bind to the specified object in the local domain's schema container, retrieve the value of the object's schemaIDGUID, and pass the value to the StringFromGUID2 Win32 API. StringFromGUID2 converts the binary octet value to a string and returns it to the calling program, which writes the string back to the ADsType Conversion (schemaIDGUID) dialog box, as Figure 3 shows.
ADsType.dll performs the identical conversion function as ADsType.exe, but performs that function in a way that is more script friendly. The only caveat is that, like any ActiveX component, you must register ADsType.dll on the computer on which you'll use the component. To register and test ADsType.dll, perform these steps:
- Copy ADsType.dll to your favorite component directory, and execute the code
regsvr32 adstype.dllIf the registration is successful, regsvr32 will echo the message DllRegisterServer in adstype.dll succeeded.
- Run the test script GetSchemaIDGUID.vbs in Listing 4 by typing
C:\>cscript getschemaidguid.vbsat a command prompt. Providing all goes well, you'll see output similar to that in Figure 4, page 7.
- Incorporate the ActiveX component in your script. Replace the line of code at callout C in Listing 3 with the code in Listing 5, page 7. By replacing the code, you'll eliminate Listing 3's dependency on the hard-coded schemaIDGUID.
Although the focus here is on delegating control to an entire object, the same concepts and rules apply for individual properties.