Why Did You Do That?

By The Microsoft Scripting Guys

Sesame Script

Welcome to Sesame Script, the column for beginning script writers. The goal of this column is to teach the very basics of Windows scripting for system administration automation. We’ll provide you with the information you’ll need to begin reading and understanding scripts and to start modifying those scripts to suit your own needs. If there’s anything in particular about scripting you’re finding confusing, let us know; you’re probably not alone.

Check the Sesame Script Archives to see past articles.

On This Page

Why Did You Do That?
I Quit
It’s Getting Dim in Here
It’s Nothing, Really
I Need a Break
Comment-ary
Now What?

Why Did You Do That?

Way back, several hundred years ago, when one of the Scripting Guys was still in school, this future Scripting Guy showed up at lunch one day with a peanut butter and jelly sandwich. One of the Scripting Friends showed up with a bag of potato chips. The future Scripting Guy asked for a handful of potato chips, then proceeded to open the sandwich, put the chips in, close the sandwich, and squish it all down. The Scripting Friends were horrified. “Why did you do that?”

First off we’d like to say that if you haven’t tried a peanut butter and jelly and potato chip sandwich, you should. (The Scripting Friend with the potato chips did, and for the rest of the year the future Scripting Guy split the sandwich with the potato chip friend, and the potato chip friend shared the potato chips so they could both have peanut butter and jelly and potato chip sandwiches for lunch.) Now, you might be thinking the point of this story is “Don’t knock it until you’ve tried it.” That would make sense, but that’s not it. The point of this story is that there remains to this day many Scripting Friends who would never dream of putting potato chips in a sandwich. Along those same lines, there are many things other scripters do that the Scripting Guys would never do themselves. And even if we did, we don’t think we’d enjoy it as much as potato chips in a sandwich.

The Scripting Guys have seen a lot of scripts. There were the scripts sent in for the Scripting Games and submissions to the Community-Submitted Scripts Center. In addition, many people send us email asking us to look at their scripts and help them figure out what’s wrong. And every once in a while, as we’re looking at these scripts, we think, “Why did you do that?”

Although, when we really think about it, we actually have a pretty good idea what some of your answers probably are:

“I just modified an existing script. That stuff was already there and I didn’t want to mess with it.”

“Someone told me I needed to do that.”

“I don’t know, but the script works so I don’t care.”

While those are all fine answers (except maybe the last one), we’d like to go over some of those things that have us scratching our heads. Now, we’re not pointing fingers or criticizing, and we certainly don’t want you to feel self-conscious about sending us your scripts. (We never feel self-conscious when people see the potato chips in our sandwiches.) We’re still pretty impressed with the scripts all of you come up with, and we know many of these scripts have made your lives much easier. But our sole reason for being is to teach you to be better scripters, and we’d be remiss in doing that if we didn’t try to clear up a few misconceptions and help you clean up your code a little. Besides, this could amount to less typing for you in the future, and that’s always a good thing.

I Quit

One thing we see over and over is a script like this:

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colItems = objWMIService.ExecQuery("Select * from Win32_CacheMemory")

For Each objItem in colItems
    Wscript.Echo "Access: " & objItem.Access
    Wscript.Echo "Additional Error Data: "
    Wscript.Echo "Associativity: " & objItem.Associativity
    Wscript.Echo "Availability: " & objItem.Availability
    Wscript.Echo "Block Size: " & objItem.BlockSize
    Wscript.Echo "Cache Speed: " & objItem.CacheSpeed
    Wscript.Echo "Cache Type: " & objItem.CacheType
    Wscript.Echo "Current SRAM: "
    For Each objElement In objItem.CurrentSRAM
        WScript.Echo vbTab & objElement
    Next
    Wscript.Echo
Next
Wscript.Quit

This script retrieves information about the cache memory on a computer. You’ll find if you run this script is does exactly what it’s supposed to, and you shouldn’t see any errors. So what’s wrong with it? Look at the last line:

Wscript.Quit

According to the Windows Script Host (WSH) Reference, the Quit method “Forces script execution to stop at any time.” That means that wherever you put that line of code in your script, your script will abruptly end right there. So it might seem natural to add this line to the end of your script, because when you’ve completed all the lines of code you want the script to stop.

While that’s true, and putting that line of code at the end of your script doesn’t hurt anything, your script is going to stop anyway. VBScript reads and executes one line of code at a time. After it’s read all the lines of code, the script ends. So there’s no need to tell it to end, it knows it has to end. In other words, when the script shown above gets to the line Wscript.Quit, it’s going to quit whether that line is there or not.

The same is true if you use functions or subroutines in your script: the script automatically quits when it reaches the last line in the main body of the script. Let’s change the previous script to include a subroutine (this isn’t necessary, either, it’s just for demonstration purposes):

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colItems = objWMIService.ExecQuery("Select * from Win32_CacheMemory")

