Error handling in Windows scripts

The most common type of errors we encounter is a run-time errors. Run-time errors occur while a script is running and are the results of the script trying to perform an invalid operation, such as creating an existing file, accessing an invalid device, etc. In this section we will discuss how JScript scripts can handle those errors.

The try...catch...finally statement

JScript has a special try...catch statement to handle errors. The general syntax if this statement is
try{
   try_statements;
}
catch( exception ){
   error_handling_statements;
}
[
finally{
   final_statements;
}
]
The try...catch…finally statement provides a way to handle some or all of the possible errors that may occur in a given block of code, while still running code. If errors occur that the programmer has not handled, JScript simply provides its normal error message to a user, as if there was no error handling.

The try_statements contain code where an error can occur, while error_handling_statements contain the code to handle any error that does occur. If an error occurs in the try_statements, program control is passed to error_handling_statements for processing. The initial value of exception is the value of the error that occurred in try_statements. If no error occurs, error_handling_statements are never executed.

If the error cannot be handled in the error_handling_statements associated with the try_statements where the error occurred, use the throw statement to propagate, or rethrow, the error to a higher-level error handler.

After all statements in try_statements have been executed and any error handling has occurred in error_handling_statements, the statements in final_statements are unconditionally executed.

Notice that the code inside final_statements is executed even if a return statement occurs inside the try or catch blocks, or if the catch block re-throws the error. final_statements are guaranteed to always run, unless an unhandled error occurs (for example, causing a run-time error inside the catch block).

The Error object

The Error object contains information about errors. To create a new instance of this object we need to use operator new:
errorObj = new Error([error_code[, description]]);
where Whenever a run-time error occurs, an instance of the Error object is implicitly created to describe the error. This instance has two intrinsic properties that contain the description of the error (description property) and the error number (number property).
An error number is a 32-bit value. The upper 16-bit word is the facility code, while the lower word is the actual error code.
Error objects can also be explicitly created, using the syntax shown above, or thrown using the throw statement. In both cases, you can add any properties you choose to expand the capability of the Error object.
Typically, the local variable that is created in a try...catch statement refers to the implicitly created Error object. As a result, you can use the error number and description in any way you choose.

The following example shows how to create a code that opens a file and checks for any errors. If an error occurs, the script will print an error message that includes the error code and description:

var fs = new ActiveXObject("Scripting.FileSystemObject");
try{
   var fname = WScript.Arguments(0); // may cause an error if script argument is not given
   var file = fs.GetFile(fname);     // may cause an error if file doesn't exist
   var fstr = file.OpenAsTextStream(2); // may cause an error if file is Read-Only
   fstr.WriteLine("new line\n");
   fstr.Close();
}
catch( e ){
   var code = e.number & 0xFFFF;
   var msg = "Error " + code + ": " + e.description;
   var sh = WScript.CreateObject("WScript.Shell");
   sh.Popup(msg, 0, "Run-time error in the script "+WScript.ScriptName, 16);
}
In this example we are using implicitly created Error object. We accessing its properties number and description to get some information about the error occurred. To retrieve the 16-bit error code from the 32-bit property number we use binary operator &. Some standard error codes and descriptions are in the table below.
Error code Description
5 Invalid procedure call or argument
6 Overflow
7 Out of memory
9 Subscript out of range
10 This array is fixed or temporary locked
11 Division by zero
13 Type mismatch
14 Out of string space
17 Can't perform a request operation
28 Out of stack space
35 Sub or Function not defined
48 Error in loading DLL
51 Internal error
52 Bad file name or number
53 File not found
54 Bad file mode
55 File already open
57 Device I/O error
58 File already exists
61 Disk full
62 Input past end of file
67 Too many files
68 Device unavailable
70 Permission denied
71 Disk not ready
74 Can't rename with different drive
75 Path/File access error
76 Path not found
91 Object variable or with block variable not set
92 for loop not initialized
93 Invalid pattern string
94 Invalid use of null
322 Can't create necessary temporary file
424 Object required
438 Object doesn't support this property or method

If we need to create our own exception (for example, file provided by the user does exists, but has a wrong type), we can create our own Error object and throw it as an exception using operator throw.

var fs = new ActiveXObject("Scripting.FileSystemObject");
var file;

try{
   file = fs.GetFile( WScript.Arguments(0) );
   if( file.Type != "Microsoft Word Document" ){
      var err = new Error(5001, "Wrong type of the file. Microsoft Word Document is needed.");
      throw err;
   }
   WScript.Echo("Pretend I'm starting MS Word now ...");
}
catch( e ){
   WScript.Echo( "Error "+(e.number&0xFFFF)+": "+e.description );
}

If there are some instructions we need to execute no matter whether an error occurred or not (for example close an application or disconnect a network drive), then we need to put these instructions inside the finally part of the try statement. This optional part contains t instructions that will be executed in either case. Please add these lines to the example above see how it works

finally{
   WScript.Echo("This statement always displayed");
}

Nested try...catch statements

In the case when an error is not handled in the catch part of a try statement or is rethrown, this exception will be sent to the catch part of a higher level try or to the JScript itself (if there is no higher level try, in this case standard error message will be printed). Please take a look at the Microsoft try...catch...finally example.


References