Est. 1993 Beginner

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)

Paradigm Procedural, Scripting
Typing Dynamic, Weak (environment variables are strings; SET /A evaluates integer arithmetic)
First Appeared 1993
Latest Version No independent version; cmd.exe tracks the Windows build and is current in Windows 11

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:

  1. 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 with cmd /E:OFF) and why delayed expansion — which changes how ! characters parse — is off by default to this day.
  2. 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.
  3. Strings all the way down. Variables are environment variables — untyped strings in the process environment. SET /A grafts integer arithmetic onto this model, and IF grows numeric comparisons, but there are no data structures beyond what can be faked with variable-name conventions.
  4. 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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@echo off
setlocal EnableExtensions EnableDelayedExpansion

set /a total=0
rem FOR /F parses each line of a CSV into tokens
for /f "tokens=1,2 delims=," %%A in (sales.csv) do (
    set /a total+=%%B
    rem !total! is delayed expansion: read at run time, not parse time
    echo Region %%A running total: !total!
)

call :report %total%
endlocal
exit /b 0

:report
echo Grand total: %~1
exit /b 0

Everything in that script beyond @echo off and echo arrived with NT:

  • SETLOCAL/ENDLOCAL scope environment changes to the script (a feature inherited from OS/2’s interpreter).
  • SET /A evaluates integer expressions with C-like operators, including compound assignment (+=) and bitwise operations.
  • FOR /F tokenizes lines from files, strings, or the output of another command — the closest thing batch has to reading structured data. FOR /L counts, FOR /R recurses directories, FOR /D iterates directories.
  • Delayed expansion (!var!) fixes the classic batch trap where %var% inside a parenthesized block is expanded once, at parse time.
  • CALL :label gives batch real subroutines with arguments and EXIT /B return codes, and the %~ modifiers (%~1 to strip quotes, %~dp0 for the script’s own directory, %~nx1 for name and extension) are among the most-used idioms in the language.
  • Conditional execution with && and ||, command grouping with & and parentheses, and full redirection including 2>&1.
  • PUSHD with 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, richer IF.
  • 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

1987
OS/2 1.0, developed jointly by Microsoft and IBM, ships in December 1987 with a command interpreter named CMD.EXE and the .cmd file extension — the direct ancestor of the Windows NT command processor.
1993
Windows NT 3.1 is released on July 27, 1993 with a new 32-bit cmd.exe, written by Therese Stowell of the original NT team. Batch files now run in a Win32 environment with long filename support, genuinely concurrent pipelines, and better error messages than COMMAND.COM's 'Bad command or file name'.
1996
Windows NT 4.0 (released August 1996) ships cmd.exe with Command Extensions enabled by default: SET /A integer arithmetic, the extended FOR forms (/D, /R, /L, /F), IF comparison operators such as EQU and GEQ, and CALL :label subroutines — the release that turns NT batch into a real scripting language.
2000
Windows 2000 (February 17, 2000) adds delayed variable expansion (the !var! syntax enabled by SETLOCAL ENABLEDELAYEDEXPANSION), SET /P for prompting, dynamic variables such as %CD%, %DATE%, %TIME%, and %RANDOM%, substring and string-substitution syntax, and the %~ parameter modifiers.
2001
Windows XP (October 25, 2001) unifies the consumer and business Windows lines on the NT kernel. cmd.exe and the NT batch dialect become the command-line environment for effectively all Windows users, ending the COMMAND.COM era of the Windows 9x line.
2006
Microsoft releases Windows PowerShell 1.0 on November 14, 2006 as the strategic successor for Windows automation. The NT batch language is effectively frozen from this point — fully supported and shipped with every Windows release, but receiving essentially no new language features.
2015
The Windows 10 November Update (version 1511) begins a long-overdue overhaul of the Windows Console, adding virtual-terminal (ANSI escape sequence) processing — so batch scripts can finally produce colored and styled output the way Unix shells long have.
2019
Microsoft announces the open-source Windows Terminal at Build in May 2019 (version 1.0 follows in May 2020). cmd.exe becomes one profile among many, running alongside PowerShell and WSL shells in a modern tabbed terminal.
2021
Windows 11 (October 5, 2021) still ships cmd.exe and runs .bat and .cmd scripts unchanged; in the 22H2 update (October 2022), Windows Terminal becomes the default terminal application, hosting the Command Prompt by default.

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

4NT / TCC (Take Command)

Running Today

Run examples using the official Docker image:

docker pull mcr.microsoft.com/windows/nanoserver:ltsc2022

Example usage:

docker run --rm mcr.microsoft.com/windows/nanoserver:ltsc2022 cmd /c "echo Hello, World!"
Last updated: