If you run Claude Code on Windows, this environment variable has probably crossed your radar. Set CLAUDE_CODE_USE_POWERSHELL_TOOL=1 and Claude Code will prefer PowerShell when it executes shell commands internally. Whether that is actually the right move, though, depends a lot on what you are building and where you are running it.
I had occasion recently to use both WSL2 and bare PowerShell on the same Windows 11 box, so I tested this variable across a few projects. The short answer is: it is not a flip-it-on-for-everyone setting. There are clear cases where it helps and clear cases where it just adds friction. This article lays out my decision rubric.
What actually changes
The variable affects which shell Claude Code reaches for when it runs commands. Without any configuration, on a bare Windows host, Claude Code may go through cmd.exe, which can produce odd UTF-8 issues and surprising behavior when running PowerShell scripts (.ps1).
With CLAUDE_CODE_USE_POWERSHELL_TOOL=1 set, Claude Code reaches for PowerShell first (powershell.exe or pwsh.exe). The most visible difference is that Windows-native commands and PowerShell cmdlets like Get-ChildItem execute correctly without translation.
That much is in the docs. What I want to share is what actually happens during day-to-day work that the docs do not cover.
When to turn it on
Across the projects where I have run both, I now flip it on without hesitation in three situations.
First, projects that lean on Windows-only tooling. WPF, WinForms, UWP — anything where you call dotnet or MSBuild — runs more predictably under PowerShell. PATH and environment variable inheritance behave more reliably than via cmd.exe.
Second, when I want Claude Code to author or edit .ps1 scripts. In cmd.exe mode, Claude has to do a translation step to actually execute PowerShell snippets, and you start hitting cases where it hesitates or guesses about how to invoke them.
Third, teams that have already standardized on PowerShell 7 (pwsh) as their primary shell. If you have profile settings like Set-PSReadlineOption you want honored, you want Claude Code launching from inside that environment.
When to leave it off
There are equally clear cases where flipping it on creates more confusion than it solves.
If you do most of your development inside WSL2, the variable does nothing useful. Claude Code running inside WSL is in a Linux process tree — it will use bash or zsh regardless. Setting it inside .bashrc is just confusing future you.
If your toolchain is purely cross-platform — npm, pip, pytest, and friends — the shell choice does not affect behavior. In this case, switching to PowerShell can actually slow things down a touch, since PowerShell has heavier startup than cmd.exe. You feel it in rapid file searches and npm run dev boots.
If you mix WSL and Windows host work in the same session, only setting USE_POWERSHELL_TOOL makes the picture muddier. The actual behavior depends on which parent process started Claude Code, and trying to debug that with one variable in flight is harder than just being explicit about which shell you launched from.
What I observed across three projects
I compared both modes side by side on real work.
Case 1: Next.js front-end (cross-platform). With the variable on, every command spawned PowerShell, so file scans and dev server launches felt fractionally laggier. Off was the better default here.
Case 2: .NET 9 WPF project (Windows-native). With the variable on, dotnet build output came through correctly in UTF-8 and build errors were easier to read. This was a clear win.
Case 3: Python project inside WSL2. The variable made no observable difference. WSL runs bash internally; the Windows-side variable does not propagate. Even when starting WSL from PowerShell explicitly, behavior was unchanged.
How to set it and verify
The conventional way is to set it as a user environment variable.
# Persist (PowerShell)
[Environment]::SetEnvironmentVariable("CLAUDE_CODE_USE_POWERSHELL_TOOL", "1", "User")
# Verify
[Environment]::GetEnvironmentVariable("CLAUDE_CODE_USE_POWERSHELL_TOOL", "User")Close and reopen PowerShell after setting. Then launch Claude Code and try a small command (Get-ChildItem is a good probe) to confirm it executes as a PowerShell cmdlet.
To remove it later:
[Environment]::SetEnvironmentVariable("CLAUDE_CODE_USE_POWERSHELL_TOOL", $null, "User")Setting it to 0 works as a temporary disable.
Pitfalls when flipping the switch
After turning it on, I had a project where npm run scripts started failing. The cause turned out to be && chained commands in package.json.
{
"scripts": {
"build": "tsc && next build"
}
}Old Windows PowerShell (5.1 and earlier) does not support &&. PowerShell 7 added it. If your team has anyone still on Windows PowerShell, replace these with npm-run-all or similar.
The other gotcha is path quoting. PowerShell handles spaces in paths differently from cmd.exe. Claude Code usually quotes correctly, but it can slip. When in doubt, be explicit: & "path with space\app.exe".
A simple decision checklist
A short rubric I now run through:
You write .ps1 scripts. You build on Windows-native SDKs (dotnet, MSBuild). You launch Claude Code directly from Windows Terminal. You want PowerShell profile settings honored.
If two or more of these are true, give it a try.
You live in WSL2. You write only Node/Python cross-platform scripts. You notice startup latency.
If you fall into this group, leave it off.
Personally, my main work happens in WSL2, but when I write small Windows-native utilities, I set $env:CLAUDE_CODE_USE_POWERSHELL_TOOL=1 per session rather than persisting it. Per-session toggling has caused me less confusion than a global flag.
When in doubt, flip it on for a day, see how it feels, and revert if anything is off. It is a low-stakes setting to experiment with.