In "Scripting in Windows NT, part 1 ," I examined special characters, subroutines, and the if statement. In part 2 , I described the for and the replace statements. In this Daily Drill Down, I’ll cover three commands: set,call, and shift. I’ll also discuss file extensions and associations.
The set statement
The set statement is one we all use, with great frequency, in our code—from the simplest batch file to the most complicated script. For the uninitiated, this statement sets an environment variable to a value:
You then access the value of the variable as %variable%. Note: You do not need the double quotes as you did in the for statement.
You can also check the value of an environment variable on the command line by typing
This command will display:
When checking the value a variable is set to, you can partly specify the variable name:
which will display:
PROCESSOR_IDENTIFIER=x86 Family 6 Model 5 Stepping..
The results might be slightly different on your own system.
The result of the set command will set ERRORLEVEL to 1 if the variable is not set. So you could write
set windir ŠŠ set windir=c:\winnt
which looks to see if the variable windir is set and, if not, (‘ŠŠ’) sets it to a useful value.
Command extensions add a single switch to the set command, which provides another tool, previously missing from the scriptwriter’s box of tricks:
set /A expression
The /A switch lets you do arithmetic on environment variables. Here’s a very simple example:
set /a x=x+1
When this is executed on the command line, the value 2 is displayed. The operators supported are:
|( )||Used to group expressions|
|* / % + -||Normal arithmetic operators|
|<< >>||Logical shift operators|
|^||Bitwise EXCLUSIVE OR|
|=||Assignment operator—this should be preceded by any of the operators above (e.g., set /a x+=1)|
You’ll want to keep the following points in mind:
- Any non-numeric variables are converted to numeric before they’re used.
- A value of 0 is used for variables that have not been defined.
- The assignment operator needs a variable name to the left.
- Hexadecimal numbers can be specified by preceding them with 0x.
- Binary numbers are specified by the 0b prefix.
- Octal numbers are specified by the 0 prefix.
With the enhancements to the set command came enhancements to variable substitution. For example:
This replaces all occurrences of str1 in the environment variable PATH with str2. If str2 is empty, then all occurrences of str1 will be removed. If str1 begins with an asterisk, it will match everything from the beginning of PATH to the first occurrence of the string following the asterisk in str1.
In addition, the enhancements to the set command introduced the substring function. Here’s an example:
This statement returns the ten characters from the environment parameter PATH beginning at the sixth character. This method can be applied to any environment parameter and, as you’ll see later, can also be applied to positional variables.
The call statement
The call statement is a fairly innocuous statement—well, it was, until command extensions were introduced. Script writers originally used this command to execute another batch file, handing back control to the statement following call once that batch file completed—a form of subroutine call, except that the subroutine had to be external to the main batch file.
The syntax of the call command is
call batch_file_name [parameter [parameter]....]
With command extensions, we see a second form:
call :label [parameter [parameter]....]
Now, instead of putting the code in a separate batch file and having to keep track of both (or several if there are a number of subroutines), you can put the code all in one file. The return part of the subroutine nature of this command is provided by the statement
Here’s an example:
call :%USERDOMAIN% TestUser
reg update “HKLM\Software\Microsoft\Windows NT\CurrentVersion\RegisteredOwner=%USERNAME%”
net use h: \\HOPDC\C$
copy h:\ntreskit\reg.exe c:\windows
net use h: \\BRPDC\C$
copy h:\reskit\reg.exe c:\windows
First, a new, undocumented feature is introduced in the call statement. I have used a variable for the label—:%USERDOMAIN%. You can use this method in the goto statement in the same way. In this example, I’m assuming that there are two NT account domains that may not have a trust relationship, and I’ve designed this little script to work on any NT machine, regardless of the domain it is in. So, the script gets the domain from the standard environment variable USERDOMAIN, which is set to the domain the user is currently logged on to. It then calls the label that matches this domain name. It creates a mapping to the C$ share and copies the Reg.exe utility from the directory that contains the NT Reskit. It carries out a reg command, and then the batch file exits (goto :EOF).
In addition, expansion of batch script positional argument references (%0, %1, etc.) have been changed as follows (%* in a batch script refers to all the arguments—e.g., %1 %2 %3 %4 %5):
|%~f1||Expands %1 to a fully qualified pathname.|
|%~d1||Expands %1 to a drive letter only.|
|%~p1||Expands %1 to a path only.|
|%~n1||Expands %1 to a filename only.|
|%~x1||Expands %1 to a file extension only.|
|%~s1||Changes the meaning of n and x options to reference the short name instead.|
|%~$PATH:1||Searches the directories listed in the PATH environment variable and expands %1 to the fully qualified name of the first one found. If the environment variable name is not defined or the file is not found by the search, then this modifier expands to the empty string.|
The modifiers can be combined to get compound results:
|%~dp1||Expands %1 to a drive letter and path only.|
|%~nx1||Expands %1 to a filename and extension only.|
|%~dp$PATH:1||Searches the directories listed in the PATH environment variable for %1 and expands to the drive letter and path of the first one found.|
In the above examples, %1 and PATH can be replaced by other valid variable names, as I discussed in part 2.
The shift statement
While we are on the subject of positional parameters, it is worth mentioning the shift statement. This statement simply shifts the parameters along to the left—for example, %2 moves to %1, %3 moves to %2, and so on, with the original %1 being lost. Because there is no way to shift to the right, the %1 parameter cannot be recovered. The statement is
Surprisingly, command extensions have been applied even to this simple command. A parameter has been introduced that allows the shift to start at any position between 2 and 8. The statement can now be written as
where n is any number between 2 and 8. So, for example
would leave %1 and %2 intact, and shift %4 to %3, %5 to %4, and so on. In this form, the positional parameter defined by the switch is the one that is lost.
Command extensions and file associations
Now I’ll wrap up this Daily Drill Down with a quick note on the way command extensions in Windows NT 4 have improved the way you can execute commands.
If command extensions are enabled, external command invocation through the command line or the start command will change. Non-executable files may be invoked through their file association just by typing the name of the file as a command. (For example, Word.doc would launch the application associated with the .doc file extension.) You can create these associations from within a command script by using the assoc and ftype commands.
When executing an application that is a 32-bit GUI application, Cmd.exe does not wait for the application to terminate before returning to the command prompt. This new behavior does NOT occur if executing within a command script.
When you’re executing a command line by using CMD without an extension or path qualifier, CMD is replaced with the value of the COMSPEC variable. You thus avoid picking up random versions of Cmd.exe when you least expect them.
When you’re executing a command that does NOT include an extension, Cmd.exe uses the value of the PATHEXT environment variable to determine which extensions to look for and in what order. The default value for the PATHEXT variable is
Notice the syntax is the same as the PATH variable, with semicolons separating the different elements.
When you’re executing a command, if no match exists for any extension, the command looks to see whether the name, without any extension, matches a directory name. If there is a match, the start command launches the Explorer on that path. If you execute the command from the command line, that’s the same as using a CD /D command to that path.
I do not feel that this is a particularly useful enhancement. I like to know exactly what my scripts are doing, what commands they are running, and from what directory they’re running, rather than relying on some “side-effect” of ambiguity to get it right (or, perhaps, wrong). Remember, it may work fine on your own PC, but it may fail on another, or, worse, it may appear to work, when it has actually done something pretty nasty.
In this Daily Drill Down, I’ve discussed three commands: set, call, and shift. I’ve also examined file extensions and associations. In part 4 of this series, I’ll cover the commands start, title, pushd and popd, mkdir, rdir, time and date, at, and xcopy.
Richard Charrington’s computer career began when he started working with PCs—back when they were known as microcomputers. Starting as a programmer, he worked his way up to the lofty heights of a Windows NT Systems Administrator, and he has done just about everything in between. Richard has been working with Windows since before it had a proper GUI and with Windows NT since it was LANManager. Now a contractor, he has slipped into script writing for Windows NT and has built some very useful auto-admin utilities.The authors and editors have taken care in preparation of the content contained herein, but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for any damages. Always have a verified backup before making any changes.