Creating User Interfaces in Windows Scripting Host

There are several ways for system administrators to collect input from users via a logon script and each has its advantages. The process we will be exploring in this post has the advantages that it is not does not require security reconfiguration as when working with HTA (HTML Applications) files and it allows the administrator an array of more diverse, normalized input methods. This input data can then be captured and used with Windows Scripting Host’s (WSH) natively built-in functions. Doing things like giving users that frequently moving between departments the ability to select from a list where they’re working and then appropriately configuring disk and printer mappings is straightforward using this method. This way of getting user input can be helpful when users frequently move between workstations or when published applications on a Citrix or RDS environment are being used.

The intended audience for this post is Windows system administrators with experience in scripting. In you do not have any experience with this technology visit  here for an introduction to WSH. There are two scripting languages supported by WSH and the following examples will use both; depending on your background there may be an advantage of choosing one over the other for this type of information gathering. The first scripting language VBscript (Visual Basic Script) is heavily used by system administrators and example code is for it abundant online. This option may best serve your purposes if the style of script authoring you leverage commonly includes finding sample code online. If you also have no web development background this may be the more comfortable option to work with. The second option is Jscript which is syntactically identical to what is popularly known as JavaScript (or more pedantically ECMAscript) and is wildly popular all over the Internet and is supported by numerous web browsers. If you have experience with JavaScript then Jscript will feel very familiar and have the added benefit of lending itself to the development of Dynamic HTML (DHTML) in a way that is already natural. Ordinarily it would not make sense to explain to this audience the difference between VBscript and Jscript but on the off chance the reader has web development experience it is important.

DHTML

Dynamic HTML loosely speaking is a collection of technologies that allow for the creation of interactive web pages using the primitive HTML objects users interact with. As an example a web developer may create a static HTML page without a BUTTON element for submission of a form. In the DHTML approach the web page may have loaded page without any buttons, but after a user has filled all of the fields in the form a JavaScript function may cause one to be created and attached to the HTML page that was not there previously.

The object used to accomplish this web browsers is the Document Object Model (DOM) which is a predefined set of HTML elements, properties and methods. The features of the DOM are documented and available publicly on MSDN and our examples will leverage several of them. Instead of using scripting inside of the browser to work with the DOM we will use WSH and its automation capabilities.

Step 1 – WSH is in Charge of Internet Explorer

The user interface for our script will be Internet Explorer—for our purposes this browser is well documented and the automation integration with Windows and availability makes it an obvious choice. What is being accomplished here may be possible with alternative browsers but that will not be explored here. Internet Explorer in this case is the useful lowest common denominator because with the exception certain editions of Windows used in Europe this code will natively work on all Windows systems without any enhancements being necessary. The following code will create Internet Explorer, navigate immediately to a blank page, and make it visible to the user.

VBScript:

Set objInternetExplorer = WScript.CreateObject("InternetExplorer.Applicaiton", "MAINIE_")
objInternetExplorer.Navigate("about:blank")
objInternetExplorer.Visible = True


JScript:

var objInternetExplorer = WScript.CreateObject("InternetExplorer.Application", "MAINIE_");
objInternetExplorer.Navigate("about:blank");
objInternetExplorer.Visible = true;

Running these snippets of code will cause Internet Explorer to appear on screen for the user and that navigation to the page about:blank, which is important. That page will be the canvas our user interface will be built upon. Expanding on that code there are customizations of Internet Explorer we may want to include as this is a script running with limited user input and therefore we do not want features like the address bar or a back button presented. The following additions will give our about:blank document a title, fix the Internet Explorer window dimensions, take away the user’s ability to resize the window, and remove the tool and status bars.

VBScript:

Set objInternetExplorer = WScript.CreateObject("InternetExplorer.Applicaiton", "MAINIE_")
objInternetExplorer.Navigate("about:blank")
objInternetExplorer.Document.Title = "Test Script Interface"
objInternetExplorer.ToolBar = 0
objInternetExplorer.StatusBar = 0
objInternetExplorer.Width = 300
objInternetExplorer.Height = 200
objInternetExplorer.Resizable = False
objInternetExplorer.Visible = True


JScript:

