WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Eight Reasons Windows Administrators Should Learn JScript Instead of VBScript
Pages: 1, 2

Reason #6: JScript Arrays Are Much More Powerful

Arrays have always been a sore spot in the VBScript language. They're inflexible and can only be resized provided that the array was defined without a fixed number of elements (e.g., you can't add a sixth element to an array that was declared as having only five elements, and you can't expand it either). For example, consider the following VBScript code:




Dim MyArray(4)       ' Declares an array that can only ever contain 5 elements
MyArray(5) = "Test"  ' Raises an error; the array can only hold 5 elements
ReDim MyArray(6)     ' Also raises an error; the array was declared with a fixed size

You can create a dynamically resizable array in VBScript, but this is a two-step process; you have to first declare the array, and then you have to resize it to hold the correct number of elements:


Dim MyArray()
ReDim MyArray(5)     ' Resizes the array to contain 6 elements
MyArray(5) = "Test"  ' Assign a value to the 6th element in the array

If you want to use a VBScript array to contain a variable number of items read from a loop (e.g., an array of File objects retrieved from the FileSystemObject's Files collection), you will need to periodically resize the array using the ReDim statement with the Preserve keyword. (For performance reasons, you probably wouldn't want to ReDim after each loop iteration.)

In JScript, arrays are an object type, are dynamic in nature, and provide a list of methods to manipulate them. For example, the push and pop methods append items to and remove items from an array, automatically resizing it in the process. JScript arrays also have a sort method that supports a user-defined ordering function. For ActiveX objects that return VBScript-style arrays (JScript calls these SafeArrays or VBArrays), the Array object has a toArray method that converts the SafeArray into a JScript array.

In fact, it seems that Microsoft created the scripting runtime's Dictionary object to overcome the limitations of the VBScript array data type. I've found that since I've been writing code in JScript, there's only one case in which I've needed the Dictionary object: to return a SafeArray object from a JScript array (oddly, this capability isn't built in). For example:


function toSafeArray(arrayObject) {
  var dict = new ActiveXObject("Scripting.Dictionary");
  for (var n = 0; n < arrayObject.length; n++)
    dict.Add(arrayObject[n], "");
  return dict.Keys();  // The Keys method returns a SafeArray
}

SafeArrays are sometimes required when using ActiveX components, and I use a function like the one above when I need to convert a JScript array into a SafeArray.

Reason #7: JScript Date Handling Avoids Local Time Problems

In VBScript, a date value is always "local." Depending of the source of the date, this can result in UTC (Universal Coordinated Time, aka GMT) and daylight saving time errors when calculating dates. Let's consider a practical example.

The pwdLastSet Active Directory (AD) user attribute is stored as a number of 100-nanosecond intervals since 12:00am January 1, 1601, UTC. Here's a VBScript example of how to convert the pwdLastSet value to a VBScript date:


Dim UserDN, ADsUser, LastSet, NanoSecs, VBTime
UserDN = "CN=John Smith,OU=Sales,DC=wascorp,DC=net"
Set ADsUser = GetObject("LDAP://" & UserDN)
Set LastSet = ADsUser.pwdLastSet
NanoSecs = (LastSet.HighPart * (2 ^ 32)) + LastSet.LowPart
VBTime = CDate(#1/1/1601# + (NanoSecs / 600000000 / 1440))  ' Returns UTC time

This script fragment connects to John Smith's user account object in AD, and retrieves the account's pwdLastSet property. (The Set statement is required because the pwdLastSet value is returned as an object.) Next, the code converts the pwdLastSet value into a single 32-bit value by reading its HighPart and LowPart properties. (This conversion is only an approximation, but we'll let that pass for now.) Finally, the code adds this number of days to 12:00am January 1, 1601, to obtain the final result.

The resulting value is in UTC, and VBScript provides no way to convert this date to local time. Some examples I've seen kludge around this problem by reading the local time offset from the registry and adjusting the date to local time. This is an assumption-laden and brittle solution, because 1) it assumes that the account running the script has permission to read the registry value, 2) it assumes the registry value never changes, and 3) it does not account for daylight saving time (DST) offsets if the resulting date falls before or after a DST change. For example, if we're calculating the date and time a user's password is going to expire in the future, the current local time offset may be inaccurate for the future date if the future date occurs after a DST change takes effect.

In JScript, dates are handled by the Date object. Date objects are natively stored as an offset in milliseconds before and after 12:00am 1 January 1970 UTC. Here's equivalent code in JScript:


var userDN, aDsUser, lastSet, nanoSecs, jsTime;
userdn = "CN=John Smith,OU=Sales,DC=wascorp,DC=net";
aDsUser = GetObject("LDAP://" + userDN);
lastSet = aDsUser.pwdLastSet;
nanoSecs = ((lastSet.HighPart * (Math.pow(2, 32))) + lastSet.LowPart);
jsTime = new Date(Date.UTC(1601, 0, 1, 0, 0, 0, nanoSecs / 10000));  // Natively stored as UTC

This code starts out doing the same thing as the VBScript code--it copies the pwdLastSet value into a single 32-bit value. However, notice how the last line of code uses the UTC method of the Date object to construct a UTC date. The nice part is that when you retrieve this value, JScript knows how to convert it to local time.

I performed this test using a user account on my own domain. VBScript reported 16 May 2007 15:12, and JScript reported 16 May 2007 09:12. Notice that JScript's result is already correct with respect to local time: 9:12 instead of 15:12 because my local time zone is six hours earlier (including the one-hour DST offset) than UTC.

Reason #8: JScript Has Better Exception Handling

VBScript has a crude exception handling mechanism made up of two programming statements. On Error Resume Next disables the default error handler, and On Error GoTo 0 enables the default error handler. If an error occurs after you disable the default error handler, VBScript updates the properties of the Err object. This means that if you have a sequence of successive statements that might raise an error, you will have to check the Err object after each statement, and only continue if the Err object's Number property is zero. For example:


On Error Resume Next
Dim FSO, TS
Set FSO = CreateObject("Scripting.FileSystemObject")
Set TS = FSO.CreateTextFile("C:\Logfile.csv")
If Err = 0 Then
  TS.WriteLine("LastName,FirstName,Email")
  If Err = 0 Then
    LogData
  End If
  TS.Close()
End If

The above code tries to create a text file; if this succeeds, then it tries to write a line of text to the file. The script will only execute the LogData function if the WriteLine method succeeds. It can be difficult to follow the script's logic if you need to check for multiple errors.

In contrast, JScript uses block-based exception handling that makes it simpler to handle errors without having to check for errors after each statement. The JScript equivalent of the above code looks like this:


var FSO, TS;
FSO = new ActiveXObject("Scripting.FileSystemObject");
try {
  TS = FSO.CreateTextFile("C:\Logfile.csv");
  TS.WriteLine("LastName,FirstName,Email");
  logData();
  TS.Close();
}
catch(err) {
  // Put error-handling code here
}

The try { ... } block indicates code that might generate an error. If an error occurs, the flow of the script jumps to the catch block. The err variable will contain an object that contains the details of the error.

JScript also supports a finally block, after the try and catch blocks, that contains statements that are guaranteed to execute after the try block (and the catch block, if an error occurs). This can be useful when, for example, the script needs to free a resource regardless of whether an error occurred.

Conclusion

JScript is the best language for Windows automation that's built into the operating system. In this article, I've outlined eight reasons why it's superior to VBScript. Windows administrators will be well served in learning this powerful language.

Bill Stewart is the systems administrator for French Mortuary in Albuquerque, NM, and has published numerous articles, mainly about Windows scripting.


Return to Windows DevCenter.