The unexplained failures on Windows
If you've used Claude Code on Windows for any length of time, you've probably seen this pattern. Basic actions — opening a file, searching text, running a quick script — all work. Then something trips: a path gets mangled, a Git command blows up on quoting, line endings turn a straightforward command into a mystery. From the Claude Code side, it starts oscillating ("try this Bash command — error — try a different one — error"), and the transcript bloats.
A surprising fraction of these symptoms trace back to a mismatch between the Windows-side Bash environment (Git Bash, MSYS2, WSL-style wrappers) and the shell behavior that Claude Code's Bash tool assumes. That's where the CLAUDE_CODE_USE_POWERSHELL_TOOL=1 environment variable comes in. When set, Claude Code sends shell commands through PowerShell rather than its POSIX-flavored Bash path.
This article is a pragmatic note from living with the switch on Windows — when to turn it on, what actually changes, and what stays unfixed.
What the variable really does
Claude Code uses a small set of internal "tools" to execute work. The one that runs shell commands defaults to a Bash-oriented implementation — POSIX shell behavior expected. On Linux and macOS this works naturally.
On Windows, many users run Claude Code under a POSIX emulation layer like Git Bash. That layer frequently introduces seams: slashes get mixed into paths, quoting gets interpreted twice, and the final executor oscillates between cmd and PowerShell depending on the environment.
Setting CLAUDE_CODE_USE_POWERSHELL_TOOL=1 rewires the shell execution path to dispatch to PowerShell directly. PowerShell is pre-installed on modern Windows, and it speaks Windows paths, user profiles, and environment variables natively. That alignment removes many Windows-specific quirks.
When the switch pays off
The switch earns its keep in a handful of recurring scenarios.
Paths with spaces or non-ASCII characters
Windows paths like C:\Users\<Name>\OneDrive\Documents routinely contain spaces, and some have non-ASCII characters. Passing these through Git Bash always comes with layered-quoting problems. With PowerShell directly in the loop, Windows-style paths go through cleanly, and most of the quoting anxiety disappears.
Corporate networks — proxies and certificates
On company-managed machines, HTTP proxy and certificate configuration tends to live in the Windows Credential Manager and certificate store. Bash-based tooling often can't find them, producing errors like SSL certificate problem. PowerShell consults the Windows certificate store directly, so many of these failures quietly go away without extra configuration.
Cmdlets that only exist in PowerShell
Cmdlets such as Get-Process, Get-Service, and Get-AppxPackage are PowerShell-only. Bash can't invoke them. With the PowerShell tool active, Claude Code can reach native Windows diagnostics directly.
What changes that you should prepare for
Flipping the switch also means some Bash conventions stop translating cleanly.
Pipes and redirection
command1 | command2 still works, but PowerShell pipes push objects, not text. You'll see Claude Code substituting grep with Select-String, awk with ForEach-Object, and so on. For interactive use it handles most translations well. Pasting large legacy shell scripts and expecting them to run as-is, however, is now risky.
Execution Policy
PowerShell has an Execution Policy that restricts script execution. On corporate hardware this is often set to Restricted, which will reject any .ps1 files Claude Code tries to run. The minimum adjustment is a one-time:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUserThat scopes the change to your user only — a safer default than a machine-wide change.
Quoting differences
POSIX shells and PowerShell have subtly different quoting rules, especially around $ expansion inside double quotes and the meaning of single quotes. If you've been running every command Claude Code produces without reading it, expect a few surprises. Run shorter commands first and confirm output before chaining into long operations.
How to turn it on (and off)
The switch is an environment variable; it takes effect the next time Claude Code starts.
# PowerShell — current session only
$env:CLAUDE_CODE_USE_POWERSHELL_TOOL = "1"
claude
# Persist at the user level
[Environment]::SetEnvironmentVariable("CLAUDE_CODE_USE_POWERSHELL_TOOL", "1", "User")If you're launching claude from Git Bash, add the export to ~/.bashrc so it's inherited:
# ~/.bashrc
export CLAUDE_CODE_USE_POWERSHELL_TOOL=1To disable:
# Current session
Remove-Item Env:CLAUDE_CODE_USE_POWERSHELL_TOOL
# User-level
[Environment]::SetEnvironmentVariable("CLAUDE_CODE_USE_POWERSHELL_TOOL", $null, "User")Deciding whether to switch
My rule of thumb: if any of these describe your setup, it's worth a trial.
You mostly work on Windows, and you'd rather not juggle Git Bash and PowerShell at the same time. Your machine is managed by a corporate IT policy with strict proxy and certificate settings. Your project leans on Windows-native tooling (.NET, PowerShell scripts, Windows APIs).
Conversely, if your Claude Code sessions already live inside WSL, you're effectively on Linux already — the switch brings very little benefit.
Windows-specific friction that remains
The variable doesn't remove every Windows idiosyncrasy. A few to keep in mind.
Path length limits
Windows has a default 260-character path limit. Deeply nested node_modules trees will still hit it. This is unrelated to Claude Code; you fix it via LongPathsEnabled in the registry or group policy.
Line endings
core.autocrlf in Git will still translate line endings on checkout. Claude Code isn't the source of the surprise, but you'll feel it through commands it runs. New repositories benefit from a minimal .gitattributes like * text=auto eol=lf.
Commands that need elevation
Anything that requires admin rights — netsh, sfc, Stop-Service, and friends — needs Claude Code itself to be launched elevated. On machines where every elevation prompts UAC, those are tasks you'll probably want to run by hand rather than via Claude Code.
Verifying the switch is actually active
Once you've set the variable, it's easy to confirm the tool is really routing through PowerShell. Ask Claude Code to run a short PowerShell-native command:
$PSVersionTable
Get-Location
[System.Environment]::OSVersionIf these return sensible output, the switch is live. Under the Bash path these would usually surface as "command not found"-style errors, so the contrast is obvious.
If you've had that vague sense that Claude Code is "fighting" your Windows environment, this is one of the cheapest experiments you can run — set the variable, try a short session, revert if you don't like it. For machines I use exclusively on Windows, I leave it on permanently. Between Windows and macOS workstations my Claude Code environments need to differ anyway; making that explicit with a single environment variable turns out to be a surprisingly durable quality-of-life improvement.