RetrieveInfo
Wscript.Echo "End of script"
Wscript.Quit

Sub RetrieveInfo
    For Each objItem in colItems
        Wscript.Echo "Access: " & objItem.Access
        Wscript.Echo "Additional Error Data: "
        Wscript.Echo "Associativity: " & objItem.Associativity
        Wscript.Echo "Availability: " & objItem.Availability
        Wscript.Echo "Block Size: " & objItem.BlockSize
        Wscript.Echo "Cache Speed: " & objItem.CacheSpeed
        Wscript.Echo "Cache Type: " & objItem.CacheType
        Wscript.Echo "Current SRAM: "
        For Each objElement In objItem.CurrentSRAM
            WScript.Echo vbTab & objElement
        Next
        Wscript.Echo
    Next
End Sub

If you comment out (or, more appropriately, leave out) the call to Wscript.Quit, this script will end immediately after echoing “End of script.”

When Would I Quit?

The Quit method does have a very practical use. There may be times when you want your script to stop before all the lines of code have been executed. Suppose, for example, in the preceding script you want to stop echoing information if the cache is a data cache. If that’s the case, the CacheType property will return a value of 4. So we check to see if CacheType is 4, and if it is, we echo a message and end the script right there.

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colItems = objWMIService.ExecQuery("Select * from Win32_CacheMemory")

For Each objItem in colItems
    Wscript.Echo "Access: " & objItem.Access
    Wscript.Echo "Additional Error Data: "
    Wscript.Echo "Associativity: " & objItem.Associativity
    Wscript.Echo "Availability: " & objItem.Availability
    Wscript.Echo "Block Size: " & objItem.BlockSize
    Wscript.Echo "Cache Speed: " & objItem.CacheSpeed
    Wscript.Echo "Cache Type: " & objItem.CacheType
    If objItem.CacheType = 4 Then
        Wscript.Echo "Cache type is data: Do not show any more cache information."
        Wscript.Quit
    End If
    Wscript.Echo "Current SRAM: "
    For Each objElement In objItem.CurrentSRAM
        WScript.Echo vbTab & objElement
    Next
    Wscript.Echo
Next

In this case, as soon as the script echoes back the CacheType value for a data cache and echoes our message, the script will end.

More Information

Controlling How a Script Runs - Windows 2000 Scripting Guide

Quit Method (Windows Script Host) - Windows Script Host Reference

It’s Getting Dim in Here

Another thing we see quite often is what you might call an overuse of the Dim statement. The purpose of the Dim statement is to declare the variables that you use in your script. Here’s a simple example:

Dim a
Dim b

a = 4
b = 9
Wscript.Echo a + b

This script will echo the value 13. This next script will also echo the value 13:

a = 4
b = 9
Wscript.Echo a + b

When you use the Dim statement you’re telling VBScript to set aside some memory because you’re going to use this variable for something somewhere else in the script. That’s fine, except that as soon as you actually use the variable VBScript sets aside the memory required to use that variable. So, basically, declaring a variable with the Dim statement is just a way of giving VBScript a tap on the shoulder ahead of time, which doesn’t really accomplish anything.

Why Be Dim?

As with other keywords, Dim does have its place, and sometimes it’s not only nice to have, it’s absolutely necessary. We already showed you that this script works just fine:

a = 4
b = 9
Wscript.Echo a + b

However, the following script will not echo 13, it will display an error:

Option Explicit

a = 4
b = 9
Wscript.Echo a + b

The reason for the error, as you might have guessed, is the inclusion of the Option Explicit statement. This statement tells VBScript that every single variable used in the script must be declared with a Dim statement before it can be used. The reason you would do this is for the purposes of error handling. Suppose you’ve named your variables a little more intuitively, like this:

FirstNumber = 4
SecondNumber = 9
Wscript.Echo FirstNumber + SeconNumber

Everything still looks good, right? Well, maybe not. Try running the script. Instead of 13, you’ll receive a value of 4. Why 4? Because if you look closely, you’ll see that the variable to which you assigned the number 9 was named SecondNumber, while the variable you added in the Echo statement was SeconNumber (without the d). Because you never assigned a value to SeconNumber, it defaults to zero; thus you’ve added 4 to 0, for a total of 4. This might be easy to see here, but in a longer and more useful script this type of error can be difficult to diagnose; you might not even know you’re getting the wrong number back. Option Explicit helps guard against this type of problem. Try this:

Option Explicit
Dim FirstNumber
Dim SecondNumber

FirstNumber = 4
SecondNumber = 9
Wscript.Echo FirstNumber + SeconNumber

