If you’ve ever had to move one of your scripts to another machine, you may have run into a little problem. Every machine can be set up differently. This can pose a problem to administrators. This article describes how to avoid the most common pitfalls.
The problem arises due to the fact that most people write environment specific scripts. Using full path names and assuming certain programs are installed are just two of the very common mistakes that script writers can make.
If you plan on using your script on more than one computer, using full paths should be considered a big no-no. The most common example of this mistake is assuming that Windows is installed in the C:Windows directory.
Sure, it’s logical to believe that the majority of users will install Windows XP to its default location, but let’s not forget that a great number of systems running XP were upgrades from Windows 2000. Windows 2000 systems were installed to the C:WINNT directory by default.
But wait! Who’s to say that the user is even running Windows XP? I know a great many people running Windows Server 2003 and Windows Vista. My point is that you need to know your target audience, and if you don’t, you need to be prepared for anything.
Windows provides a simple method to programmers for ensuring platform compatibility. Every Windows system provides environmental variables. These unique variables provide specific information about the current Windows installation.
As an example, the %windir% variables will return the directory where Windows is installed. Another example is %homepath% which returns the user profile location for the currently logged on user. Let’s take a look at the default environmental variables.
Variable
Description
Sample Value
%systemdrive%
System drive letter
C:
%systemroot%
System root directory
C:Windows
%systemdirectory%
The folder in the system root that contains the system files
C:WindowsSystem32
%windir%
The “Windows” folder
C:Windows
%programfiles%
The Program Files directory
C:Program Files
%comspec%
The command line interpreter
C:WindowsSystem32cmd.exe
%temp%
Current temporary files directory in 8.3 format
C:DOCUME~1UserLOCALS~1Temp
%homedrive%
Drive letter associated with the current user
C:
%homepath%
Path to current user profile
Documents and SettingsUser
%homeshare%
Path current user’s share
%os%
OS generation
Windows_NT
%computername%
The current machine name
COMPUTERNAME
%userdomain%
The machine or domain that contains the current user’s account
COMPUTERNAME
%username%
Current user
User
%path%
The program execution path
C:Windows;C:WindowsSystem32
%allusersprofile%
All Users profile location
C:Documents and SettingsAll Users
%appdata%
Application data storage
C:Documents and SettingsUserLocal SettingsApplication Data
%cd%
Current directory string
C:Documents and SettingsUser
The above list of the most common environmental variables is not complete. There are user specific, hardware specific, and application specific variables as well. For example, %NUMBER_OF_PROCESSORS% will return the number of processors currently installed on the machine.
Environmental variables can differ to some degree between Windows versions, but the majority of common ones always stay the same. You can see what an environmental variable contains by echoing it from the command line, e.g. “echo %systemroot%” without the quotes.
For a more complete list of environmental variables available to Windows XP, you can read the Windows XP Professional Product Documentation on the Microsoft website.
WSH provides two ways to handle environmental variables natively. Let’s take a look at how to implement them in your scripts.
WSH provides us with the WshEnvironment object. This is a read/write collection that contains the environmental variables. You must use the WshShell object’s Environment property to access this object.
Set WshShell = CreateObject("WScript.Shell")
Set colEnvVars = WshShell.Environment
For Each objVar In colEnvVars
WScript.Echo objEnv
Next
The above example lists all of the environmental variables found in the WshEnvironment collection. Let’s take a look at the properties and methods available to the WshEnvironment object.
Properties
object.Item(name)
object.length
Methods
object.Count
object.Removename
You can use the Item property to return the contents of a specific environmental variable. The length property and the Count method both perform the same function and return the number of items in the collection. Finally, the Remove method deletes a specified item.
You may have noticed that the list of variables in the last example seemed a bit short. For example, the common %systemroot% variable wasn’t there. You may be wondering why.
There are three types of environmental variables: System, User, and Process. By default, the Environment property only returns those in the System list. However, you can specify which ones are returned. On Windows NT systems you can see the entire list in the following manner.
Set WshShell = CreateObject("WScript.Shell")
Set colEnvVars = WshShell.Environment("Process")
For Each objVar In colEnvVars
WScript.Echo objEnv
Next
There, now that’s better. So let’s take a little closer look at what we can do with environmental variables. We’ll begin by learning how to create our own.
Set WshShell = CreateObject("WScript.Shell")
Set colEnvVars = WshShell.Environment("System")
colEnvVars("MyVariable") = "This is my variable"
WScript.Echo colEnvVars.Item("MyVariable")
colEnvVars.Remove "MyVariable"
To add our own variable, all we need to do is add an item to the Environment collection. This is done simply by specifying the new item name and its initial value as with any collection.
Our script then goes on to display the newly created variable by checking it with the Item property. Finally, we delete it with the Remove method. That wasn’t so hard, was it?
Now that you know how to manipulate variables, let’s take a look at what they can be used for.
Environmental variables were intended to be used by applications for cross-platform compatibility. With that in mind, they were designed to house important information about the operating system. Most commonly they are used to house common folder paths.
There are many ways in WSH to determine the currently logged on user. Most often you would probably use the WshNetwork object or WMI, but the next example shows a very simple method using Environmental variables.
Set WshShell = CreateObject("WScript.Shell")
Set colEnvVars = WshShell.Environment("Process")
strUser = colEnvVars.Item("UserName")
You can also combine environmental variables with other methods. The next example also uses the FileSystemObject to connect to the current user’s desktop.
Set objFso = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell")
Set colEnvVars = WshShell.Environment("Process")
strDrive = colEnvVars.Item("HomeDrive")
strProfile = colEnvVars.Item("HomePath")
strDesktop = strDrive & strProfile & "Desktop"
Set objDesktop = objFso.GetFolder(strDesktop)
WScript.Echo objDesktop.Path
I’d like to show you one more way that WSH makes using environmental variables easy. Many times you’ll encounter environmental variables in path strings. You might see something like this:
%systemroot%System32Explorer.exe
The above path, of course, refers to the Explorer.exe program file. Suppose for a second that you encounter this path in one of your scripts. How would you handle that?
You could parse the string and poll the variable in the WshEnvironment collection and then put the string back together. Perhaps something like this:
strPath = "%systemroot%System32Explorer.exe"
Set WshShell = CreateObject("WScript.Shell")
Set colEnvVars = WshShell.Environment("Process")
x = InStr(1, strPath, "%")
y = InStr(x + 1, strPath, "%")
strVar = Mid(strPath, x + 1, y - x - 1)
strPart = Mid(strPath, y + 1, Len(strPath) - y)
strVar = colEnvVars.Item(strVar)
WScript.Echo strPath
WScript.Echo strVar & strPart
Basically, I’ve used a bunch of string manipulation to extract the variable name and then find the path associated with that variable. Then I piece it all together.
But look at all that code! Could you imagine having to write that every time? How much more code would it take if there was more than one variable in our string?
Luckily, WSH’s WshShell object makes things much easier. It provides the ExpandEnvironmentStrings method that does all of the work in the above code for us.
WSH also provides another simple way of accessing common system folders known as the WshSpecialFolders collection. Depending on the current version of Windows, the collection contains the folders in the following table.
AllUsersDesktop
Common desktop
AllUsersStartMenu
Common start menu
AllUsersPrograms
Common “All Programs”
Desktop
Current user’s desktop
Favorites
Current user’s Favorites
Fonts
System fonts
MyDocuments
Current user’s Documents
NetHood
Network Neighborhood or My Network Places
PrintHood
Printers and Faxes
Programs
Current user’s “All Programs”
StartMenu
Current user’s start menu
Templates
Templates folder
AppData
Application Data
Recent
Recent documents
SendTo
Send To folder
Using the WshSpecialFolders collection makes accessing any of these folders very easy and efficient. Consider what we went through to connect to the current user’s desktop in our earlier example and compare it to the following:
Set WshShell = CreateObject("WScript.Shell")
Set WshSpecialFolders = WshShell.SpecialFolders
WScript.Echo WshSpecialFolders("Desktop")
You can also perform a little shorthand by calling the SpecialFolders collection directly from the WshShell object.
Set WshShell = CreateObject("WScript.Shell")
WScript.Echo WshShell.SpecialFolders("Desktop")
As you can see, both of the previous examples perform the same task. The second example makes things a little easier by polling the WshSpecialFolders collection directly.
By incorporating Environmental Variables and Special Folders you should be able to create more portable scripts. It’s good practice to employ these techniques all of the time.
I will offer one word of caution if you are using environmental variables in a script that is designed to be used as a Schedule Task. It won’t work. Unfortunately, you’ll have to resort to either the SpecialFolders collection or hard-coded paths.
One last thing to consider when writing portable scripts is software versions. Many times there are substantial differences between different Windows releases. The same holds true for components such as the Windows Script Host.
If you’re employing code that was not available in a previous version, it is good to do a quick error check to make sure the proper version is available. Unfortunately, I’m out of space so that will have to wait for another article. Until next time, keep coding!