# Windows Shell Scripting

{{< snippet "old" >}}

This article is translated to
*[Serbo-Croatian](http://science.webhostinggeeks.com/windows-shell)* by
*[WHGeeks](http://webhostinggeeks.com)*. Thanks\!

I plan to move much of this to {{< snippet "jp-github" >}} at some point...

## Introduction

The term "shell script" comes from UNIX, the DOS term is "batch files."
UNIX shell scripts are very powerful and flexible, they are essentially
programming languages unto themselves. Windows or more rightfully DOS
batch files are a pale imitation. However, sometimes you need to write
something that will just **work** on any plain old out-of-the-box
Windows install someone has--without adding all kinds of other tools.

Before getting too deep into this topic, consider if there is another
tool you might use. Here is a list of tools, all of which are far more
powerful, flexible and are probably easier to use than batch files:

  - **{{< xref "/source/perl.html" "Perl" >}}** *( [Perl for
    Windows](http://www.activestate.com/solutions/perl/))*
  - *[JP Software's](http://www.jpsoft.com/)* *[4Dos (now
    free)](http://jpsoft.com/downloads/4dos/4dos750.exe)* & *[TCC/LE
    (was 4NT, now free)](http://jpsoft.com/tccle-cmd-replacement.html)*
    (almost as powerful as UNIX shell scripts, but with a DOS/Windows
    "flavor")
  - *[NirCmd](http://www.nirsoft.net/utils/nircmd.html)* Freeware
    command-line tool
  - UNIX tools ported to DOS/Windows, e.g. the
    *[UnxUtils](http://unxutils.sourceforge.net/)* and *[GNU Win32
    ports](http://sourceforge.net/projects/gnuwin32/)*.
  - Bash or other UNIX shells ported to DOS/Windows, e.g. the *[CygWin
    project](http://sources.redhat.com/cygwin/)*. It may not be totally
    obvious how to get things at the Cygwin site. Either download the
    "*[setup.exe](http://sources.redhat.com/cygwin/setup.exe)*" program,
    which will guide you through everything, or use the *[mirrors
    page](http://sources.redhat.com/cygwin/mirrors.html)* to find a
    mirror site and get everything yourself.
  - *[AutoIt](http://www.autoitscript.com/)* Free scripting and
    installation language for 95, 98, ME, NT4, 2000, XP, 2003. No
    run-times and may be compiled into an EXE.
  - *[KixTart](http://www.kixtart.org/)* (and *[a KixTart script
    library](http://www.kixscripts.com/scriptlibrary/)*)
  - *[REXX](http://www-4.ibm.com/software/ad/rexx/)*
  - And there are tons of other free scripting tools for Windows out on
    the 'Net.

### Powershell

If you follow Windows at all you will be aware that
*[Powershell](http://en.wikipedia.org/wiki/Powershell)* is Microsoft's
new command line tool, and that you will be required to use it more and
more with newer Windows versions. That is a Good Thing, in my opinion,
and it only took them about 20 years to realize, but that is not covered
here\! I don't really do Windows anymore and I have not bothered to
learn Powershell, which reminds me unpleasantly of Java's verbose
ugliness. So this page is somewhat historical, though most everything
should work to at least Win7.

If you are interested in current Windows command line scripting and
Powershell (and if you like Windows you should be), there are any number
of other resources and books that will help. These are probably good but
I haven't read them:

  - *[Windows PowerShell for
    Developers](http://www.amazon.com/Windows-PowerShell-Developers-Douglas-Finke/dp/1449322700/)*
  - *[Windows PowerShell Cookbook: The Complete Guide to Scripting
    Microsoft's New Command
    Shell](http://www.amazon.com/Windows-PowerShell-Cookbook-Scripting-Microsofts/dp/0596801505/)*

-----

## A Tweak

Did you know that Window's `cmd.exe` has file and directory name
completion, like UNIX shells? It does, and that can be amazingly useful.
But in most versions of Windows it's not turned on by default. (I
*believe* it may be on in Windows 2003, but can't swear to it.)

To enable file and directory name completion under Windows, download
[this registry file](/public/source/NT-Tab.reg.txt) and remove the
.txt, then double-click on it and answer yes to the question about
importing into the Registry. If you can't download for some reason you
can copy the text below into a new file and import it, or just open
regedit, navigate to the key, and change the values for CompletionChar
and PathCompletionChar to 9. One you've done that, open a new command
prompt and type `dir c:\win` then hit the TAB key and watch what
happens. Of course the up arrow and other command line editing functions
will still work as always.

```
REGEDIT4

; NT-TAB.reg -- Sets the NT Command Completion Character to TAB
; Use "RegEdit /s NT-TAB.reg" for silent installations
; v1.0 1998-10-22 JP Vossen  http://www.jpsdomain.org/
; v1.1 2001-09-06 JPV Added PathCompletionChar
; v1.2 2003-03-30 JPV Added .DEFAULT and SOFTWARE sections

[HKEY_CURRENT_USER\Software\Microsoft\Command Processor]
"CompletionChar"=dword:00000009
"PathCompletionChar"=dword:00000009

; Can also do this if you have the permissions
;[HKEY_USERS\.DEFAULT\Software\Microsoft\Command Processor]
;"CompletionChar"=dword:00000009
;"PathCompletionChar"=dword:00000009
```

-----

## The Dirt

OK, if you are still going to go through with this, the first thing you
need is Tim Hill's *[Windows NT Shell
Scripting](http://www.amazon.com/Windows-Shell-Scripting-Tim-Hill/dp/B00297Q2ZO)*,
otherwise you don't have a chance. For Windows 9x/ME, you are still
toast, but for NT/2000 this book is really great. It's the only way you
can navigate the bazaar, inconsistent, contradictory and often asinine
"scripting" language built into cmd.exe.

Using material from that book, plus my own almost 20 years experience
with DOS batch files, I still had a hell of a time writing the following
script. All it does is give you some basic file information (similar to
UNIX stat) and tell you if a file will fit on a floppy disk.

-----

## The Scripts

**Clicking on the name of a script will open that script in a new
window.**

[Stat](/public/source/stat.cmd.txt) v1.0 2000-12-03
: NT Batch file to provide similar info to the UNIX (file) stat command.

[nt-cmd.cmd](/public/source/nt-cmd.cmd.txt) v1.2 2001-08-29
: Sample/demo code I wrote after reading *Windows NT Shell Scripting*.

[drives](/public/source/drives.cmd.txt) v1.1 2000-01-11
: A tiny script to display active drives.

-----

## Simple Sleep

Another of the many lacking tools is a simple "sleep" command, but you
can easily fake that using the "ping" command of all things. The
following will "sleep" for about 5 seconds, give or take:

```
C:\> ping -n 5 localhost \> NUL
```

Obviously you adjust the 5 as needed for the number of seconds. You can
even write a trivial "sleep" function in your scripts:

```batch
@echo off
REM sleep_demo.cmd--Simple "sleep" command demo
REM 2012-07-26

echo Before sleep
call :sleep 7
echo After sleep

REM End of Main program
REM ###################################################################
goto :EOF

REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM sleep for a specified number of seconds, more-or-less...
REM Called like:  call :sleep 7
:sleep
    set sleep_secs=%1
    ping -n %sleep_secs% localhost > NUL
goto EoF
```

-----

## The Date

### How to get and use dates and time in Windows scripts.

This is trivially easy in UNIX. You want to copy a log file to a dated
name? "cp mylog \`date '+%Y-%m-%d'\`-mylog" will copy mylog to
2002-11-27 (as of this writing). What could be easier? But in Windows,
it sucks.

There are two basic ways to approach this, both with advantages and
disadvantages. The native way is the "for" and "date /t" commands under
NT/2000/XP. These do NOT work under Windows 9x and they do not
consistently use 2 digit time fields, which totally screws you up if you
need the time. The second way is to use the UNIX date command, then do
whatever you please. This is very flexible, but requires you to download
and have the executable (*[date](http://unxutils.sourceforge.net/)*)
handy. You will also want to rename it (I use udate.exe) so you don't
conflict with the built-in date command.

UPDATE (2012-07-26): All versions of Unix "date" commands that I have
tested under both WinXP and Win7 have a bug that causes them to skip
*[skip Mar-11 and/or
Apr-04\!](https://sourceforge.net/tracker/?group_id=23617&atid=379173)*
That's pretty annoying but has never been fixed as far as I know. Since
it affects both tools I've tested (UnxUtils and GNU Win32), I suspect
the Windows strftime lib is the problem. But I can't prove it. And
someone else replied to the bug he could not reproduce the problem. So
I'd say it's something I'm doing, but I find it off that both the WinXP
I've been using forever and a much newer Win7 do the same thing.

**UPDATE (2003-06-07): Here is a third way that's trivial\!** It seems
there are built-in but undocumented environment variables %time% and
%date% in Windows 2000. I have not tested other platforms (let me know
if you do). Due to the format, you can't easily use the date in file
copy operations (for example), but the time should be OK. And it's by
far the easiest option if you are just going to display (writing to a
log file or something).

```
C:\> echo %date% %time%
Sat 06/07/2003 18:32:30.52
```

### Windows Trivial

```
@echo off
REM Play with W2K date/time env. vars.

echo The date: %date%
echo The time: %time%
```

**UPDATE (2006-05-11): Here is a another trivial way\!** Thanks to
Richard Blake (RBlake {at} nea {DOT} org) for this great hack. In
addition to the above %time% and %date% variables, there is a
*%VAR:offset,len%* construct documented for the SET command, which works
elsewhere. As above, the use of a two digit time code can mess you up,
but for just the date it will work very well. Code to deal with non zero
padded hours is left as an exercise for the reader.

```
C:\tmp> set MyNewFileName=%DATE:~10,4%%DATE:~4,2%%DATE:~7,2%%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%

C:\tmp> echo %MyNewFileName%
20060511 21921
```

This RedmondMag.com *[Backup Basics in Windows Server 2008
R2](http://redmondmag.com/Articles/2010/04/01/Backup-Basics-in-Windows-Server-2008-R2.aspx?Page=2)*
article expands on the same method, but they are not portable because
they depend on how your system time is displayed, and that will vary
from machine to machine based on locale and user preference. For
example, I loath any date/time format except for
*[ISO8601](http://en.wikipedia.org/wiki/ISO8601)* so I have my Windows
formats set as close to that as possible, which then breaks the
assumptions in the first block:


```batch
@echo off
REM date_demo.cmd--Simple date parsing demo
REM 2012-03-10

echo Current dates (Windows default date format for US)
set year=%date:~10,4%
set month=%date:~4,2%
set day=%date:~7,2%
set hour=%time:~0,2%
set min=%time:~3,2%
set sec=%time:~6,2%
echo Date: %date% Time: %time%
echo ISO-8601: %year%-%month%-%day%_%hour%:%min%:%sec%

echo.
echo Current dates (ISO-8601 date format)
REM 2012-03-10
set year=%date:~0,4%
set month=%date:~5,2%
set day=%date:~8,2%
set hour=%time:~0,2%
set min=%time:~3,2%
set sec=%time:~6,2%
echo Date: %date% Time: %time%
echo ISO-8601: %year%-%month%-%day%_%hour%:%min%:%sec%
```

### Other Ways

  - [windate](/public/source/windate.cmd.txt) v1.0 sometime in 2001 or
    2002
    Native Windows Date commands
  - [unixdate](/public/source/unixdate.cmd.txt) v1.0 sometime in 2001
    or 2002
    Using a UNIX date command in Windows

-----

## Getting Input

There are various tools like ask.exe and choice.exe that allow you to
get input. There there's an even easier, although undocumented, way: set
/P. As in:

```batch
set /P MyAnswer=Your Prompt Here!
```

That prompts the user with "Your Prompt Here\!" and puts whatever they
type into %MyAnswer%. Very cool.

-----

## Simple Utilities

Except for FindZero.bat, all of these batch files will work under DOS,
or any Windows.

  - DOS Commands are **not** case sensitive, unlike UNIX commands.
  - An "@" as the first character of a line prevents the command from
    echoing whether echo is on or off.
  - *echo.* will echo a blank line (CRLF).
  - Command line parameters are specified with %1, %2, etc. not $1, $2
    as in UNIX.
  - %0 is the name of the program, as invoked. In other words, if you
    type "mybatch" %0 will be "mybatch". If you type
    "c:\\utils\\mybatch.bat" %0 will be "c:\\utils\\mybatch.bat".
  - ^G is a 'control G' which makes the console beep. This tiny [batch
    file](/public/source/beep.bat.txt) has a ^G in in, which you can
    cut & paste into scripts. There are lots of other ways to get
    control characters into files, but they depend on your OS and text
    editor. In most DOS windows, holding down the \<ALT\> key while
    typing the ASCII code on the numeric keypad will produce that
    character. ^G is 007, you you hold down \<ALT\>, type 007 on the
    numeric keypad, then release \<ALT\> to get a beep.
  - Tim Hill's *[Windows NT Shell
    Scripting](http://www.amazon.com/Windows-Shell-Scripting-Tim-Hill/dp/B00297Q2ZO)*
    for much more information and detail. Much of the book applies to
    DOS and Windows (other than NT) as well.

### AddPath.bat

```batch
@path=%1;%path%
```

### MCD.bat

```batch
@md %1
@cd %1
```

### [auto-ftp](/public/source/auto-ftp.cmd.txt) v1.2 1999-09-16

Automatically Download a file using FTP (not secure\!).

### CLR.bat

```batch
@echo off
cd c:\
cd d:\
c:
cls
ver
```

### [aformat](/public/source/aformat.cmd.txt) v2.4 2002-11-09

Format Floppy with no user prompts.

### SPrompt.bat

Requires ANSI.sys, included with DOS & Windows, or PC Magazine's free
[AnsiCom](/public/tools/ansicom.zip).

```batch
@echo off
REM SPrompt.bat -- Dynamically Set Prompt
REM Created sometime in 1992
REM 03-Mar-1998 JPV
REM 19-Feb-1999 JPV Added "neat" prompt from JPS mail list

REM Neat PROMPT `$+[%user@$P]%@EXECSTR[if %@LEN[%_CWD] GT 20 ECHOS $_:$s]`

prompt $e[0;33;1;44m$P$e[36;44m$G $e[0;37;44m
if not "%1" == "" prompt $e[32;1m%1 %2 %3 %4 %5 %6 %7 %8 %9$_$e[33m%prompt%
rem prompt $e[s$e[1;7f$e[0;45;37;1m$e[K($z)   $d   $t$e[u$e[1m$P$e[0m$G $e[0m
rem set WINPMT=$e[0;33;1;44mEXIT to Windows$_$P$e[36;44m$G $e[0;37;44m
if {%OS%}=={Windows_NT} prompt $P$G
```
### WhoAmI.bat

Requires Microsoft Networking to be installed and active, and the DOS
find command. If you have a UNIX find command in the path, you'll
probably get a "No such file or directory" error.

```batch
@echo off
echo.
net config /yes | find "name"
echo.
pause
```

-----

## Sending e-mail

Something else that is taken for granted on UNIX is the ability to send
e-mail from the command line or a script. As usual, windows makes this a
challenge. There are a few free and commercial solutions for this,
including but not limited to the following list (I've only ever used
Blat):

1.  *[Blat](http://www.blat.net/)* "is a Win32 command line utility that
    sends eMail using the SMTP or NNTP protocols."
2.  *[NTsendmail](http://www.ntsendmail.com/)* "is Highly Acclaimed UNIX
    Sendmail replacement for NT. NTsendmail is realeased under the GNU
    Public License. NTsendmail was designed to enable script writers to
    use their UNIX CGIs on Windows 95/98/NT/2000."
3.  And I'm sure there's at least one or two Perl modules that can do
    this.

-----

## Upload from Frontpage to your ISP

I used to use MS FrontPage to maintain this site (don't ask me why). My
old ISP did not support FrontPage or its extensions, for excellent
security reasons. Using FrontPage to create pages, then uploading them
to a hosted site is a gigantic pain in the ass because of the way
FrontPage keeps all of its proprietary information in various
"\_VTI\_CNF" and other subdirectories. So simply zipping up the
directories and dumping them onto a host is not ideal. So I came up with
the following solution.

The old code I posted to a Netaxs news group was WRONG in places\! THIS
stuff works.

I don't use this any more, I use [Hugo](https://gohugo.io/) and [Relearn](https://mcshelby.github.io/hugo-theme-relearn/index.html).

Open issues are:

1.  If you do a ZIP, and upload it, but do not delete it from the PC,
    the next run will append, not overwrite. Your "diff" zip will just
    keep growing. You need to manually delete the zip file after each
    run is successful.
2.  Since find is working off of the modification time, if you move a
    file into the structure that has not been modified (i.e. a tool or
    utility program) it will not be picked up by a diff. You have to add
    that to the zip manually.

[upload.cmd](/public/source/upload.cmd.txt) v1.0 2000-12-14
:  Upload.bat runs on my Windows workstation, and creates a ZIP file I
  can upload, but it does **not** grab the stupid "\_VTI\_CNF"
  directories\!

[upload.sh](/public/source/upload.sh.txt) v1.1 2001-01-24
: Unzip upload.zip and set permissions on www directory.

-----

## Windows Scripting Resources

  - *[Master and Command Line](http://www.redmondmag.com/columns/article.asp?editorialsid=802)*:
    "Using the Windows GUI is fine--if you want to go slow. Learn to use
    the command line and move into the administration fast lane."
  - *[Scripting for
    MCSEs](http://www.mcpmag.com/columns/article.asp?EditorialsID=500)*
    (details about the Scriptomatic)
  - *[The TechNet Script
    Center](http://www.microsoft.com/technet/treeview/default.asp?url=/technet/scriptcenter/default.asp)*
  - *[MS Windows Scripting
    FAQ](http://www.microsoft.com/technet/scriptcenter/scrptfaq.asp)*

-----

This article is translated to
*[Serbo-Croatian](http://science.webhostinggeeks.com/windows-shell)* by
*[WHGeeks](http://webhostinggeeks.com)*. Thanks\!

{{< snippet "old" >}}
