Windows NT Batch
The batch scripting dialect of Windows NT's cmd.exe — a 32-bit command interpreter from 1993 whose command extensions turned DOS batch into a genuine scripting language that still ships with every copy of Windows.
Created by Microsoft (the original Windows NT cmd.exe was written by Therese Stowell)
Windows NT Batch is the scripting dialect understood by cmd.exe, the 32-bit command interpreter Microsoft shipped with Windows NT 3.1 in July 1993 and has included in every version of Windows since. It is the direct descendant of DOS Batch — any 1980s .BAT file of ECHO, IF, GOTO, and FOR still runs — but the NT lineage grew far beyond COMMAND.COM: integer arithmetic, subroutines with CALL :label, a FOR /F loop that parses file contents and command output, string slicing, and delayed variable expansion. The result is a language that was never designed so much as accreted, is famous for its parsing quirks, and yet remains arguably one of the most widely executed languages in the world, because every Windows machine runs it and an enormous body of tooling — build launchers, installer glue, logon scripts, npm shims — is written in it.
The original NT cmd.exe was written by Therese Stowell, one of the first engineers on the Windows NT team, and its design drew on the CMD.EXE that Microsoft and IBM had built for OS/2 in 1987 — which is where the .cmd file extension comes from.
History & Origins
When Microsoft set out to build Windows NT, it needed a command-line environment worthy of a real 32-bit operating system. MS-DOS’s COMMAND.COM was a 16-bit real-mode program with famously terse error reporting and pipelines faked through temporary files. The precedent for something better already existed in-house: OS/2’s CMD.EXE, from the era when Microsoft and IBM were building OS/2 together, had introduced a more capable interpreter and the .cmd extension in December 1987.
For NT, Therese Stowell wrote a new command interpreter as a native Win32 console application. Shipping with Windows NT 3.1 on July 27, 1993, cmd.exe ran batch files with long filename support, ran both sides of a pipeline concurrently as real processes, kept a command history, and reported errors in sentences. Crucially, it remained compatible with existing DOS batch files — compatibility that has constrained and preserved the language ever since.
The dialect’s real growth came in two bursts. Windows NT 4.0 (1996) introduced Command Extensions, enabled by default: SET /A arithmetic, comparison operators for IF (EQU, NEQ, LSS, GTR, and friends), CALL :label subroutines, and the powerful extended FOR variants. Windows 2000 then added delayed expansion, SET /P prompting, dynamic variables like %CD% and %RANDOM%, and substring/substitution syntax. After Windows 2000 the language was essentially complete; Microsoft’s attention turned to a from-scratch successor, PowerShell, released in 2006.
Design Philosophy
NT batch has no design document; its philosophy must be read from its behavior:
- Never break an old batch file. Compatibility with COMMAND.COM scripts was non-negotiable, which is why new behavior arrived as Command Extensions that can be disabled (
SETLOCAL DISABLEEXTENSIONS, or per-invocation withcmd /E:OFF) and why delayed expansion — which changes how!characters parse — is off by default to this day. - The interpreter is the language. There is no specification and no independent implementation from Microsoft; the language is whatever cmd.exe does, including its parse-time variable expansion, its caret (
^) escape character, and the interaction rules among quotes, percent signs, and parentheses that practitioners learn by experiment. - Strings all the way down. Variables are environment variables — untyped strings in the process environment.
SET /Agrafts integer arithmetic onto this model, andIFgrows numeric comparisons, but there are no data structures beyond what can be faked with variable-name conventions. - Small language, big commands. Like the Unix shell, batch delegates real work to external programs; the language itself is mostly control flow, variable plumbing, and redirection.
Key Features
A script showing off the specifically-NT parts of the dialect:
| |
Everything in that script beyond @echo off and echo arrived with NT:
SETLOCAL/ENDLOCALscope environment changes to the script (a feature inherited from OS/2’s interpreter).SET /Aevaluates integer expressions with C-like operators, including compound assignment (+=) and bitwise operations.FOR /Ftokenizes lines from files, strings, or the output of another command — the closest thing batch has to reading structured data.FOR /Lcounts,FOR /Rrecurses directories,FOR /Diterates directories.- Delayed expansion (
!var!) fixes the classic batch trap where%var%inside a parenthesized block is expanded once, at parse time. CALL :labelgives batch real subroutines with arguments andEXIT /Breturn codes, and the%~modifiers (%~1to strip quotes,%~dp0for the script’s own directory,%~nx1for name and extension) are among the most-used idioms in the language.- Conditional execution with
&&and||, command grouping with&and parentheses, and full redirection including2>&1. PUSHDwith a UNC path (\\server\share) temporarily maps a drive letter automatically — a small feature that makes scripts portable across networked Windows environments.
Scripts use the .bat or .cmd extension interchangeably in practice; both are run by cmd.exe on NT systems, with only minor behavioral differences (some internal commands report ERRORLEVEL slightly differently between the two).
Evolution
The language’s history is unusually front-loaded:
- 1993 — NT 3.1: a faithful 32-bit reimplementation of the DOS batch world on the NT kernel.
- 1996 — NT 4.0: Command Extensions transform the language — arithmetic, subroutines, extended
FOR, richerIF. - 2000 — Windows 2000: delayed expansion, dynamic variables, string manipulation. The dialect reaches essentially its final form.
- 2001 — Windows XP: the NT line absorbs the consumer market; NT batch becomes the Windows batch language.
- 2006 onward: PowerShell is the designated successor, and cmd.exe enters maintenance. The language stops evolving, but its environment improves around it — the Windows 10 console gained ANSI/VT escape-sequence processing starting with version 1511 (2015), and Windows Terminal (2019) became Windows 11’s default terminal host in the 22H2 update.
That a language could stop changing around 2000 and remain in daily production use into the 2020s is itself the most telling fact about it.
Current Relevance
NT batch today occupies the same position on Windows that /bin/sh scripts occupy on Unix: rarely anyone’s favorite language, but everywhere. It is the lowest-common-denominator automation layer guaranteed present on every Windows machine with no runtime to install and no execution policy to configure — a genuine advantage over PowerShell scripts, which are blocked by default policy in many environments. Build systems (Gradle’s gradlew.bat, Maven’s mvn.cmd), Visual Studio’s vcvarsall.bat, npm’s generated .cmd shims, Windows Setup’s SetupComplete.cmd hook, and legions of enterprise logon and deployment scripts keep it in constant use.
For new substantial scripting work, Microsoft steers developers to PowerShell, and the batch language receives no new features. But cmd.exe remains a fully supported component of Windows 11, and Microsoft’s official documentation for the command set is actively maintained. Batch files even run in Windows containers: Microsoft’s Nano Server and Server Core base images include cmd.exe, so docker run mcr.microsoft.com/windows/nanoserver:ltsc2022 cmd /c "echo Hello, World!" works — noting that Windows container images require a Windows host.
Why It Matters
Windows NT Batch matters first through sheer reach: for three decades it has been the automation language that is always there on the world’s dominant desktop operating system, and an untold volume of infrastructure — from corporate logon scripts to the launcher that starts your Java build — quietly depends on it.
It is also an instructive case study in evolutionary language design. Every one of its notorious quirks — parse-time %var% expansion, the delayed-expansion opt-in, caret escaping, the baroque tokenizing rules of FOR /F — exists because compatibility with a 1981 command processor was preserved at each step while real features were bolted on. The contrast with PowerShell, Microsoft’s clean-slate answer, frames the central trade-off of language evolution: NT batch shows both the costs of never breaking anything and the extraordinary longevity that policy buys. COMMAND.COM’s descendants have now been running the same scripts, on hardware and operating systems their authors never imagined, for over forty years — and the NT dialect is the form in which that lineage survives today.
Timeline
Notable Uses & Legacy
Build tool launchers
The Gradle wrapper's gradlew.bat and Apache Maven's mvn.cmd are NT batch scripts checked into or shipped with millions of projects, bootstrapping Java builds on Windows. Nearly every cross-platform developer tool ships a .bat or .cmd launcher alongside its Unix shell script.
Visual Studio developer environments
Visual Studio's vcvarsall.bat and VsDevCmd.bat configure the compiler, linker, and SDK paths for command-line MSVC builds. These load-bearing batch files ship with every Visual Studio installation and are invoked by countless CI pipelines.
npm command shims
On Windows, npm generates a .cmd shim for every globally installed package's executable, so commands like tsc or eslint work from the Command Prompt. Vast numbers of NT batch files are generated this way every day without their users ever reading one.
Windows deployment scripting
Windows Setup runs SetupComplete.cmd after OS installation, a Microsoft-documented hook that enterprises use to finish image customization. Batch remains a workhorse for deployment glue in SCCM/Intune packages and unattended installs.
Active Directory logon scripts
Domain logon scripts mapping drives, connecting printers, and setting environments have been written as .bat/.cmd files since Windows NT domains, and Group Policy still supports assigning them — many organizations run decades-old scripts unchanged.
Language Influence
Influenced By
Influenced
Running Today
Run examples using the official Docker image:
docker pull mcr.microsoft.com/windows/nanoserver:ltsc2022Example usage:
docker run --rm mcr.microsoft.com/windows/nanoserver:ltsc2022 cmd /c "echo Hello, World!"