var objInternetExplorer = WScript.CreateObject("InternetExplorer.Application", "MAINIE_");
objInternetExplorer.Navigate("about:blank");
objInternetExplorer.Document.Title = "Test Script Interface";
objInternetExplorer.ToolBar = 0;
objInternetExplorer.StatusBar = 0;
objInternetExplorer.Width = 300;
objInternetExplorer.Height = 200;
objInternetExplorer.Resizable = false;
objInternetExplorer.Visible = true;

After running these code snippets there is a noticeable difference in the Internet Explorer experience afterwards. If it were not for the blue E icon it would be difficult for a user to know that Internet Explorer is currently running.

image1

Step 2 – Display Text in Our Window

Next we’re going to add code to create a paragraph block on the canvas and display a simple message. In this this example a simple department selection interface will be created, so the message will read “What department do you work for?”

In order to accomplish this in DHTML we need an object to hold the text inside of our document. The paragraph object in HTML is a simple tag noted by the letter P. The createElement method that belongs to the document creates the element based on the type passed to it as a string parameter. The following code will create a paragraph element, set its text to our message, and then appended the element as a child node to the body of our HTML document.

VBScript:

Set objMyParagraph = objInternetExplorer.document.createElement("P")
objMyParagraph.innerText = "What department do you work for?"
objInternetExplorer.document.body.appendChild(objMyParagraph)


JScript:

var objMyParagraph = objInternetExplorer.document.createElement("P");
objMyParagraph.innerText = "What department do you work for?";
objInternetExplorer.document.body.appendChild(objMyParagraph);

With these lines of code added when the script is run, the DOM is accessed by our first new line creating the paragraph element. This element has nothing useful in it and is not actually attached to our document yet in a meaningful way. The second line of code put text inside the paragraph element which results in the message ultimately displayed and the last line appends our entire paragraph to the body of the document. What we see is the following:

image2

Through this script HTML elements will be appended as child nodes of our document or as child nodes to other nodes. All of the elements seen as the user interface are part of a hierarchy within our document object. This tree can be traversed and managed dynamically by removing and adding elements.

Step 3 – Adding a Button That Does Something

We are going to do steps three and four out of order. This is because a button is simpler to setup and use than a selection list. There are a couple of concepts we will pick up in this step and expand further in the next step.

The same method to create and attach our button will be used that was used to put our paragraph in place but with an additional twist. This time around we will be interested in what happens when our button is clicked; this will be addressed using the onclick property of the button and the way this works is different depending on the scripting language we’re using. Up until this point both scripts have looked remarkably similar.

VBScript:

Set objMyButton = objInternetExplorer.document.createElement("BUTTON")
objMyButton.innerText = "Go!"
objMyButton.onclick = GetRef("cleanUpAndEndScript")
objInternetExplorer.document.body.appendChild(objMyButton)


JScript:

var objMyButton = objInternetExplorer.document.createElement("BUTTON");
objMyButton.innerText = "Go!";
objMyButton.onclick = cleanUpAndEndScript
objInternetExplorer.document.body.appendChild(objMyButton);

This addition will create a button however it will not be usable yet. If you try to run the Jscript at this point it will fail because the cleanUpAndEndScript function is undefined. So let’s create that function and have it do two things for us; firstly it will terminate Internet Explorer and secondly the Windows Scripting Host will be terminated as well.

VBScript:

Sub cleanUpAndEndScript()
       objInternetExplorer.Quit()
       WScript.Quit()
End Sub


JScript:

function cleanUpAndEndScript() {
       objInternetExplorer.Quit();
       WScript.Quit();
}

Now both scripts will run without issue, but if you’re playing along from home you notice that the button does not do anything. You can click it over and over again but WSH is no longer running so there is nothing handling that click event anymore. So we’ll use a trick to keep our script engine running indefinitely, an infinite loop. Place this loop at the end of the script and don’t worry when the user clicks the button our script will shut down as directed by the cleanUpAndEndScript function thusly terminating our loop.

VBScript:

While True
       WScript.Sleep(100)
Wend


JScript:

while (true) {
       WScript.Sleep(100);
}

Now the script will run until the user clicks the button invoking the termination of both Internet Explorer and the script itself. At this point the running script will look like this:

image3

