Overview: Windows scripting currently comes in two major flavors, batch scripts (.bat or .cmd) and Windows Scripting Host (.wsh) files. Of the two, programmers generally pick the .wsh files, while administrators pick .bat files. Each of these types of files has advantages and disadvantages over the other, but this document shall only cover the .bat form of scripts. Why script over making a new program? One of the first things people say when they see a complex script, is why not just learn a real programming language. Because of this, I should first cover why we make scripts over full blown programs. The biggest advantage scripts have over exe files, a script does not need to be recompiled when you make changes to it. Since it’s just an text file, all you need is notepad to change how the program works. When talking about batch and Windows Scripting Host files, every Windows computer has the tools to make and edit the script, letting you change it without needing a compiler. It also means you can make the script on any Windows computer, even if you do not have access to a compiler. Differences in .bat and .wsh files: Both types of scripts have their own uses in Windows. The .wsh scripts offer much more power then .bat, but add extra complexity to the mix. Most wsh files are Visual Basic script, with a syntax based on VB. A VBScript program can also be placed in a HTML Application file (.hta) and be given a GUI. An .hta file is nothing more then a standalone .html file named .hta. When ran, it looks and acts like a exe file, but is really nothing more then a web page. Batch files offer less power then wsh files, but can be quicker and easier to make. When working with file operations, batch files are normally better suited then even full blown programming languages. While you may need a findfirst() and findnext() loop to gather a list of file names when in C++, a batch file can use a simple for loop:[code] for %a in (*.divx) do echo %a is a movie file. [/code] Batch files are nothing more then command line interface (CLI) commands saved into a file, or batch, to be ran at one time. The most basic usage of a batch file is to execute more then one program at once, or a batch job. But any job that can be done via the command line can be automated by batch files, and scheduled to run at a set time, making batch files useful for automation tasks. Notes on command line interface (CLI) usage: There’s a few things you should know about the command line before you can make batch files. If you run cmd on 2K\XP\2K3 you get the basic command prompt. From here, you can run any program on your computer, just like with explorer. One of the basic parts of a command line are parameters, or arguments. These are extra bits of info that control how a called program will run. For example:[code] dir *.txt[/code] The command is dir, and the first parameter is *.txt. Another command is this:[code] dir /s *.txt[/code] While it is almost the same as the first command, this one has two parameters. The first one, /s, tells dir to list files in subdirectories, while the second parameter, *.txt, tells it to find any .txt files. To separate the different parameters, you place spaces between them. This is also one of the most basic problems people have when learning scripting and the command line, the problems with spaces. For example:[code] del d:\batch files\target.txt[/code] This may look ok, but it will return an error. Why? Because the del command sees two parameters, d:\batch and files\target.txt. So it tries to delete d:\batch, and can’t find it. Then it tries to delete files\target.txt and can not find that. To solve this, you wrap parameters in double quotes if they contain spaces, like this:[code] del “d:\batch files\target.txt”[/code] Another major issue with scripting, is the active directory (This is not related to Active Directory, windows LDAP implementation) When you execute a batch file, you generally are in the same directory as the batch file. But sometimes you execute a batch file from another location. When this happens, depending on how you launched it, the batch file may be active in the wrong folder. For example, make a new folder on your desktop. Inside this folder, make a sub folder. Inside this sub folder, make a new batch file with these two lines:[code] @Echo off Dir | Find “Directory”[/code] Now open a command line in the same folder as the batch file, and run it:[code] J:\New Folder (6)\New Folder>test.bat Directory of J:\New Folder (6)\New Folder[/code] It replies with the directory you are currently in. Now type cd .. to move up one folder, and run the batch inside the sub folder, like this:[code] J:\New Folder (6)\New Folder>cd .. J:\New Folder (6)>"New Folder\test.bat" Directory of J:\New Folder (6)[/code] See what happened? The first time we can it, it did the dir command inside the folder the batch file was in, since we were running the batch file the same directory. The second time we ran it, we ran the batch file from a remote directory, and the batch file ran the directory command from the directory we were active in. This is known as the working directory. Back inside explorer, right drag the batch file icon (right drag is just like dragging a normal icon, but you press and hold the right mouse button, not the left) When you release the icon, you get a copy, move, make shortcut menu. Pick make shortcut, then right click the short cut, and hit properties. On the shortcut tab, you see an edit box with the label Start In: next to it. When you make shortcuts in windows, this is the line that tells the program where to set it’s active directory. To see how this works, first change the batch file to have the line pause at the end, so the complete batch file looks like this:[code]@Echo off Dir | Find “Directory” Pause[/code] Next, change the start in for the shortcut to c:\windows. (Or to where ever your windows is installed. C:\winNT by default on 2K) Now run the shortcut, you should see this line:[code] Directory of c:\windows[/code] The variable %cd% also reports the current directory. The last major issue people have when first making scripts, is the window closes soon as they run it. That is how batch files are supposed to run. If you want to window to stay open when you’re done, place a pause at the end of it, just like in the test batch file we just wrote. What can batch files do? Command 1: Executing other programs. To know how to make a batch file, you need to know what they can do. Batch files can run any program that works with the command line, and every Windows program can be started from the command line, and most can be automated from the command line. Let’s say you want a text file opened at login each morning. A batch file with this line is all you need:[code] notepad test.txt[/code] So, how does it work? Well to execute a file from a batch file, all you do is type in the name of the file, just like the command line. If it ends in .exe or .bat, then you do not need the extension of the file. Because notepad is in %systemroot%\system32, it is in the system path, so you don’t have to write out the full path to the program to run it. If you want to execute a file in another directory, you have to type out the full path name. Many programs are designed to load other types of files. For example, notepad loads text files, paint loads bmp files, ext. In most cases to make a program load another file, the file must be a parameter in the call. For example, type notepad test.bat in the command line and it will load test.bat if it can find it, otherwise it will ask if you want to make it. As a matter of fact, this is how explorer works. When you double click an icon, for example a text file, it looks up what command to run in the registry. Unless the file type uses persistent handlers, then it’s stored in the value shell\open\command. For example a room editor for my game uses a file type .room. When you set the file types to be associated to the program, it makes a registry key with this line:[code] "D:\Base\Programming\FromLaptop\Projects\Clean Source II\Editproject.exe" "%1" [/code] The first part, the path, just points to the exe when you set it, while the second part, the “%1” is a variable that returns the program that you clicked. For example, if you double clicked d:\base\rooms\room1.room, then explorer runs this command:[code] "D:\Base\Programming\FromLaptop\Projects\Clean Source II\Editproject.exe" “d:\base\rooms\room1.room" [/code] So with this basic knowledge, you know how to have a batch file start any program on your pc. Let’s see how this works with a test batch file. Make a new one with these lines:[code] notepad calc [/code] Now when you run it, notepad and calc should start, and they will. But it may not be how you think. Notepad will open, but calc won’t. Once you close notepad, calc starts up. This is default on how a batch file works, it won’t run the next command till the last one is ran. If you want a command to start without this wait, you can use the start command. Like this: [code] start notepad calc[/code] However, the start command needs a few other bits of into before you can go use it. The biggest thing to keep in mind with the start command, if you run it with a program, you need to place the program’s name in double quotes. So c:\program files\mirc\mirc.exe needs quotes around it. However, start uses the first quoted string for the title of the new window, if it can. For example:[code] start "notepad"[/code] This will not open notepad. It will open a new cmd window, and the title bar will say notepad on top. To fix this, just place an empty quote in front of the command. Like this: [code] start "" "notepad"[/code] Start is nice if you want to start a program up minimized. In this case, you just add the /min parameter like this:[code] start /min “” “notepad”[/code] If you want start to stop the batch file until the program is closed, you can use the /wait switch. Like this:[code] start /max /wait “” “notepad”[/code] This will start notepad maximized, and will continue running the batch file once notepad is closed. A few other parameters start will take include /LOW, /NORMAL, and /HIGH. These control the process level of the program. For example I encode a lot of .divx video files. I like to run my encoder on low priority, so if anything such as explorer needs cpu time, it gets it first. This keeps the system from suffering from lag, and lets the encoder use up all unused cpu time. So now you should know how to chain programs in batch files, and control how they start up (minimized, maxed, low priority, ect..) Command 2: Variables Batch files are a type of programming language. While they are not close to being like C\C++, they do follow the very definition of a computer programming language. And something just about every language out there has is support for variables. Batch files support three types of variables, the % ones, such as %1, %2, ect. They also support the normal %% types that the user can set inside the batch file. The last type of variable is %% such as %%l, %%a, ect. These are used in for loops, and will be talked about in the for loop section. If you remember back in the last section, I mentioned %1 in the part on running commands. The %1 style variables work exactly the same. Inside the batch file %1 holds the first parameter, %2 holds the second one, ect. So if you made a batch file called test.bat and ran this line:[code] c:\>test param1 param2 “param 3” [/code] then %1 would hold the string param1. %2 would hold param2. %3 will hold “param 3”. Note that %3 will return it with quotes around it. This can sometimes give you problems when working with the variables, so you can force it to strip quotes. %~1, %~2, ect will return the variable with no quotes around it, so %~3 will return param 3 in this case. There are two special commands you should know about, %* and shift. The %* command means to return all parameters. If the batch file was ran with this line:[code] c:\>test.bat this is a test of all the param strings[/code] then %* would return this is a test of all the param strings. The second command is shift. When ran, it removes the variable in %1, and replaces it with what’s in %2. It then replaces %2 with %3, ect. If %1 is the only assigned variable, then it empties is, meaning “%1” would return “”. Shift command, along with an if statement and goto loop, can be used to make a program grab all parameter strings in a batch file. Also note that %0 returns the batch file that is currently running. The second type of variable is the %% type. There are some predefined ones, such as %computername% and %username%, and you can also make your own using the set command. For example, make a batch file like this:[code] @Echo off Echo %Username% ran batch file %0 on %computername% at %time% %date% Pause[/code] To get a list of premade variables, type set with no other parameters. To make your own variables, you use the set command, the name of the variable, equal sign, and what you want it to be, like this:[code] set MyVariable=Lalalala[/code] This sets %MyVariable% to Lalalala. Note that variables can hold integers and strings, they are all universal. To use Arithmetic on a variable, you use the /a switch in set. For example, set /a Test=1+5 will set %test% to 6, while set Test=1+5 will make it 1+5 as a string. You can also use += -= *= and the like, so set /a test+=1 is the same as set /a test=%test%+1 Besides the /a switch, the most used switch is the /p switch, or prompt. When using set /p it sets the variable to whatever the user inputs. The string after the = is the question they prompt the user for. For example:[code] C:\Documents and Settings\Ozzy_98>set /p test=Please enter a string: Please enter a string: hi! C:\Documents and Settings\Ozzy_98>Echo %Test% hi![/code] There’s two more things you should know about variables. They work as commands, so if you did this:[code] Set MyVar=dir %MyVar%[/code] Then is will do a dir command. Another thing you should know is delayed expansion. In a for loop, %% style variables do not change until the end, so for example, if you set test to 0 before hand and ran this code:[code] For /l %%a in (1,1,10) do Set /a Test+=%%a & echo %Test%[/code] it will return all 0’s, then after the loop is done, %test% will be equal to 55. To have it check during the loop, you need to enable delayed variable expansion, off by default on Windows installs. The command to enable delayed expansion is SetLocal ENABLEDELAYEDEXPANSION. If you forget it, setlocal /? lists is from the command prompt. It’s best to have the setlocal as one of the first few commands in the batch file if you plan on using it. With delayed expansion, you can now use !! form of a variable. %test% and !test! will both return the same value, that of %test%. The only difference is inside loops or command groupings, !test! will return the correct value inside the loop, while %test% will return the value before entering the loop. Delayed expansion also has one side effect, nesting variables. Say you have two variables named %MyArray[0]% and %MyArray[1]%. You can access this with a variable where the number is, in the format !MyArray[%Element%]!. Here’s an example:[code] @Echo off SetLocal ENABLEDELAYEDEXPANSION Set Element=0 Set MyArray[0]=First Element Set MyArray[1]=Second Element Echo !MyArray[%Element%]! Set /a Element+=1 Echo !MyArray[%Element%]! Pause[/code] Running this batch file returns this:[code] C:\Documents and Settings\Ozzy_98>test First Element Second Element Press any key to continue . . .[/code] Note that it MUST be in the form of !Variable%Variable%!, with the delayed form on the outside, and the %s form on the inside. %MyArray[!Element!]% is not valid, and will return an empty string. As you can see from this example, you can simulate arrays using this technique. Command 3: Variable Manipulations This command should really be considered a subcommand of variables. When a variable is in the %1 form, or %%a in a for loop, there are some set manipulations you can do to change how they work. For example, %~1 as you saw will remove any quotes from around the variable. You can also use other letters after that, for example %~n1 will return the name of the file in %1, So c:\batch files\test.bat would return test. And modifiers can be combined, so %~dp0 will return the drive and path of the batch file. Here’s a list of modifiers from the for command's help:[code] %~I - expands %I removing any surrounding quotes (") %~fI - expands %I to a fully qualified path name %~dI - expands %I to a drive letter only %~pI - expands %I to a path only %~nI - expands %I to a file name only %~xI - expands %I to a file extension only %~sI - expanded path contains short names only %~aI - expands %I to file attributes of file %~tI - expands %I to date/time of file %~zI - expands %I to size of file[/code] The second form of variable manipulations only works on the %% style ones. %VariableName:~1% tells it to skip the first letter. So if the variable %test% is Hello, then %test:~1% will print ello. You can also use a -1, meaning skip all but the last letter. so in this case, %test:~-3% will print llo. If you have a second number, like this: %test:~1,1% the second one tells it how many letters to print. For example, %Test:~0,3% tells it to skip 0 letters, and print the next three, hel in this case. Again, you can use negatives, so %Test:~0,-1% tells it to print all but the last letter. Using this with for loops will let you scan a string for a letter\phrase. Check this batch file for an example:[code] @Echo off SetLocal ENABLEDELAYEDEXPANSION Set TestString=Find Hi in this string. Set counter=1 :Loop If "!TestString:~%Counter%,2!"=="Hi" Echo Found Hi at position %Counter% Set /a Counter+=1 If "!TestString:~%Counter%,1!"=="" goto endloop Goto :Loop :EndLoop Pause[/code] It will return “Found Hi at position 5” (Remember batch strings are 0 based anyways) Command 4: Echo Echo is one of the most used commands in batch files. It serves two functions, the first is to turn on\off echoing of commands. For example, when you make a batch file, it will show your commands like you were entering them. So to stop it, most batch files use Echo off command first line. Leaving echo on makes the batch files very ugly, but also helps debugging, as you can see what commands were being ran. To hide echoing of a single command, you can use the @ symbol before it. As a matter of fact, the line that starts most batch files is @Echo off, the @ being used to hide the Echo off command. When working with the command line, and not inside batch files, @ can be used to hide commands inside for loops. For example, in the command line try this:[code] For /l %a in (1,1,10) do echo %a[/code] Now try this:[code] For /l %a in (1,1,10) do @Echo %a[/code] The second use of echo is to print to the screen. Echo hello world will print the line hello world. You can use any variables you want in the echo commands. Printing a blank line, or printing just the lines on or off, can be kind of tricky. To print a blank line, use Echo. just like that. If you wanted to print a period, use echo . instead. Echo skips the letter right after it, so when you use Echo Hello World there isn’t a space in front of hello. Command 5: Redirection This part will cover two topics, redirection, and piping. Redirection is simple, but has lots of power. When you run a command, it normally sends data to the screen. Using > or >>, you can send it to a file (Or even a printer or some other device) When you type a command such as dir, if you used a redirect like this:[code] dir > test.txt[/code] then you would see nothing on the screen, but you now have a text file called test.txt, that shows all that dir would have. The differences between > and >> is simple. Using > will cause it to overwrite the file, erasing everything in it before it writes. Using >> causes it to append to the file. Using redirects like this is great when used with echo command, letting you write to a file. Take this example here:[code] @Echo off Set Filename=index.html Set Title=IP Address Configuration For All Computers Set BGColor=c0c0c0 Set Background= Echo ^ >%filename% Echo ^ >>%filename% Echo %Title%>>%Filename% Echo ^ >>%filename% Echo ^ >>%filename% Echo.>>%filename% Echo.>>%filename% Echo ^ >>%Filename% Echo ^ >>%Filename% Echo ^^
>>%Filename% Echo ^ >>%Filename% Echo %Pages% These Computers Reported: >>%Filename% Echo ^ ^ ^ >>%Filename% For /l %%a in (1,1,10) do ( Echo ^ ^ >>%Filename% Echo ^ Computer Name: %%a ^ ^ >>%Filename% ) Echo ^ >>%Filename%[/code] This batch file generates an html page. It actually used to scan a folder by using a for %%a in (computers\*.html) do loop, but I changed it to a simpler loop so it would work without the extra files. As you can now see, rather then making just a static txt file, your scripts can generate web pages. The biggest thing you may have noticed, a lot of ^’s in the code. The ^ is used for escape character, meaning “The code after this is a special character, but treat it like a normal letter”. So ^> will not redirect the text like it normally would. & is also a special character, so it too must be ^’ed. Also, if you want to print a %, you need to use two, %%. The redirects, > and >>, are actually seen by the computer as 1> and 1>>. The one means to print out any good messages. There’s also a 2> and 2>>, meaning print any errors. Try this code:[code] dir khjwkh>error.txt[/code] You should see, on the screen, File Not Found. To capture error messages, you use 2>. And yes, you can combine both 1 and 2, to have dir 1> good.txt 2> error.txt. If you want to print to both the screen and a file at once, you may want to make a procedure to do it for you. (Procedures are covered later) Here’s an example:[code] @Echo off Set TextFile=Test.txt Set Write=Call :Writeln Goto Main :Writeln Echo %* Echo %*>>%TextFile% Goto :Eof :Main %Write% Testing[/code] Not only does it write to the screen, but it writes to the file of your choice. I did the Set Write=Call :Writeln to make it easier on me, so I don’t have to type call :Writeln each time I want to print. The second form of redirection isn’t used as much. It’s the < form. It sends input into the command from a file. Have you ever ran a command line program like nslookup, that can go into an interactive mode, where the prompt changes? Well, you can write all the commands to a text file using >, then use < to redirect it back into the command. It even sends carriage returns, so you can completely automate the program. But most programs, such as nslookup, can be ran all on one line, so this isn’t used too much in scripting. The last item to cover, related to redirection, is piping. Pipes send date from one program to another. The most commonly used programs for this, more, sort, and find. A common 3rd party one is grep. To redirect, you use the |, like this:[code] Ping 127.0.0.1 -n 1 | find “TTL”[/code] This will print only lines that have TTL in them, such as ping replies. That command right there even makes a crude network scanner:[code] for /l %a in (1,1,254) do @ping 192.168.40.%a-n 1 -w 50 | find "TTL"[/code] Not the fastest of programs, but it’s simple to remember when on-site. This can also send data to interactive programs, like this:[code] Echo google.com | nslookup [/code]