When you run this script, you’ll receive an error because the variable SeconNumber was never declared. It’s now easy to see that there’s a problem, and therefore you can fix the problem before your script starts returning unexpected or inaccurate results.

Advanced: Dim and Global Variables

Another use of the Dim statement is to declare global variables in scripts that have subroutines or functions in them. A global variable is a variable that is used throughout the script. Here we set a value for the variable a, call the ChangeA subroutine, change the value of a, then echo the value of a + b:

a = 4
b = 9

ChangeA
Wscript.Echo a + b

Sub ChangeA
    a = 10
End Sub

This script will echo the value 19. We set a to 4 and b to 9, but then we called the subroutine ChangeA, which reset the value of a to 10. We then added a (10) to b (9) and echoed the value. But let’s try something a little different:

b = 9

ChangeA
Wscript.Echo a + b

Sub ChangeA
    a = 10
End Sub

This time we left out the first line, which assigned the value of 4 to a. You might still expect to get a value of 19, but you don’t. Instead this script returns a value of 9. In this case, we never used the variable a in the main body of the script. That meant that when we used this variable in the subroutine, a was assumed to be a local variable. Local variables are available only within the subroutine in which they’re declared. Once we left the ChangeA subroutine the variable a ceased to exist. When we added a to b in the Echo statement, VBScript assumed that a was a variable you hadn’t declared, and the value was set to zero by default. Now let’s try this:

Dim a
b = 9

ChangeA
Wscript.Echo a + b

Sub ChangeA
    a = 10
End Sub

Once again, we have a value of 19. We’ve declared a outside the subroutine, so it holds its value globally, inside and outside the subroutine. If you don’t want to actually set the value in the main body of your script but you want to use it globally, be sure to use the Dim statement to declare it.

Let’s take a quick peek at one more thing:

Dim a
a = 4
b = 9

ChangeA
Wscript.Echo a + b

Sub ChangeA
    Dim a
    a = 10
End Sub

What do you think this will return? Go ahead, take a guess. All right, we’ll tell you: this script echoes the value 13. First we use the Dim statement to declare a as a global variable (so we can use it anywhere in our script) and set the value to 4. We then call the ChangeA subroutine. Within ChangeA, we used the Dim statement again to declare the variable named a. By doing this we’ve overridden the global variable and created a local variable in our subroutine that can be used only inside the ChangeA subroutine. We set the local variable a to 10, but then we leave the subroutine and the local variable doesn’t exist anymore. Our Echo statement uses the value of the global variable a, and echoes a value of 13.

In other words, the Dim statement can be used to help you differentiate between global and local variables, and help assure the exact results you’re expecting.

Clean It Up

If you’ve ever seen this particular Scripting Guy’s garage, you know what happens when you don’t get rid of things you’re not using anymore. There’s a general rule that if you don’t use something for some specified period of time (six weeks, six months, six years) you probably don’t need it anymore and you should get rid of it. (In the case of one Scripting Guy, that just means burning your garage down. We don’t recommend this course of action, however, because you also tend to lose things you’re still using. Like the garage.) If you’re not using the variables you’ve declared in your Dim statements, get rid of them. They don’t hurt the functionality of your script by being there, but they can hurt the readability and make troubleshooting more difficult. We’ve seen scripts that are 20 lines long that have an additional 30 lines of Dim statements. We suppose that if you’re trying to impress your boss with a high line count that will do the trick, but otherwise it doesn’t make much sense.

More Information

Dim Statement - VBScript Language Reference

Initializing Variables - Windows 2000 Scripting Guide

It’s Nothing, Really

Setting object references to Nothing is a practice we see all the time. We won’t go into a lengthy discussion here because we already discussed this in a previous edition of Sesame Script. Suffice to say, if you’re not going to reuse an object reference on a new object, and if your script isn’t using up massive amounts of memory, you don’t have to do this:

Set objReference = Nothing

All your object references will be released automatically when the script ends, you don’t need to force that to happen. Again, it doesn’t hurt anything, it just isn’t necessary.

More Information

Unloading Objects from Memory - Windows 2000 Scripting Guide

Nothing Keyword - VBScript Language Reference

I Need a Break

Everyone has their own style. Some are flashy, some more subdued. Some eat their pizza with a fork, some with their hands. And everyone formats their scripts just a little differently. Two of the main differences are indentation and line breaks.

Code formatting doesn’t have even the tiniest fraction of a second of impact on the performance of your script. This is all about appearances. Not for reasons of vanity, of course (the Scripting Guys wouldn’t know anything about that), but for reasons of readability and ease in maintaining your scripts. Take a look at this script, which changes the size of a page file:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colPageFiles = objWMIService.ExecQuery _
    ("Select * from Win32_PageFileSetting")

