Windows DevCenter    
 Published on Windows DevCenter (http://www.windowsdevcenter.com/)
 See this if you're having trouble printing code examples


Eight Reasons Windows Administrators Should Learn JScript Instead of VBScript

by Bill Stewart
06/19/2007

When Windows NT was first released, Microsoft did not provide much in the way of automation except for the Cmd.exe shell. You could always install third-party tools such as Perl (and this is still the case), but the operating system didn't provide much built-in scripting functionality. This changed, though, with the release of the Windows Script Host (WSH) and HTAs (HTML applications). One nice advantage of both WSH scripts and HTAs is that they're both built into the OS on Windows 2000 and later. There are two built-in languages you can use to write WSH scripts or HTAs: VBScript and JScript.

Some administrators have opted for other languages (such as Perl or Python), and Microsoft has itself initiated a new direction with the creation of PowerShell. These are great choices, but they're not built into the operating system, and it's often important to be able to manage the lowest common denominator (e.g., a machine on which you can't install PowerShell). A logon script is a good example: if you write it in Perl, only machines that have a Perl interpreter installed can execute it. PowerShell, while very powerful, has a pretty high barrier to entry (Windows XP service pack 2 or later, and .NET 2.0). By contrast, a WSH script written in VBScript or JScript will run without any prerequisites on Windows 2000 and later (and even on down-level machines that are running Internet Explorer 5.0 or later).

Since most Windows administrators will need to write WSH scripts anyway, it makes sense to use the best language for the job: JScript.

Reason #1: JScript Is More Widely Used

In my experience, there seems to be confusion about what JScript is. In the simplest terms, JScript is Microsoft's implementation of the ECMA-262 specification, which describes a scripting language called ECMAScript. JavaScript and JScript are the two most widely used implementations of the ECMAScript specification. JScript is currently equivalent to JavaScript 1.5, with the exception of a few proprietary extensions that facilitate COM programming. (Note that JScript .NET is a different language, and is beyond the scope of this article.)

The JavaScript/JScript language is used in many different applications on different platforms--most notably, in web browsers. Other vendors have also used it as an automation language (e.g., Adobe). In other words, JScript knowledge can be leveraged in more places. VBScript, by comparison, is proprietary to Microsoft and is only available in Microsoft applications on the Windows platform that use the VBScript interpreter.

Reason #2: JScript Is Alive and Well

As I mentioned above, JScript is based on the ECMA-262 standard. Although the current version of JScript is equivalent to JavaScript 1.5, the upcoming JavaScript 2.0 specification will be backward-compatible with JavaScript 1.5. If JavaScript 2.0 gains wide acceptance, Microsoft will need to update JScript to maintain browser compatibility.

By comparison, VBScript is in a state of "sustained engineering" with Microsoft. This means that Microsoft will only fix major bugs and security holes in the VBScript interpreter; it's not going to be adding any new features or extending the language for other uses. Since VBScript is on life support, it makes more sense to invest in learning a language that has a future.

Reason #3: JScript Is Easy to Learn

One of the reasons VBScript is so widely used in Windows administration is that VBScript has a reputation for being easy to learn. For some reason, this has given JScript a reputation for being hard to learn. This is probably due in part to the fact that JScript's C-like coding style looks different from VBScript. However, once you get past the basics, JScript is easy to learn in its own right. Many of the basic concepts are the same (statements, variables, functions, etc.); they just look different. Once you learn the fundamentals of the language, it's very easy to get your scripting work done using JScript instead of VBScript. Like most Windows scripting authors, I started out using VBScript, but I found that JScript was just as easy to learn as VBScript, even though some of its programming concepts are different.

Reason #4: JScript Is Object-Oriented

JScript is built from the ground up as an object-oriented language. Built-in data types (such as strings and numbers) are themselves objects that have methods. For example, numbers have a toString method that returns the number as a string, and strings have the toUpperCase and toLowerCase methods to return the strings in upper- and lowercase.

It's also easy to create your own objects with minimal code. Consider this example:

var options = { path: "", recurse: false };

This single line of code creates an unnamed object containing two properties and initializes the properties.

You can create a user-defined object in VBScript, but it's a lot more complicated. The language forces you to create a class and an initialization subroutine, like this:


Class OptionsClass
  Public Path
  Public Recurse
  Private Sub Class_Initialize()
    Path = ""
    Recurse = False
  End Sub
End Class

Dim Options
Set Options = New OptionsClass  ' Creates an instance of the class

JScript's object-oriented nature makes this a simple task; VBScript requires quite a bit more code to accomplish the same thing.

JScript also lets you create a named object (which VBScript forces you to do); if you need more than one of these objects, you can simply define a constructor function that defines the object. For example:


function optionsObject(path, recurse) {
  this.path = path;
  this.recurse = recurse;
}

var options = new optionsObject("c:\\winnt", true);  // Creates an instance of the object

JScript uses prototype-based, rather than class-based, inheritance. Using the prototype property of an object, you can extend an object's behavior by adding a method to its prototype property. For example:

Array.prototype.exists = function(item) {
  for (var n = 0; n < this.length; n++)
    if (item == this[n]) return true;
  return false;
}

The above code adds the exists method to the Array object. Here's an example of how you'd use the new method:

var myArray = ["a", "b", "c", "d"];  // Defines an array containing four elements
var result = myArray.exists("a");    // Returns true
var result = myArray.exists("e");    // Returns false

This example illustrates how flexible the JScript language is and how it's simple to extend either your own or built-in objects with custom methods.

Reason #5: JScript's Regular Expression Handling Is Better

Regular expressions are a natural part of JScript; they're built into the language's syntax. Regular expression support wasn't added to VBScript until version 5 of the language and, as a result, the syntax is comparatively verbose and awkward. For example, suppose you want to check whether a string looks like an email address using a regular expression. In VBScript, you have to use the New keyword with the Set statement to create a RegExp object, and configure its properties for the search. Here's a code sample:


Address = "foo@bar.com"
Set RE = New RegExp
With RE
  .Pattern = "\w+@\w+\.\w+"
  .IgnoreCase = True
End With
Result = RE.Test(Address)  ' Evaluates to True

The equivalent JScript code is more concise:

var address = "foo@bar.com";
var RE = /\w+@\w+\.\w+/gi;
var result = RE.test(address);  // Evaluates to true

The second line of code, above, creates a RegExp object. The /expression/ syntax is a convenient way to describe a regular expression pattern when you know the pattern before the code gets executed. Alternatively, you can create RegExp objects using the new operator, like this:

var address = "foo@bar.com";
var RE = new RegExp("\\w+@\\w+\\.\\w+", "i");  // \ is JScript's escape character, so '\\' = '\'
var result = RE.test(address);                 // Evaluates to true

This syntax is useful when you want to describe a regular expression pattern at runtime. In addition, JScript RegExp objects have a compile method that provides for increased performance when using them repeatedly, such as in a loop.

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.

Copyright © 2009 O'Reilly Media, Inc.