Class is in Session
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
Class is in Session
Many times, the Scripting Guys have seen people go off to a beginning computer programming class (or even a beginning scripting class) and come back completely confused. These were people who worked with computers every day, and who seemed very intelligent. So why were they all coming back feeling like idiots? Were these people really not quite as bright as they seemed? Although this is a distinct possibility that we don’t want to rule out, chances are they just rushed a little too quickly into the concepts of classes and objects. But don’t worry, we’re going to take our time and do our best to get you through this, and maybe—just maybe—when we’re done you won’t be feeling quite as confused as all those other poor people.
What Is a Class?
A class is kind of like a house plan or blueprint. A house plan will show that the house has a kitchen, three bedrooms, a bathroom, and so on. It will even show that the kitchen has a stove and a sink, and the bedroom has a closet. What it doesn’t show is which way to turn the faucets on the sink, how much water will come out, and what to put in the closets. For example, here’s a plan for a kitchen:
A class is similar in that it gives you a framework to work from. Let’s see what a Kitchen class would look like.
Obviously you can’t fry an egg on your kitchen plan, you need to actually build the kitchen and put the stove in to do that. In the same way you can’t really do anything with your Kitchen class, you have to use that class to create a kitchen object. Hang on, we’ll get back to objects in just a second.
A whole house - and even a kitchen - is pretty big and complicated, so let’s think a little simpler and just look at a refrigerator. We’ll start by examining the characteristics of a refrigerator. Let’s see, there’s color - you might not want a plain white refrigerator in your beautiful lime green and purple kitchen. There also must be shelves to put the food on. How many? Is there an ice dispenser in the door?
Let’s see what we have now:
Refrigerator Color Shelves IceDispenser
Surprise! You just defined the properties of your Refrigerator class. Look again:
Refrigerator string Color int Shelves boolean IceDispenser
Color has to be the name of a color, so we defined it as a character string. Shelves tells us the number of shelves in the refrigerator, so we made that an integer. And IceDispenser is just a Yes/No value - either there is an ice dispenser or there isn’t - so we made that a Boolean.
Advanced: Even though we gave our properties data types (string, int, and boolean) here, VBScript doesn’t really use types like this. VBScript uses one data type: Variant. What’s a Variant? A Variant is VBScript’s way of saying “any type.” But when you look though any of the SDKs on MSDN, you’ll see specific data types defined. These data types are required by other languages such as C++, but for VBScript the definition in the SDK is relevant only in that it will tell you what kind of data you should be expecting. We’ll probably cover data types in a future article.
VBScript Data Types - Microsoft Windows 2000 Scripting Guide
Elementary Data Types - Visual Basic Language Reference
We’ve identified some characteristics, or properties, or our refrigerator. Now let’s think about what we want to be able to do with our refrigerator. The most obvious thing of course is that we want to keep things cool. To do this we need to be able to set the temperature. And if there is an ice dispenser, we might need to choose between crushed ice or cubed. Ta Da! We now have methods:
Refrigerator SetTemperature SelectIce
We can now use the SetTemperature method to set the temperature of our refrigerator. But we can’t just tell the refrigerator “Set the temperature!”, we need to tell it what temperature we want. To do this we have to use a parameter with the method. In this case the parameter is the value we want to set the temperature to:
For the ice we’ll just give the method a string parameter, either “crushed” or “cubed”:
This is called passing a parameter to the method. We pass a parameter to give the method certain information we want it to act on. We can also pass a parameter using a variable (as we discussed in a previous column):
intTemperature = 39 SetTemperature(intTemperature)
So how do we know that when we call the SetTemperature method we need to pass it a number, or that we need to pass the SelectIce method a string of either “crushed” or “cubed”? We look it up in the associated SDK (Software Developer Kit). There is SDK documentation on MSDN for most of the scripting technologies you’ll be using.
Advanced: Properties vs. Methods
As we’ve presented them here in our ideal world of refrigeration, there’s a pretty distinct difference between properties and methods: properties describe something, whereas methods take an action on that thing. Makes perfect sense, right? Okay then, why do we have a method for SetTemperature rather than just using a Temperature property and assigning that property a number that represents the temperature? Why did we need a method?
We’ll be amazed if you have a good answer to that question, because we don’t. Let’s take a look at a couple of real-life examples and you’ll see what we mean.
The WMI class Win32_OperatingSystem has quite a few properties, and four methods. The properties are things like LastBootUpTime, SerialNumber, and Version. These are features associated with the operating system, so according to our definition of properties these make perfect sense. Even the methods make sense: Reboot, SetDateTime, Shutdown, and Win32Shutdown. These are all actions, something that needs to happen to the operating system. So far so good, right?
Now take a look at the WMI class Win32_Directory. This class has many of the properties related to working with directories that you’d expect, such as FileName, Extension, and Hidden. Now look at the methods. Wait a minute - there’s a method called Rename. But there’s also a Name property. Why would we need to call a Rename method rather than just setting the Name property?
As if that’s not confusing enough, sometimes you’ll find a class with a method such as Rename but no Name property at all. Why? We don’t know. What’s really happening here is that the developer who created the class made his or her best guess at whether something should be a feature or an action. It won’t always make perfect sense to the rest of us, but that’s the way it is.
Here’s what our class looks like now:
Refrigerator string Color int Shelves boolean IceDispenser SetTemperature(int Temp) SelectIce(string IceType)
Knowing we have a Refrigerator class, let’s set the Color for the Refrigerator:
Refrigerator.Color = "green"
We now have a green refrigerator, right? Wrong! Remember, our class is just a blueprint of a refrigerator - you can’t turn a blueprint green. (That would make it a greenprint, and, well, that’s just not right.) First we need to create an actual object, in this case a refrigerator:
Set objFridge = CreateObject("Refrigerator")
Objects are always created with the Set statement. Sometimes we use CreateObject, sometimes GetObject, sometimes other things, but always the Set statement. Why not just do this?
objFridge = CreateObject("Refrigerator")
Because that’s not how objects work. It takes more effort than just an equal sign to make an object out of a class, you need the Set.
Advanced: All right, there is a little more to it. It has to do with memory addresses. We’re not just moving a value into a variable, we’re actually referencing a location in memory. So another term you’ll see a lot is object reference. The variable, such as objFridge, doesn’t actually contain an object, it contains a reference to an object stored in memory. So in all honesty, you actually can create an object without the Set statement, but you can’t assign the object reference to a variable and use that object reference anywhere else unless you’ve used Set in the assignment statement.
Now that we have an object we can do things like set the temperature, change the color, and query for whether or not there’s an ice dispenser:
Set objFridge = CreateObject("Refrigerator") objFridge.SetTemperature(43) ' Degrees Fahrenheit objFridge.Color = "green" Wscript.Echo objFridge.IceDispenser
You might be wondering why we had to go through all that. Why can’t we just use the class rather than having to make an object? It’s not like it’s a real, physical refrigerator, it’s still all on the computer. Well, what happens if you’re talking about a restaurant with two refrigerators? How would you distinguish the features of both? Using objects makes this simple: create two objects, both based on the Refrigerator class. Let’s say we want refrigerator 1 to be colder than refrigerator 2. We just use the Refrigerator class to create two objects:
Set objFridge1 = CreateObject("Refrigerator") Set objFridge2 = CreateObject("Refrigerator") objFridge1.SetTemperature(39) objFridge2.SetTemperature(43)
The COM Process - Microsoft Windows 2000 Scripting Guide
Creating an Object Reference - Microsoft Windows 2000 Scripting Guide
So how are you doing? Hanging in there? Need to stop and get a drink of water? That’s okay, we’ll wait.
Ready now? We’re about the get a little more complicated, so prepare yourself.
We can’t talk about objects without talking about binding. If you read many of the articles in the Script Center, you’ll frequently see a phrase like this: “We begin by binding to the user account in Active Directory,” or this: “We begin by connecting to the WMI service.” Okay, in the second case we said “connecting” instead of “binding,” but it’s the same thing. (No we’re not just being inconsistent, it’s for your own good; we like to expose you to the variations in terminology. Really.) You might also hear about “instantiating.” It’s all pretty much the same thing.
So what does it mean to bind to something (or connect to or instantiate)? At the very heart of it, it really just means you’re creating an object. You bind to Active Directory or WMI or ADO or any other object by calling either CreateObject or GetObject, depending on the type of object and where it’s coming from. We’re not going to get into the details here of which one to call when. Your best bet to start with is to just look for an example that uses the object you want and steal it. (That’s what the Script Repository is all about, feel free to take whatever you need.)
Binding - Microsoft Windows 2000 Scripting Guide
Connecting to Objects - Microsoft Windows 2000 Scripting Guide
One thing people get a little confused about is releasing objects. You release an object by doing this:
Set objFridge = Nothing
Setting an object to Nothing makes it so you can’t use the object in your script anymore. There are a lot of people who think they need to do this to all of their objects at the end of their scripts. We’ll let you in on a little secret: You don’t need to do this. It’s just extra typing, and as we’ve said before, the Scripting Guys always discourage extra typing.
Why do so many people think this is necessary? History. Here’s the story:
When you create an object, your computer sets aside some space in memory for that object. So when you create objFridge, there’s a little space on your computer that says “Hey, I’m objFridge now!” In many programming languages, such as C and C++, a program will come to an end and that piece of memory will still be hanging around out there on the computer saying “I’m objFridge.” If you run the program again, another piece of memory, a different one this time, would start saying “Look at me, I’m objFridge!” After running the program a number of times you’d have a whole bunch of memory claiming to be objFridge but not really doing anything useful, just sitting around feeling very self-important and thinking they’re needed. Because this memory thinks it’s being useful, it can’t be used for anything else. When you start the program again, you can’t use the objFridges that are already out there, they all think they’re busy, so the program has to make a new one every time.
You can probably imagine what happens to the performance of your computer after you’ve created a few thousand objFridges. These objFridges are taking up all your memory so no one else can use it. The way to avoid this is to always clean up your objects at the end of the program: set them to Nothing and release the memory so someone else can use it.
All right, we’re done anthropomorphizing our memory.
So why are we saying you don’t need to do this? Because unlike some of these other languages, VBScript cleans up after itself. As soon as the script ends, all the memory it was using is automatically released. So when you set your object to Nothing at the end, you’re just doing what VBScript was about to do anyway. Why waste all that typing?
Now, if you happen to create a very long and complicated script that does a lot of processing or runs for a long time, it might be worth your while to release some of the objects that you’re not using anymore so you can use the memory for something else. But for short scripts that are just completing a few tasks for you, don’t worry about it.
One more thing to note on releasing objects. When you set an object to Nothing, as we said, you’re making it so you can’t use the object in your script anymore. However, if that object created a running instance of an application, that application will continue to run. Even ending the script doesn’t do the trick; there’s no memory keeping track of it anymore, but the application is still running, which of course uses memory itself. For example, the following line of code creates an instance of Microsoft Excel:
Set objExcel = CreateObject("Excel.Application")
If you run this line of code in your script, Excel will start. Doing this will not shut down Excel:
Set objExcel = Nothing
Setting objExcel to Nothing will mean you can’t refer to that instance of Excel in your script anymore, but Excel will continue to run. For this type of object, you’ll either need to make Excel visible using the Visible property so the user can shut it down manually, or you’ll need to close Excel from your script:
Making Excel visible:
objExcel.Visible = True
So to summarize, setting objects to Nothing does not end a running application object, and it doesn’t do anything VBScript wouldn’t do for you anyway unless you have a very complicated, long-running, memory-intensive script. (Okay, you can breathe now.)
When Are You Required To Set Objects To Nothing? - Eric Lippert’s Blog
Unloading Objects from Memory - Microsoft Windows 2000 Scripting Guide
The Real World
We’re done with refrigerators and house plans, let’s look at how this works in a real script. We’ll take a look at the FileSystemObject class. The FileSystemObject class defines a bunch of methods and properties that allow you to create an object that will access your computer’s file system. (Note that this works only on the local machine, it won’t work against remote machines. But we’re not talking about that today, so let’s move on.)
If you take a look at the documentation on MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/jsobjfilesystem.asp), you’ll see that the FileSystemObject class defines quite a few methods, plus one property. Here’s a script that creates a FileSystemObject object and then checks to see whether a specific folder exists:
Set objFSO = CreateObject("Scripting.FileSystemObject") If objFSO.FolderExists("C:\Scripts") Then Wscript.Echo "Folder exists." Else Wscript.Echo "Folder does not exist." End If
As you can see, the first thing that happens is that we create a FileSystemObject object from the FileSystemObject class, and we call that object objFSO. So objFSO is the actual object that we can work with, or, put a little more technically, objFSO is an object reference to the instance of the FileSystemObject class that we’re working with (see where instantiating came from?).
Note: You’ll often see us refer to just “the FileSystemObject.” That’s because “the FileSystemObject object” sounds redundant and kind of stupid. But that’s what we mean.
Next we call one of the methods available to any object created from the FileSystemObject class, in this case the FolderExists method. We pass this method one parameter, the path to the folder whose existence we want to check for:
One thing we should mention about methods is that not only can they take parameters, but many of them can also return values. We could have done this:
IsAFolder = objFSO.FolderExists("C:\Scripts")
Then we would use the IsAFolder variable in the If statement:
If IsAFolder Then
But we took a shortcut and just put the method call inside the If statement. This type of shortcut is standard practice when you’re using a method that returns a Boolean (true/false) value like the FolderExists method does.
After that we just echo out a statement saying whether or not the FolderExists method found the folder.
Taking Multiple Actions by Using If Then Else - Microsoft Windows 2000 Scripting Guide
If…Then…Else Statement - VBScript Language Reference
FolderExists Method - Scripting Runtime Library
FileSystemObject Basics - Scripting Runtime Library
Well, that’s it. Time to go out and celebrate—you’re no longer one of the poor confused souls whose head spins at the mention of classes and objects. At least we hope not. If you are, well…congratulations on at least sticking it out to the end of the article. Go out and celebrate anyway.