Search code examples
javascriptjscriptinternalwsh

Prevent an internal Function execution stopping the main execution


background

I have a JScript script running under WSH.

The script is fairly simple. It iterates over a list of strings, each string, a JScript itself, and run each "internal" script.

Problem

It is possible that some "internal" script, may call Quit method. This causes the main script to stop, which is not desired.

Simple example

var strSomeScript = "WScript.Quit(1)";

var F = new Function(strSomeScript);
var exitCode = (F)();

WScript.Echo("Continue doing more things...");

the last line will not be executed since the "internal" script stops the execution.

Question

If I have no control over the content of the "internal" scripts, how can I prevent them from breaking my main flow.

Requirements

I need to run each "internal" script, wait for it to finish and store its exit code.


Solution

  • If you want only to prevent specifically WScript.Quit calls you can simply sanitize your input with a simple replace. (*) If you want to be able to prevent any way of stopping the script - for example, var x = WScript; x.Quit(); - you're basically trying to solve the halting problem, which I hear is kind of hard.

    If you were using regular JS you could have tried something like:

    WScript.Quit = function(e) {
        // Assume there's something reasonable to put here
    };
    

    or:

    var __WScript = WScript;
    WScript = { ConnectObject: function(obj, pref) { __WScript.ConnectObject(obj, pref); },
                CreateObject: function(progid, pref) { __WScript.CreateObject(obj, pref); },
                ... };
    

    But the WScript object doesn't implement IDIspatchEx etc. so that won't work.

    The only way do make sure an arbitrary string, when interpreted as JavaScript code, doesn't end your script is not to eval that string as part of your script, but rather run it in a brand new context. (And calling the Function contrcutor on that string and then calling the resulting object is pretty much the same as evaling it.)

    You can write it to a file and execute wscript.exe with this file as argument, or use the Microsoft Script Control if you don't want to write a file to disk and/or want to give the script access to objects from the parent script.


    (*) Not that this makes any sense either way. Lets even say that your only problem is WScript.Quit. What are you going to put instead? return? That's not going to cut it:

    function bar(a) {
        if (Pred(a)) {
            WScript.Quit(123);
        }
        return 456;
    }
    
    function foo() {
        var x = bar(789);
        if (!x) {
            DoSomethingBad();
        }
    }
    
    foo();
    

    A script that used to end silently now does something bad. If you "know" that changing the WScript.Quit to return doesn't do anything bad you should also know that there aren't any WScript.Quits in the code in the first place.

    There's simply nothing sensible you can do instead quitting even if you could catch every call to WScript.Quit.