Colored text output in PowerShell console using ANSI / VT100 codes Colored text output in PowerShell console using ANSI / VT100 codes powershell powershell

Colored text output in PowerShell console using ANSI / VT100 codes


While console windows in Windows 10 do support VT (Virtual Terminal) / ANSI escape sequences in principle, support is turned OFF by default.

You have three options:

  • (a) Activate support globally by default, persistently, via the registry, as detailed in this SU answer.

    • In short: In registry key [HKEY_CURRENT_USER\Console], create or set the VirtualTerminalLevel DWORD value to 1
      • From PowerShell, you can do this programmatically as follows:
        Set-ItemProperty HKCU:\Console VirtualTerminalLevel -Type DWORD 1
      • From cmd.exe (also works from PowerShell):
        reg add HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1
    • Open a new console window for changes to take effect.
    • See caveats below.
  • (b) Activate support from inside your program, for that program (process) only, with a call to the SetConsoleMode() Windows API function.

    • See details below.
  • (c) Ad-hoc workaround, from PowerShell: pipe output from external programs to Out-Host; e.g., .\test.exe | Out-Host

    • See details below.

Re (a):

The registry-based approach invariably activates VT support globally, i.e., for all console windows, irrespective of what shell / program runs in them:

  • Individual executables / shells can still deactivate support for themselves, if desired, using method (b).

  • Conversely, however, this means that the output of any program that doesn't explicitly control VT support will be subject to interpretation of VT sequences; while this is generally desirable, hypothetically this could lead to misinterpretation of output from programs that accidentally produce output with VT-like sequences.

Note:

  • While there is a mechanism that allows console-window settings to be scoped by startup executable / window title, via subkeys of [HKEY_CURRENT_USR\Console], the VirtualTerminalLevel value seems not to be supported there.

  • Even if it were, however, it wouldn't be a robust solution, because opening a console window via a shortcut file (*.lnk) (e.g. from the Start Menu or Task Bar) wouldn't respect these settings, because *.lnk files have settings build into them; while you can modify these built-in settings via the Properties GUI dialog, as of this writing the VirtualTerminalLevel setting is not surfaced in that GUI.


Re (b):

Calling the SetConsoleMode() Windows API function from inside the program (process), as described here, is cumbersome even in C# (due to requiring a P/Invoke declaration), and may not be an option:

  • for programs written in languages from which calling the Windows API is not supported.

  • if you have a preexisting executable that you cannot modify.

If you don't want to enable support globally in that case (option (a)), option (c) (from PowerShell) may work for you.


Re (c):

PowerShell automatically activates VT (virtual terminal) support for itself when it starts (in recent releases of Windows 10 this applies to both Windows PowerShell and PowerShell Core) - but that does not extend to external programs called from PowerShell.

However, if you relay an external program's output via PowerShell, VT sequences are recognized; using Out-Host is the simplest way to do that (Write-Host would work too):

.\t.exe | Out-Host

Note: Use Out-Host only if you mean to print to the console; if, by contrast, you want to capture the external program's output, use just $capturedOutput = .\test.exe

Character-encoding caveat: Windows PowerShell by default expects output from external programs to use the OEM code page, as defined by the legacy system locale (e.g., 437 on US-English systems) and as reflected in [console]::OutputEncoding..NET console programs respect that setting automatically, but for non-.NET programs (e.g., Python scripts) that use a different encoding (and produce not just pure ASCII output (in the 7-bit range)), you must (at least temporarily) specify that encoding by assigning to [console]::OutputEncoding; e.g., for UTF-8:
[console]::OutputEncoding = [Text.Encoding]::Utf8.
Note that this is not only necessary for the VT-sequences workaround, but generally necessary for PowerShell to render non-ASCII characters correctly.

PowerShell Core, unfortunately, as of v6.1.0-preview.4, still defaults to the OEM code page too, but that should be considered a bug, given that PowerShell Core otherwise defaults to UTF-8 without BOM.


Thanks to user mklement0 for making me aware that VT support is not enabled automatically. This made me look in the right direction and I found this helpful post.

So to answer my question: Add or set the registry key

HKCU:\Console  -  [DWORD] VirtualTerminalLevel = 1

Restart the console and it works.


For Haskell specifically, you need to call the hSupportsANSIWithoutEmulation function to enable ANSI escape sequences in your program on Windows 10.