1. Windows Script Host
The
Windows Script Host is the engine responsible for running scripts.
Rather than a tangible, interactive application like the Command Prompt
or Windows PowerShell , WSH is simply an extensible collection of support files. In
theory, WSH is language-independent, meaning that it can be extended to
support any modern scripting language, such as Perl and Python. Of
course, you can install and run Perl on your PC and then run Perl
scripts completely independently of WSH, but the concept of WSH
integration means that your Perl scripts would have access to all the
WSH objects and services . Regardless,
most WSH scripts end up being written in VBScript.
VBScript
is based on another Microsoft programming language, Visual Basic (VB),
which, in turn, is loosely based on Beginner's All-purpose Symbolic
Instruction Code (BASIC). If you're at all familiar with BASIC, taught
in grade school since the 70s, the fundamentals of VBScript won't be
much of a challenge.
So,
where does WSH end and the VBScript language begin? From the point of
view of the person running the script, WSH starts when you double-click a
script file, at which point it automatically chooses an appropriate
language interpreter based on the script filename extension. From the
point of view of the developer, WSH provides special functionality to
all languages through the use of objects ; that way, each WSH-supported language needn't
bother providing functionality for advanced functions, such as Registry
access and filesystem operations.
2. Build a VBScript Script
A script
is simply a list of commands placed one after another and stored in a
text file. Script commands are like building blocks: the more commands
and programming techniques you learn, the broader your palette will be
for making useful scripts.
To run a script, just double-click on the script file icon; you'll probably never need to run the Scripting Host program (wscript.exe) directly.
There are actually two WSH script interpreters (engines) included with Vista. WScript.exe is a native Windows interpreter and is used in most cases. CScript.exe is a console interpreter, and is used when you want the script output to be sent to the console (Command Prompt). You can use CScript.exe at any time by right-clicking a script file and selecting Open with Command Prompt. |
|
When
the Scripting Host runs the script, the commands are executed in order,
one by one. You can leave a Notepad window open to make changes and
additions while you test the script; big screens are especially handy
for this sort of thing.
You can quickly open an existing script file for editing by right-clicking and selecting Edit. This will, by default, open Notepad, although you might want to associate the Edit action for .vbs files with a more powerful text editor .
The
process of putting a script together essentially involves typing
commands and then running the scripts to test them. Following are the
background concepts necessary to complete many tasks with scripts:
Using variables to store and manipulate informatio.
Asking for and displaying information with the InputBox and MsgBox commands
Creating interactive scripts with conditional statement.
Using loops to repeat a series of command.
Making building blocks with subroutines and function.
Extending scripts with object reference.
2.1. Use Variables to Store and Manipulate Information
The
use of variables is essential when some interaction is required by a
script. A variable can be assigned a value, which is subsequently used
or simply recalled later in the script. For example, the following two
commands:
MyName = "joe user"
MyShoeSize = 12
set two different variables to two different values. The first variable, MyName, is assigned to a text string, while the second, MyShoeSize, is set to a numeric value.
You can also assign variables in terms of other variables:
MyIQ = MyShoeSize + 7
which, when placed after the two preceding lines, would result in the variable MyIQ having a value of 19
(12 plus 7). When a variable name appears on the left side of an equals
sign, its value is being manipulated. When it appears on the right side
of an equals sign or within some other command, its value is simply
being read. You can carry out more complex mathematical operations using
various combinations of parentheses and the standard operators (+, -, *, /, and ^ for addition, subtraction, multiplication, division, and exponentiation, respectively).
2.2. Give Your Scripts an Interface with the InputBox and MsgBox Commands
Some
scripts are ideally suited to run in the background and perform a
sequence of tasks, and then simply exit when those tasks are complete.
Others require some sort of user interaction, either in the form of
asking the user for input or informing the user when something has gone
wrong. For example, this command:
MyName = InputBox("Please enter your name.")
will display a prompt on the
screen when the script is run, asking for some text to be typed. When
you enter some text and click OK, the script places the text you've typed into the variable MyName and continues on to the next command.
Now, collecting and rearranging information does no good without the ability to spit out a result. The versatile MsgBox function allows you to display a simple message, as follows:
MsgBox "Hello, Hello Again."
Combining the principles covered so far, consider the following code:
MyAge = InputBox("Please type your age.")
NewAge = MyAge + 5
MsgBox "In 5 years, you will be " & NewAge & "."
The first line does two things: it first asks the user to type something, and then assigns the typed text to the variable MyAge. The second line creates a new variable, NewAge,
assigns the user's input to it, and adds five. Note the lack of any
error checking in this example: if one enters something other than a
number, this code will cause a WSH error, and the script will end early.
The third line then uses the & operator to concatenate (glue together) a text string to the NewAge variable and displays the result in a message box.
Notice that plain text is always enclosed in quotation marks, but variable names are not. If you were to enclose the NewAge variable in quotation marks, the script would simply print out the text NewAge instead of whatever value is stored in the variable.
The MsgBox statement can also be used like this:
Response = MsgBox("Here's My Message", 17, "Message Title")
which allows it to be used for not only displaying a message, but recording the response as well. The 17 is the sum of a few different values, which specify the options used to customize the message box. Figure 1 shows two sample message boxes, each with different buttons and icons.
To choose the buttons that are displayed by the MsgBox function, specify:
- 0 for OK
- 1 for OK & Cancel
- 2 for Abort, Retry, & Ignore
- 3 for Yes, No, & Cancel
- 4 for Yes & No
- 5 for Retry & Cancel
To choose the icon that is displayed, specify:
- 16 for a red × (error)
- 32 for a question mark (query)
- 48 for an exclamation mark (warning)
- 64 for a blue "I" (information)
Additionally, you can add:
- 256 to give the second button the focus (dotted lines)
- 512 to give the third button the focus
- 4096 to make the message box "system modal" (i.e., all applications are suspended until the user responds to the message box)
So, to have a message box with the Yes and No buttons, to have the question mark icon, and to have No be the default, you would specify a value of 4 + 32 + 256 = 292. The two message boxes in Figure 9-1 have values of 17 (that's OK, Cancel, and the × icon) and 292, respectively. Note that it's good practice not to add the values together (like I did in the first example with 17), but rather to leave them separated, like this:
Response = MsgBox("Here's My Message", 16 + 1, "Message Title")
This way, it's easier to understand and modify later on.
When the user responds to the message box, the Response variable will be set to:
- 1 if the user clicked OK
- 2 for Cancel
- 3 for Abort
- 4 for Retry
- 5 for Ignore
- 6 for Yes
- 7 for No
The next step is to write code that can perform different functions based on this recorded response. See the next topic, "Section 9.2.3," for details on using the results from a MsgBox statement to determine what happens next in a script.
2.3. Creating Interactive Scripts with Conditional Statements
Conditional
statements allow you to redirect the flow depending on a condition you
determine, such as the value of a variable. Take, for example, the
following script:
Response = MsgBox("Do you want to continue?", 32 + 4, "Next Step")
If Response = 7 Then WScript.Quit
MsgBox "You asked for it..."
The first statement uses the MsgBox function, described in the previous topic, to ask a question. The value of 32 + 4 specifies Yes and No buttons, as well as the question mark icon. If the user chooses Yes, the value of the Response variable is set to 6; if No is chosen, Response is set to 7.
The next statement uses the vital If...Then structure to test the value of the Response variable. If it's equal to 7 (meaning the user clicked No), then the script exits immediately (using the WScript.Quit statement). Otherwise, script execution continues to the next command.
Here's another example using a slightly more complex version of the If statement:
MyShoeSize = InputBox("Please type your shoe size.")
MyIQ = InputBox("Please type your IQ.")
If MyShoeSize > MyIQ Then
MsgBox "You need to read more."
Else
MsgBox "You need larger shoes."
End If
One of the nice things
about VBScript is that most of the commands are in plain English; you
should be able to follow the flow of the program by just reading through
the commands. Before you run the previous script, try to predict what
will happen for different values entered at each of the two InputBox statements.
This script uses the If...Then
structure to redirect output depending on the two values entered at
runtime (when the script is actually being executed). It should be
evident that the first message is displayed if the value of MyShoeSize is larger than the value of MyIQ. In all other cases (including when both values are equal), the second message is displayed. Note also the use of End If, which is required if the If...Then structure spans more than one line, as it does in this example.
The If...Then structure can have as many elements as you need. For example:
Crashes = InputBox("How many times a day does Windows crash?")
If Crashes <= 3 Then
MsgBox "You lucky sod..."
ElseIf Crashes = 4 or Crashes = 5 Then
MsgBox "The national average: good for you!"
Else
MsgBox "Take two aspirin and call me in the morning."
End If
accommodates three different ranges of answers to the question posed by the first line of code (thanks to the ElseIf line). Note also the use of or on the fourth line; you could also use and here, or a combination of the two. Use parentheses to group conditions in more complex statements.
2.4. Using Loops, Using Loops, Using Loops
Another useful structure is the For...Next loop, which allows you to repeat a series of commands a specified number of times:
SomeNumber = InputBox("How many lumps do you want?")
TotalLumps = ""
For i = 1 To SomeNumber
TotalLumps = TotalLumps & "lump "
Next
Rem—The next line displays the result—
MsgBox TotalLumps
The For...Next loop repeats everything between the two statements by incrementing the value of the variable i until it equals the value of the variable SomeNumber. Each time WSH goes through the loop, another "lump" is added to the variable, TotalLumps. When the loop is finished, the contents of the TotalLumps variable are displayed.
Notice the use of the concatenation operator (&)
in the middle of the loop, which adds a new lump to the variable. Those
new to programming might be put off by the fact that we have the TotalLumps variable on both sides of the equals sign.
This works because the scripting host evaluates everything on the right
side of the equals sign (adds it all up) and then assigns it to the
variable on the left side.
Note also the TotalLumps="" statement before the For...Next
loop; this empties the variable before we start adding stuff to it.
Otherwise, whatever might be assigned to that variable before the loop
would still be kept around—something we didn't anticipate or want. It's
good programming practice to prepare for as many different situations as
can be imagined.
Also good
practice is the use of spaces, indentations, and remarks to make the
code easier to read without affecting the execution of the script. The Rem
command is used to include remarks (comments that are ignored when the
script is run), allowing you to label any part of the script with
pertinent information. In place of the Rem command, you can also use a single apostrophe ( '), which—unlike Rem—can be placed on the same line as another command, like this:
MsgBox TotalLumps 'display the result
As you write these
scripts, think about the formatting as you would in writing a
word-processor document; scripts that are easier to read are easier to
debug and much more pleasant to revisit six months later.
2.5. Make Building Blocks with Subroutines and Functions
A subroutine
allows you to encapsulate a bit of code inside a single command, making
it easy to repeat that command as many different times as you want as
though it were a built-in command. Simply include the entire subroutine
anywhere in a script, and then type the name of the subroutine elsewhere
in the script to execute the subroutine.
A function is essentially the same as a subroutine, except that it has a result, called a return value. Both subroutines and functions accept input variables, listed in parentheses after the respective Sub and Function statements.
To
those who are familiar with macros in a word processor, subroutines are
similar. In fact, Microsoft Word, Excel, and Access (in Office 95 and
later) save their macros as VBScript subroutines. |
|
Consider Example 1,
which compares the contents of two text files. At the heart of this
example are the two structures at the end of the script, although their
specific position in the script is not important. WSH separates all
subroutines and functions before executing the script; they won't be
executed unless they're called, and the variables used therein are
unrelated to variables used elsewhere in the main script. Whenever it
encounters the name of a subroutine or function in the script body, it
executes it as though it were a separate script. Try to follow the
execution of the script, command by command.
Example 1. Using functions and subroutines
Filename1 = InputBox("Enter the first filename")
Filename2 = InputBox("Enter the second filename")
If Not FileExists(Filename1) Then
MsgBox Filename1 & " does not exist."
ElseIf Not FileExists(Filename2) Then
MsgBox Filename2 & " does not exist."
Else
Call RunProgram("command /c fc " & filename1 & _
" " & filename2 & " > c:\Users\username\Desktop\temp.txt", True)
Call RunProgram("notepad c:\Users\username\Desktop\temp.txt", False)
End If
Function FileExists(Filename)
Set FileObject = CreateObject("Scripting.FileSystemObject")
FileExists = FileObject.FileExists(Filename)
End Function
Sub RunProgram(Filename, Wait)
Set WshShell = WScript.CreateObject("WScript.Shell")
RetVal = WshShell.Run(Filename, Wait)
End Sub
|
One of the most important aspects of both subroutines and functions is that they can accept one or more input variables, called parameters or arguments.
The parameters that a subroutine can accept are listed in parentheses
after the subroutine definition and are separated by commas (if there's
more than one).
Then, using the Call
statement, the values you wish to pass to the subroutine (which are
placed in the parameter variables when the script is run) are listed in
parentheses.
This way,
the same subroutine or function can be called repeatedly, each time
with one or more different variables. Functions (such as FileExists in this example) also can return a single variable (usually dependent on the outcome of some operation).
The first structure defines the FileExists function , which is passed a filename and returns a value of True (−1) if the file exists, and False (0) if it does not. The FileExists function is called twice, once for each filename entered when the script is run (Filename1 and Filename2). The If...Then structures first call the function, then redirect the flow based on the return value (result).
The second structure defines the RunProgram subroutine, also called from the script two times. RunProgram
simply runs the program filename passed to it; since it's a subroutine
and not a function, there is no return value. In theory, you could use
functions exclusively, and simply ignore the return values of those
functions that don't use them; the benefit of subroutines, though, is
that you don't have to think about handling a return value at all.
In FileExists and RunProgram, Filename
is a variable (shown in parentheses) in which passed data is placed so
it can be used inside the subroutine or function. It's considered a
local variable, i.e., it has no value outside of the subroutine or
function. |
|
The
most important consequence of this design—the separation of the code
into subroutines and functions—is that it makes it easy to reuse
portions of code. Experienced programmers will intentionally separate
code into useful subroutines that can be copied and pasted to other
scripts. Just think of programming as building something out of
Lego™blocks; the smaller the blocks, the more versatile they become.
It's worth mentioning that, in the case of subroutines, the Call statement is not strictly necessary. For example, the line:
Call RunProgram("notepad c:\temp.txt", False)
is equivalent to:
RunProgram "notepad c:\temp.txt", False
Note that without the Call keyword, the parentheses around the arguments are omitted. Personally, I like using Call; it makes references to my custom subroutines more distinct and easier to find, but others might prefer the simpler form.
The
solutions in the subsequent topics are presented as either subroutines
or functions. I've used subroutines for code that performs an action,
such as copying a file or writing information to the Registry. When a
result is expected, such as reading information from the Registry or
finding the date of a file, a function is used instead.
You
should be able to place the subroutines and functions directly into
your scripts and call them with a single command. It's up to you to put
the pieces together (and to modify them) to accomplish whatever tasks
you have in mind.