If you have been developing along side-by-side and have run into any bugs or pitfalls prior to now, check your Windows Task Manager to see if you have multiple wscript.exe or cscript.exe processes running in the background. This is a common non-lethal hazard of doing script development where infinite loops are involved.

The two key concepts to walk away with in this step is that first WSH will terminate on us when the end of the script is reached so we need an infinite loop to keep us running and waiting for user events and the second is the handling of the onclick event. The event is a property of the HTML element we want to programmatically manage and the assignment of function to the event differs based on the language being used. For VBscript the GetRef function is used to assign a pointer to another function, whose name is passed as string parameter, for when the event is triggered. Jscript on the other hand simply has us assign the function name to the target event.

Step 4 – Give the User a Choice

From the first paragraph you may remember that I mentioned normalized data. There are easy light weight methods of getting user input natively in WSH but a simple input dialog box could lead to many simple and preventable input errors. A single line of code could be used to capture data from a user input box and return its value to a variable but this may be asking a lot of our users.

In this step we’re going to create a 3-option selection box using DHTML and we will capture the changes made to the selection list in a variable. This last step will tie everything together and sample code that follows will be the complete script with an explanation that follows.

There will need to be four elements added to the canvas of the document in the service of our selection list. One will be the selection list itself and the other three are options that will be appended to our selection list. At this point it is important to again remember we are working with the DOM and to note that the option elements will be created on our document but they will be appended to the selection list node rather than the document itself. Also there are two properties we will need to assign data to on each option and most importantly of all on a property that is used on the selection list.

Each option will have a set text property, which is what the user sees on screen, and then a value property that is programmatically assigned. In this example each department will be assigned an integer for the value property and the corresponding text property. On the selection list the OnChange event will be used such that each time the user changes the selection the variable will subsequently be updated based on their selection. This update event will be assigned to a function or sub (relative to the language used) named selectionUpdate which will update the globally scoped variable named intDepartmentChoice. The variable intDepartmentChoice is scoped globally so our results will be accessible at the time or update and ultimately when the script goes to exit. This leads to the last change to look out for. It is a new line in the cleanUpAndEndScript function. This function now includes a WScript.Echo statement giving us feedback to see that the script has actually collected the user’s input. It is only there for validation purposes.

VBScript:

intDepartmentChoice = 1

'create our Internet Explorer object for use with our script'
Set objInternetExplorer = WScript.CreateObject("InternetExplorer.Application", "MAINIE_")
objInternetExplorer.Navigate("about:blank")
objInternetExplorer.Document.Title = "Test Script Interface"
objInternetExplorer.ToolBar = 0
objInternetExplorer.StatusBar = 0
objInternetExplorer.Width = 300
objInternetExplorer.Height = 200
objInternetExplorer.Resizable = False
objInternetExplorer.Visible = True

'Create a paragraph and append it to Internet Explorer'
Set objMyParagraph = objInternetExplorer.document.createElement("P")
objMyParagraph.innerText = "What department do you work for?"
objInternetExplorer.document.body.appendChild(objMyParagraph)

'Create the selection list and its options'
Set objMySelectionList = objInternetExplorer.document.createElement("SELECT")
objMySelectionList.OnChange = GetRef("selectionUpdate")
Set objOptionAccounting = objInternetExplorer.document.createElement("OPTION")
objOptionAccounting.Text = "Accounting"
objOptionAccounting.Value = "1"
objMySelectionList.add(objOptionAccounting)
Set objOptionIt = objInternetExplorer.document.createElement("OPTION")
objOptionIt.Text = "Information Technology"
objOptionIt.Value = "2"
objMySelectionList.add(objOptionIt)
Set objOptionHr = objInternetExplorer.document.createElement("OPTION")
objOptionHr.Text = "Human Resources"
objOptionHr.Value = "3"
objMySelectionList.add(objOptionHr)
objInternetExplorer.document.body.appendChild(objMySelectionList)

'Create our Go button'
Set objMyButton = objInternetExplorer.document.createElement("BUTTON")
objMyButton.innerText = "Go!"
objMyButton.onclick = GetRef("cleanUpAndEndScript")
objInternetExplorer.document.body.appendChild(objMyButton)

Sub selectionUpdate()
       intDepartmentChoice = Me.Value
End Sub

Sub cleanUpAndEndScript()
       WScript.Echo "The selected value was: " & intDepartmentChoice
       objInternetExplorer.Quit()
       WScript.Quit()
End Sub

While True
       WScript.Sleep(100)
Wend


JScript:

var intDepartmentChoice = 1

//Create our Internet Explorer object for use with our script
var objInternetExplorer = WScript.CreateObject("InternetExplorer.Application", "MAINIE_");
objInternetExplorer.navigate("about:blank");
objInternetExplorer.document.title = "Test Script Interface";
objInternetExplorer.toolbar = 0;
objInternetExplorer.statusbar = 0;
objInternetExplorer.width = 300;
objInternetExplorer.height = 200;
objInternetExplorer.resizable = false;
objInternetExplorer.visible = true;

//Create a paragraph and append it to Internet Explorer
var objMyParagraph = objInternetExplorer.document.createElement("P");
objMyParagraph.innerText = "What department do you work for?";
objInternetExplorer.document.body.appendChild(objMyParagraph);

//Create the selection list and its options
var objMySelectionList = objInternetExplorer.document.createElement("SELECT");
objMySelectionList.onchange = selectionUpdate
var objOptionAccounting = objInternetExplorer.document.createElement("OPTION");
objOptionAccounting.text = "Accounting";
objOptionAccounting.value = 1;
objMySelectionList.add(objOptionAccounting);
var objOptionIt = objInternetExplorer.document.createElement("OPTION");
objOptionIt.text = "Information Technology";
objOptionIt.value = 2;
objMySelectionList.add(objOptionIt);
var objOptionHr = objInternetExplorer.document.createElement("OPTION");
objOptionHr.text = "Human Resources";
objOptionHr.value = 3;
objMySelectionList.add(objOptionHr);
objInternetExplorer.document.body.appendChild(objMySelectionList);

//Create our Go button
var objMyButton = objInternetExplorer.document.createElement("BUTTON")
objMyButton.innerText = "Go!";
objMyButton.onclick = cleanUpAndEndScript
objInternetExplorer.document.body.appendChild(objMyButton);

function selectionUpdate() {
       intDepartmentChoice = this.value;
}

function cleanUpAndEndScript() {
       WScript.Echo("The selected value was: " + intDepartmentChoice);
       objInternetExplorer.Quit();
       WScript.Quit();
}

while (true) { 
    WScript.Sleep(100);
}

At this point it should all come together and your user input will be captured in the variable and the value will be displayed for you to see. For reuse of this code simply edit as necessary.

 image4

An important concept to note in this step is inside the new selectionUpdate function that was added. We do not have the ability to pass parameters to a function called by an event handler, so the Me object must be used in VBscript and the this object in Jscript. Me and this respectively are pointers to the element whose property is assigned the running function. It is the event’s way of reach back up to the caller of the function and in our example’s case getting the value property associated with choice the user has just selected.

Wrapping Things Up

At this it may not—or may not—have noticed already that the user in this scenario still has the ability to close the Internet Explorer window without using the Go button provided. Functions like the following can be used to clean up after our ill-behaved user. When the user closes the Internet Explorer we can leverage the _OnQuit event associated with our web browser instance. Notice that the handle we gave the instance when invoking the web browser originally in step 1 is used in the function name.

VBScript:

Function MAINIE_OnQuit()
      WScript.Quit()
End Function


JScript:

function MAINIE_OnQuit() {
       WScript.Quit();
}

There are tradeoffs to this completely scripted approach versus using HTA files but in many cases not requiring a system reconfiguration on all operating systems alone is enough to justify its use. There is more code work to do in this method, but there is even more that can be done that has not been investigated here; for example DOM features like cascading styles sheets are not touched here but there are many opportunities for improvement with capabilities like corporate branding and user interface customization. To see some of the capabilities of using this method check out the Documentor script on sourceforge.net, this script uses multiple Internet Explorer instances and numerous cascading style sheets to build a user application experience within Window Scripting Host.

Your email address will not be published. Required fields are marked *

Phone: 312-602-4000
Email: marketing@westmonroepartners.com
222 W. Adams
Chicago, IL 60606
Show Buttons
Share On Facebook
Share On Twitter
Share on LinkedIn
Hide Buttons