For Each objPageFile in colPageFiles
    objPageFile.InitialSize = 300
    objPageFile.MaximumSize = 600
    objPageFile.Put_
Next

It’s pretty easy to read this script. The first two lines set the computer you’re working with and connects to the WMI service. Then we call ExecQuery, which returns a collection of page file objects (colPageFiles). After that we call a For Each loop to access the objects in the collection and change the settings appropriately. Seems pretty straightforward. But would it be as straightforward if it looked like this:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colPageFiles = objWMIService.ExecQuery("Select * from Win32_PageFileSetting")
For Each objPageFile in colPageFiles
objPageFile.InitialSize = 300
objPageFile.MaximumSize = 600
objPageFile.Put_
Next

Or how about this:

strComputer = "." : Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colPageFiles = objWMIService.ExecQuery("Select * from Win32_PageFileSetting")
For Each objPageFile in colPageFiles
objPageFile.InitialSize = 300 : objPageFile.MaximumSize = 600 : objPageFile.Put_
Next

The three preceding scripts are equivalent. Which is easiest to read? You decide. (But if you decide anything other than “the first one,” well, you’re wrong. And you should be eating your pizza with your hands.)

More Information

Statement Breaks in VBScript - Windows 2000 Scripting Guide

Comment-ary

Some people will tell you that you need comments in your code. This - along with “eat your vegetables” and “brush your teeth” - is great advice. But keep in mind, if you eat nothing but carrots you might turn orange, and if you brush your teeth constantly you could wear the enamel off your teeth. As the old saying goes, “everything in moderation,” and the same holds true of code comments. You could conceivably comment every single line in your script, but it is possible to reach a point where the comments hinder the understanding of your script more than they help it. Take a look:

'*****************************************
' Script to determine what day of the week
'    a particular date falls on.
'
' Written By: The Scripting Guys
' Date: Today
'
'*****************************************

' Call the DatePart method
' Pass the parameters "w" for day of the week, and
' the date we want to check
intDay = DatePart("w", "3/2/2006") ' Date to check: 3/2/2006

' Select statement
' Determine what the day is
Select Case intDay
    ' Test for Case 1
    Case 1
    ' This is Sunday
        Wscript.Echo "Sunday"
    ' Test for Case 2
    Case 2
    ' This is Monday
        Wscript.Echo "Monday"
    ' Test for Case 3
    Case 3
    ' This is Tuesday
        Wscript.Echo "Tuesday"
    ' Test for Case 4
    Case 4
    ' This is Wednesday
        Wscript.Echo "Wednesday"
    ' Test for Case 5
    Case 5
    ' This is Thursday
        Wscript.Echo "Thursday"
    ' Test for Case 6
    Case 6
    ' This is Friday
        Wscript.Echo "Friday"
    ' Test for Case 7
    Case 7
    ' This is Saturday
        Wscript.Echo "Saturday"
End Select

In case you were wondering, there are 25 lines of comments, and 17 lines of script code. Not that you should necessarily be worried about the ratio, but are all the comments really necessary to understand the script? “Test for Case 1”? That should be pretty obvious from the Case 1line of code. Same thing with “This is Friday.” The fact that the script echoes “Friday” should be a pretty good indication that this case is for Friday. The comments at the beginning could be very useful to identify the script and when it was last modified, and by who (if you really want someone to be able to track you down later). Here’s the same script, a little more reasonable, and a lot more readable:

'*****************************************
' Script to determine what day of the week
'    a particular date falls on.
'
' Written By: The Scripting Guys
' Date: Today
'
'*****************************************
intDay = DatePart("w", "3/2/2006")

Select Case intDay
    Case 1
        Wscript.Echo "Sunday"
    Case 2
        Wscript.Echo "Monday"
    Case 3
        Wscript.Echo "Tuesday"
    Case 4
        Wscript.Echo "Wednesday"
    Case 5
        Wscript.Echo "Thursday"
    Case 6
        Wscript.Echo "Friday"
    Case 7
        Wscript.Echo "Saturday"
End Select

That’s really about all you need. Less is more, right?

More Information

Commenting Scripts - Windows 2000 Scripting Guide

Rem Statement - VBScript Language Reference

Now What?

Don’t worry, that’s it. That wasn’t too painful, was it? If you’re doing any of the things we’ve pointed out here, don’t worry. First, you’re not alone. Second, if it’s really working for you, well, who are we to mess with success? (Not that we know much about that, either - ask our manager.) But we hope we’ve provided you with some helpful hints, and helped you to move past the “I did that because…well, just because” to the more informed “I did that because I understand how this all works and I wanted to do it anyway.” More power to you. And try throwing in some potato chips the next time you make a peanut butter and jelly sandwich.