Setting environment variables in Windows usually feels straightforward, but introducing special characters like the pipe symbol (|) can cause unexpected errors depending on which command-line interface (CLI) you use. If you define a variable globally using the Windows Environment Variables GUI, PowerShell and Git Bash handle it effortlessly, while Windows Command Prompt (CMD) throws frustrating syntax errors.

The Problem: Pipe Characters Breaking CMD

Suppose you set a system or user environment variable named FOO with the value bar|biz in the Windows System Properties GUI.

When you attempt to retrieve this variable across different shells, you see contradictory behavior:

  • PowerShell: Running $env:FOO correctly returns bar|biz.
  • Git Bash: Running echo $FOO correctly returns bar|biz.
  • CMD: Running echo %FOO% fails with the error: 'biz' is not recognized as an internal or external command, operable program or batch file.

If you try to fix CMD by storing an escaped value like bar^|biz in the Windows GUI, CMD will print bar|biz, but PowerShell and Git Bash will now literally include the caret character (bar^|biz). This leaves developers wondering how to properly define a global environment variable for all environments.

The Root Cause: Storage vs. Command Parsing

The key takeaway is that the Windows environment variable system stores values literally. When you put bar|biz into the GUI, Windows stores the exact string bar|biz in the registry without any hidden escaping.

The underlying problem isn't how the variable is stored, but how CMD parses lines during execution:

  1. Early Variable Expansion: In CMD, percent-expanded variables (%FOO%) are evaluated at parse time before statement execution.
  2. Operator Evaluation: CMD expands echo %FOO% into echo bar|biz.
  3. Pipe Interpretation: CMD sees the unquoted | symbol and treats it as a command pipe, attempting to redirect the output of echo bar into an executable named biz.

PowerShell and Git Bash treat variable access differently, retrieving the literal string value without treating contained symbols as syntax operators during standard output.

The Solution: Keep Variable Values Clean and Fix CMD Access

The correct approach is to keep the stored value in the Windows GUI completely literal and unescaped: bar|biz. This ensures PowerShell, Git Bash, Node.js, Python, and native Windows APIs receive the exact intended value.

To handle the variable safely in CMD without triggering syntax errors, use one of the following methods:

Method 1: Use Delayed Expansion in CMD (Recommended for Scripts)

Delayed expansion evaluates variables at execution time rather than initial line parse time. This prevents characters like |, &, and > inside variable values from being interpreted as command operators.