Thrown for a Loop
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
Thrown for a Loop
After spending a week in a log cabin in the woods at the base of the Grand Tetons (that’s in Wyoming, USA, for those who are wondering), and another week just goofing off, this Scripting Guy has returned to the hustle and bustle of city life and working for a living. What does that have to do with this month’s column? Not much, but we thought that since we’re probably not thinking straight just yet, a good topic of discussion would be loops.
Loops are something you’ll need often in your scripts, mostly because a lot of objects and properties are returned as collections of objects and properties. Okay, so first we’ll talk about collections, then we’ll talk about loops. Oh no, wait, there are also these things called arrays that you frequently use with loops. So we’ll talk about collections, arrays, and then loops. Yes, that’s about right.
See, we told you we’re not exactly thinking straight just yet. Bear with us (no, that has nothing to do with all the bears in the Tetons, which we looked for but didn’t see), and we’ll see if we can make this column somewhat coherent.
Collections are pretty easy to understand once you understand objects and properties. If you don’t understand objects and properties, see Class is in Session.
Simply put (and accurately put, as it turns out), collections are exactly what they sound like - they’re collections. Whereas people have collections of stamps, baseball cards, or fruit-themed cookie jars, scripts have collections of - wait, think about it for a minute before we tell you. What kind of collections would you use in a script? The answer appears upside down at the bottom of this column.
Oops, we couldn’t figure out how to get upside-down text into the article, so we’ll just tell you. Scripts use collections of objects and properties. What for? We’re glad you asked.
Suppose you want to list all the disk drives on a computer. You can find this information on the local computer by accessing the FileSystemObject, like this:
Set objFSO = CreateObject("Scripting.FileSystemObject")
This gives you a single instance of a FileSystemObject in the variable objFSO. Now you need to find the drives. You might look for an object (yes, objects can contain other objects) or a property within the FileSystemObject named Drive, so that you could do something like this:
Set objDrive = objFSO.Drive
You might look, but you won’t find it. The reason is because most computers have more than one drive. At the very least these days you’ll have a hard drive and a CD drive. If we were to return a single drive object, how would the FileSystemObject know which drive to return? Rather than randomly guessing and returning a single drive, the FileSystemObject provides a Drives collection:
Set colDrives = objFSO.Drives
The colDrives variable is a collection that contains all the drives that the FileSystemObject object found on the computer.
So how do we actually see what those drives are? Can we just do this:
No. But we’ll show you what we can do in just a minute when we get to loops. But first we’re going to talk about arrays.
Actually, before we move on to arrays there are a couple other things we should point out about collections. The first is that, for the most part, as a scripter you won’t be assigning anything to collections, collections will be returned to you, as in our example where a collection of drives was provided to you by the FileSystemObject.
Second, it’s possible that a collection can have only one element. It’s even possible for a collection to exist with zero elements. If you didn’t have any drives on your computer (not likely, but we’re too lazy to come up with a new example), your colDrives collection would not have anything in it.
Collections - Microsoft Windows 2000 Scripting Guide
Collections with Zero Items - Microsoft Windows 2000 Scripting Guide
Before we talk about accessing the individual items within a collection, we’ll talk about another type of data you need to loop through - arrays. An array is like a collection in that it holds a collection of things. So what’s the difference between a collection collection and an array collection?
A collection contains items that would come from a class, which includes properties and objects (but not methods, that wouldn’t make any sense - you call a method, you don’t have a method). A collection is actually a type of object that contains multiple elements. So as you saw in the Collections section above, you’ll typically use the Set statement when assigning a collection to a variable. An array, on the other hand, contains a series of elements of just about any data type. It can contain objects, but it can also contain strings, characters, numbers, or any other data type available in VBScript. You can assign values to an array variable without using the Set statement, it’s just a container for information you want to group together.
We’re not going to show you a practical example of an array just yet (that’s hard to do without including a loop) but we’ll show you how they work. Let’s start by assigning characters to an array, and then echoing out those characters:
Dim arrArray(7) arrArray(0) = "m" arrArray(1) = "y" arrArray(2) = " " arrArray(3) = "a" arrArray(4) = "r" arrArray(5) = "r" arrArray(6) = "a" arrArray(7) = "y" Wscript.Echo arrArray(0) & arrArray(1) & arrArray(2) & arrArray(3) & _ arrArray(4) & arrArray(5) & arrArray(6) & arrArray(7)
You’ll see that the first line starts with the Dim statement. We didn’t talk about this in our article on Variables and Constants, although it probably would have been a good idea. (We’ll get to it someday.) For now what you need to know about the Dim statement is that it tells your VBScript program that you’ll be using a variable somewhere in the script. You can Dim any variable before you use it. We won’t go into why you might do this for other variables, but in the case of arrays this statement is required (sometimes—we’ll get to that later). By using the Dim statement you’re telling VBScript that the variable named, in this case, arrArray, is a variable you’ll be using in the script. Also, by putting parentheses after the variable name, you’ve told VBScript that this particular variable is an array.
The reason the Dim statement is required is because normally if you see something followed by parentheses, it’s a method:
When we assign a value to an array, we use a number within parentheses to tell the array at which position we want to store the value. So in this case, we’re saying we want to store the letter “m” in position 0 (arrays in VBScript always start at 0):
arrArray(0) = "m"
But at the same time we need to tell VBScript that arrArray isn’t a method we’re trying to call, it’s an array. That’s why we need to alert VBScript ahead of time with the Dim statement before we try to assign a value.
One more point about the Dim statement. Notice how we put a number inside the parentheses? This is the number of elements we want to put in the array, referred to as the size of the array.
What if you don’t know the size?
Please hold your questions to the end. Let’s finish going through this script first.
So we’ve told VBScript we want an array that will hold seven elements. Well, no, actually we told VBScript we want an array that will hold eight elements.
What? Eight? Where do you get eight from?
We’re pretty sure we asked you to hold your questions. We’re getting there.
Each element in an array has a position. It’s like when you buy a carton of eggs at the grocery store. Each egg has a slot in the carton. For a dozen eggs, you’d obviously want 12 slots in the carton, one for each egg. So you’d define the carton as an array of 11.
No, that’s not right, is it? You said 12.
Okay, the next person to blurt out a question has to stand in the corner until we’re done.
In VBScript, an array starts numbering its positions with zero. So if you have 12 slots, they’ll be numbered 0 through 11. When we declare an array with the Dim statement, we tell it not how many elements will be in the array, but what the number of the highest position is. So the size of your array is always defined as the number of elements in the array minus one.
Now, there will be times that you don’t know at the beginning of your script how many elements will be in your array. When that’s the case, you still have to Dim (declare) your array, but you leave the parentheses empty:
You then find out how many elements you need, and then re-Dim the array with the - surprise - ReDim statement:
That’s about all we can do without getting into loops. We’ll take your questions now (except you over there in the corner). No questions? Great, let’s move on.
Arrays - Microsoft Windows 2000 Scripting Guide
ReDim Statement - VBScript Language Reference
Now that we know what kinds of things we want to loop through, we’re going to look at two ways of looping, the For Each loop and the For Next loop.
A For Each loop looks like this:
For Each <element> in <collection> ' do something Next
As you can see, this is how we typically loop through collections. We put the name of our collection variable in place of <collection>, and we make up a new variable name for <element>. Let’s go back to our disk drives example. Here’s what we have so far:
Set objFSO = CreateObject("Scripting.FileSystemObject") Set colDrives = objFSO.Drives
Our collection variable is colDrives, and because it’s a collection of objects we’ll call the <element> objDrive:
For Each objDrive in colDrives ' do something Next
In plain English this says “For each drive object in the collection of drives we’re going to perform some action.” So the first time VBScript runs the For Each line, it will put the first drive in the collection into the objDrive object variable. It will then move on to run the lines after that. The Next statement tells us we’re at the end of our loop, that we’ve done everything with that particular drive that we need to. Since we’re done with that particular object we want to move on to the next object in the collection. At that point the script jumps back to the For Each statement, grabs the next object in the collection and assigns that object to objDrive. This process continues until the For Each statement looks for the next item in the collection and doesn’t find one. When that happens, it jumps out of the loop and the script continues running at the line past the Next statement.
Try out this example:
Set objFSO = CreateObject("Scripting.FileSystemObject") Set colDrives = objFSO.Drives For Each objDrive in colDrives Wscript.Echo "Drive letter: " & objDrive.DriveLetter Next Wscript.Echo "Done"
Now we’ll look at a loop that’s similar, the For Next loop. This loop is more commonly used with arrays, mainly when you know how many times you want the loop to occur. A For Next loop looks like this:
For <counter> = <start> to <end> ' do something Next
The <counter> is just a variable you make up. (Standard practice is to use a single letter, such as i.) The <start> value is where you want to start counting your loops, and <end> is where you want to end. Here’s an example:
For i = 0 to 3 ' do something Next
We could just as easily have started with any other number:
For i = 9 to 12 ' do something Next
Where you start depends on what you’re doing within your loop and whether you’ll be using the counter variable for anything. If you take a look at the following example, you’ll start to see where this type of loop is very useful for arrays:
Dim arrCount() size = 3 ReDim arrCount(size) For i = 0 to size arrCount(i) = i Wscript.Echo arrCount(i) Next Wscript.Echo "Done "
The output from this example will look like this:
0 1 2 3 Done
The For Next statement works very much like the For Each statement. The difference is we’re telling it how many times to go through the loop. The first time through the loop, the start value is assigned to the variable i. In this case that means that the first time through this loop, i will contain the value 0. We then run the lines that follow the For statement until we get to the Next statement. When we reach the Next statement, we jump back up to the For statement. The second time we get to the For statement, the value of i gets incremented by one, so the second time through in this case i is equal to 1. The For statement increments the value by one each time through the loop until it gets to the end number. When it gets to the end number (in this case the value of size, which is 3), it will run the lines following the For statement one last time. The Next statement will then send us back to the For statement, but at this point we’ve passed the end value, so we jump out of our For loop and execute the lines following the Next statement.
We don’t actually have to increment by one every time through the loop; that’s just the default. Instead, we can increment by any whole number:
Dim arrCount() size = 3 ReDim arrCount(size) For i = 0 to size Step 2 arrCount(i) = i Wscript.Echo arrCount(i) Next Wscript.Echo "Done "
This will run the first time using the start value (0), then will increment by 2 the next time through, so your output will look like this:
0 2 Done
You can even count backwards. (Just remember that now the start needs to be a higher number than the end or you’ll jump right out of your loop.) Try this:
Dim arrCount() size = 3 ReDim arrCount(size) For i = size to 0 Step -1 arrCount(i) = i Wscript.Echo arrCount(i) Next Wscript.Echo "Done "
For Each - Microsoft Windows 2000 Scripting Guide
For Each…Next Statement - VBScript Language Reference
For Next - Microsoft Windows 2000 Scripting Guide
For…Next Statement - VBScript Language Reference
Okay, it’s not really bonus information, but that sounded better than “A Bunch of Other Collection/Array/Looping Stuff.”
For Each with Arrays
We’ve talked about using a For Each loop with collections, and a For Next loop with arrays. We should mention that you can also use the For Each loop with arrays:
Dim arrArray(3) arrArray(0) = 100 arrArray(1) = 150 arrArray(2) = 200 arrArray(3) = 250 For Each intArray in arrArray Wscript.Echo intArray Next
This works exactly like it does for collections. The first time through the loop, intArray will be assigned whatever is in the first element of the array, arrArray(0). It will then print that element. The next time through the loop, intArray will contain the second element in the array, arrArray(1), and so on.
Creating Arrays without Dim
When we talked earlier about using the Dim statement to declare arrays, we said that the Dim statement was required—sometimes. There is another way to put elements into an array. You can use the Array method:
arrArray = Array("m","y"," ","a","r","r","a","y") Wscript.Echo arrArray(0) & arrArray(1) & arrArray(2) & arrArray(3) & _ arrArray(4) & arrArray(5) & arrArray(6) & arrArray(7)
Copy this script into Notepad and run it (if you don’t know how to do that, check out Scripting: Your First Steps); it will work without any error messages. The reason we don’t have to use the Dim statement is because the Array method returns an array, so VBScript knows that we’re put an array into the arrArray variable.
Get Me Out of Here
Suppose you’re looping through a collection looking for a particular value. Once you find it, you don’t want to keep looping, that would just be a waste of time. How do you get out of the loop? Simple:
For i = 0 to 3 Wscript.Echo i Exit For Next
Our output will look like this:
As soon as our script reaches the Exit For statement, we jump out of the loop to the line that follows the Next statement.
Exit Statement - VBScript Language Reference
Tune in Next Time…
We’re about out of steam for today. Hey, how much did you really expect from us right after vacation? Maybe not next time, but in some future column we’ll talk about a couple other kinds of loops you can use in VBScript. If you can’t wait until then, take a look at the VBScript User’s Guide on MSDN.