●MCP — Support for the 2026-07-28 spec is rolling out across Claude. The protocol moves from bidirectional and stateful to request/response, so MCP servers can now live on serverless and edge infrastructure●EXTENSIONS — Three official extensions have landed: MCP Apps for server-rendered UI, Tasks for async and long-running work, and Enterprise Managed Auth for IdP-based org-wide provisioning●ADOPTION — MCP passed 400 million monthly SDK downloads, roughly 4x growth this year, settling into its role as the standard way to connect agents to applications●QUOTA — Today, August 19, is the last day of the 50 percent weekly usage boost for Claude Code subscribers. If you have long agent runs queued, this is the window●PRICING — Claude Sonnet 5's introductory rate of $2 per million input tokens and $10 output ends August 31; standard pricing of $3 and $15 takes over on September 1, twelve days out●FIX — A bug where MCP v2 connections endlessly reopened subscriptions against servers with fixed timeouts is resolved, and a forward_user_identity setting was added for user attribution●MCP — Support for the 2026-07-28 spec is rolling out across Claude. The protocol moves from bidirectional and stateful to request/response, so MCP servers can now live on serverless and edge infrastructure●EXTENSIONS — Three official extensions have landed: MCP Apps for server-rendered UI, Tasks for async and long-running work, and Enterprise Managed Auth for IdP-based org-wide provisioning●ADOPTION — MCP passed 400 million monthly SDK downloads, roughly 4x growth this year, settling into its role as the standard way to connect agents to applications●QUOTA — Today, August 19, is the last day of the 50 percent weekly usage boost for Claude Code subscribers. If you have long agent runs queued, this is the window●PRICING — Claude Sonnet 5's introductory rate of $2 per million input tokens and $10 output ends August 31; standard pricing of $3 and $15 takes over on September 1, twelve days out●FIX — A bug where MCP v2 connections endlessly reopened subscriptions against servers with fixed timeouts is resolved, and a forward_user_identity setting was added for user attribution
Claude Code's PowerShell Tool — Native Windows, No WSL
The one setting that actually enables the Claude Code PowerShell tool, why auto mode's new default leaves Windows users still approving prompts, and what August's three permission changes left standing. With WSL2 trade-offs and unattended-run safety gates.
When the WSL2 Round-Trip Started Feeling Slow — v2.1.84
Claude Code v2.1.84, released in April 2026, introduced the PowerShell tool as an opt-in preview. This is a significant milestone for Windows developers: you can now use PowerShell as a native tool within Claude Code sessions, without needing to route everything through WSL (Windows Subsystem for Linux).
Until now, Windows users typically relied on WSL2 and Bash to interact with Claude Code. The PowerShell tool opens up native Windows capabilities — file system operations, registry access, Azure/Active Directory integration, and more — directly from your Claude Code workflow.
What Problem Does the PowerShell Tool Solve?
Working with Claude Code on Windows before this release came with a few pain points:
Limitations of the WSL2 approach:
Mixed path formats between Windows and Linux (\\wsl$\ paths) caused frequent resolution errors
Accessing the Windows registry or COM objects required workarounds
Integrations with Active Directory or Azure AD needed extra bridging layers
The PowerShell tool eliminates these friction points, bringing native Windows development and IT operations directly into Claude Code.
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦Diagnose why enabling the tool appears to do nothing — the env var format, the Bash-first default, and three distinct shell-routing paths
✦Understand why PowerShell still prompts after auto mode became the default, and design deliberately around where you want to be stopped
✦Tell apart which of August's Windows permission fixes held and which were reverted, so you know what silently passes today
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
Before enabling the PowerShell tool, make sure you have the following:
Claude Code v2.1.84 or later
Windows 10 / 11 or Windows Server 2019 / 2022
PowerShell 5.1 or PowerShell 7.x (recommended)
Node.js 18 or later (Claude Code runtime)
To check your PowerShell version:
# Check PowerShell version$PSVersionTable.PSVersion# Example outputMajor Minor Build Revision----- ----- ----- --------7 4 7 0
PowerShell 7.x (PowerShell Core) is strongly recommended for its improved security features and cross-platform design.
How to Enable the PowerShell Tool
The PowerShell tool is an opt-in preview, and enabling it comes down to a single environment variable: CLAUDE_CODE_USE_POWERSHELL_TOOL. There is no toggle to hunt for in the settings UI. I lost a good chunk of an afternoon scrolling through /config looking for one.
Option 1: Add it to the env block in settings.json (recommended)
Open ~/.claude/settings.json (on Windows: %USERPROFILE%\.claude\settings.json) and add it under env:
The value is the string "1", not the boolean true. Restart Claude Code to pick it up. On Windows the tool is part of a gradual rollout, so if you want to opt out, set the same variable to "0".
Option 2: Set the variable in your shell before launching
If you just want to try it, exporting the variable before launch keeps your settings file clean — which also makes it easier to compare behavior with and without the tool.
# Enable for the current session only$env:CLAUDE_CODE_USE_POWERSHELL_TOOL = "1"claude# Or persist it as a user environment variable[Environment]::SetEnvironmentVariable("CLAUDE_CODE_USE_POWERSHELL_TOOL", "1", "User")
Claude Code picks the executable on its own: pwsh.exe (PowerShell 7+) first, falling back to powershell.exe (5.1). There is no setting for pinning the version.
Enabling It Does Not Mean Claude Will Use It
This is the part that trips people up. The Bash tool stays registered alongside PowerShell, and Claude will not reach for PowerShell on its own. You either ask for it explicitly, or you configure shell routing.
Setting
Scope
Needs the opt-in flag?
"defaultShell": "powershell" (settings.json)
! commands in the REPL
Yes
"shell": "powershell" (per hook entry)
That hook only
No
shell: powershell (skill frontmatter)
! blocks in that skill
Yes
Hooks are the exception because they spawn PowerShell directly, independent of the tool flag. That makes them a good on-ramp: you can route just your formatting hook through PowerShell without flipping the whole toolchain. That is exactly where I started.
Verifying the Setup
Once Claude Code restarts, you can confirm the tool is active by asking:
Do your available tools include PowerShell?
If everything is configured correctly, Claude will confirm it can execute PowerShell commands.
Basic Usage
With the PowerShell tool enabled, Claude Code can execute PowerShell alongside Bash. On Windows, it will automatically select the appropriate tool based on context.
File and Directory Operations
# List all TypeScript files recursivelyGet-ChildItem -Path . -Recurse -Filter "*.ts" | Select-Object FullName# Read file contentsGet-Content .\src\components\Button.tsx# Create a new directoryNew-Item -ItemType Directory -Path ".\src\features\auth"# Create a backup of a config fileCopy-Item .\config.json .\config.json.bak
Gathering System Information
# Check installed Node.js versionnode --version# Output: v22.14.0# Available memoryGet-CimInstance Win32_OperatingSystem | Select-Object FreePhysicalMemory, TotalVisibleMemorySize# Read a user environment variable[System.Environment]::GetEnvironmentVariable("PATH", "User")
Package Management
# List top-level npm packagesnpm list --depth=0# Update global packagesnpm update -g# Install with pnpm (frozen lockfile)pnpm install --frozen-lockfile
Security Features Explained
The PowerShell tool integrates with Claude Code's dangerous-command detection system. The four behaviors below did not ship with v2.1.84 itself — they landed shortly after, in the v2.1.89–2.1.90 range on April 1, 2026. If you pinned an older build when you first tried the tool, update before relying on any of them.
Background Job Bypass Prevention
The PowerShell & operator at the end of a command can be used to sidestep security checks by running processes in the background. Claude Code detects trailing & usage and prompts for confirmation before proceeding.
# ⚠️ This will trigger a confirmation promptStart-Process notepad.exe &# ✅ Normal execution — no promptStart-Process notepad.exe
-ErrorAction Break Control
The -ErrorAction Break parameter can cause the PowerShell debugger to hang in certain conditions. Claude Code monitors for this and handles it safely so your session stays responsive.
Archive Extraction TOCTOU Prevention
Commands like Expand-Archive are checked for path safety before executing. This guards against Time-of-Check-Time-of-Use (TOCTOU) attacks where the target path could change between validation and execution.
PS 5.1 Argument Splitting Hardening
When external command arguments contain both double-quotes and whitespace, PowerShell 5.1 has known argument-splitting quirks. Claude Code detects this pattern and prompts for confirmation rather than auto-approving.
# ⚠️ Claude Code will prompt for this on PS 5.1# (arguments contain double-quotes AND whitespace)& "C:\Program Files\MyApp\app.exe" "input file.txt"
Where Auto Mode's New Default Collides With the PowerShell Tool
As of August 14, 2026, auto mode is on by default for Pro, Max, and Team. Instead of approving each step, a classifier stops only on operations judged irreversible, destructive, or reaching outside your environment.
There's a mismatch here that only Windows users run into: the PowerShell tool doesn't support auto mode yet. The default changed, but commands routed through PowerShell are still not auto-approved, so the prompts keep coming. Bash moves along quietly while PowerShell stops — which makes it very easy to assume your configuration is broken.
I've come to treat that asymmetry as a design constraint rather than a defect, and I split work along it:
What you want
Where to route it
Why
Long automated runs without interruption
Bash (via WSL2)
The only path that benefits from auto mode
Fixed, repetitive routines
A hook with "shell": "powershell"
Works independently of the opt-in flag; no prompt in the loop
Registry, services, credential stores
The PowerShell tool (with prompts)
WSL2 can't reach these at all
That third row treats the prompt as a feature. Rewriting the registry or bouncing a service is worth pausing on anyway. The auto-mode limitation happens to overlap almost exactly with the territory I'd want to be careful in — a fortunate coincidence.
The behavior of auto mode still prompting on Windows registry writes is tracked in claude-code issue #51916. Until the preview label comes off, it's safer to design around the asymmetry than to wait for it to disappear.
Three Changes to Windows Permissions in Two Days
Since I first wrote this in April, the Windows permission story has continued — specifically on August 13 (v2.1.232) and August 14 (v2.1.233). Reading either release alone will lead you to the wrong conclusion, so here they are side by side.
v2.1.232 shipped three fixes that matter directly to Windows users:
A PowerShell permission bypass where a parameter writing to a variable could silently overwrite $PSDefaultParameterValues and redirect where later commands read and wrote files. This one is about the PowerShell tool itself
A Windows bypass where Git Bash followed Cygwin-style symlinks that path validation treated as ordinary files
Nested git repositories inheriting trust from a parent directory; each repo now requires its own trust confirmation
Then, one day later, v2.1.233 reverted the second of those along with a related change that had started permission-checking input redirections (< file), with a note that a narrower version will return in a later release. The same release also fixed a v2.1.232 regression where auto mode on Windows kept stopping for approval on ordinary cd <dir> && <command> > file commands.
So as of August 16, this is where things stand:
Change
Current status
PowerShell $PSDefaultParameterValues overwrite
Fixed (still in place)
NT \??\ device prefix bypassing UNC validation (NTLM credential-leak vector)
Fixed in v2.1.233
Nested git repository trust inheritance
Fixed (still in place)
Git Bash Cygwin-style symlinks
Reverted (narrower version expected later)
Permission checks on < file redirection
Reverted (same)
Two practical takeaways. First, if you rewrote a runbook around the prompts v2.1.232 introduced, those operations pass silently again on v2.1.233. Since both reverted items are explicitly slated to return, that runbook is worth keeping rather than deleting.
Second, if Windows auto mode felt unusually noisy between August 13 and 14, that wasn't your configuration — it was the v2.1.232 regression. Upgrading clears it.
# Check what you're runningclaude --version# Updateclaude update
Permission boundaries shifting three times in two days is, read another way, evidence that the Windows path is finally getting real scrutiny. Rather than memorizing the specifics, I've found it more useful to simply keep checking claude --version.
Persistent Setup Patterns and Windows-Specific Pitfalls
So far we've covered /config and settings.json for enabling the tool, but in practice you'll hit Windows-specific issues: settings disappearing after reboot, VS Code not picking them up, PowerShell execution policies blocking scripts. Here are three persistence patterns I've settled on after running this on multiple Windows development machines.
Pattern 1: PowerShell Profile ($PROFILE) — Personal Dev Machines
Writing the environment variable into $PROFILE (loaded on every PowerShell start) is the most flexible and recommended approach.
# Find the profile path (will be created if missing)echo $PROFILE# Example: C:\Users\YourName\Documents\PowerShell\Microsoft.PowerShell_profile.ps1# Edit itnotepad $PROFILE
Add this line and save:
# Enable Claude Code PowerShell tool by default$env:CLAUDE_CODE_USE_POWERSHELL_TOOL = "1"
The setting takes effect in new terminals. To apply immediately in the current shell, run . $PROFILE.
Pattern 2: Windows System Environment Variable — Team Distribution
If you launch from multiple terminals or GUI tools (VS Code, Cursor, etc.) and want the variable always set, register it as a Windows system environment variable.
Windows key → search "environment variables" → "Edit the system environment variables"
Combined with Pattern 1 or 2 above, the variable is inherited automatically in the integrated terminal.
Common Pitfall: "Running Scripts Is Disabled on This System"
You may hit Set-ExecutionPolicy restrictions occasionally. In some organizations the policy can't be changed, so check the current state before deciding.
# Check the current policyGet-ExecutionPolicy# Allow scripts for the current user (the most conservative useful change)Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
RemoteSigned allows local scripts and requires signature verification only for downloaded ones — a reasonable middle ground for individual developers and small teams. On managed corporate PCs, check with IT before changing this.
Real-World Workflow Examples
1. Azure Resource Management
# Show current Azure account detailsaz account show --output json | ConvertFrom-Json | Select-Object name, id# List all resource groupsaz group list --output table# Check App Service running stateaz webapp show --name my-app --resource-group my-rg --query "state" --output tsv
You can ask Claude directly:
List all resources in our dev resource group and identify any App Services
that haven't been accessed in the past 30 days.
2. Active Directory / Entra ID Operations
# Import the AD module (requires domain-joined machine)Import-Module ActiveDirectory# Check which groups a user belongs toGet-ADUser -Identity "john.doe" -Properties MemberOf | Select-Object MemberOf# Find disabled accountsSearch-ADAccount -AccountDisabled -UsersOnly | Select-Object Name, SamAccountName
3. Windows Event Log Analysis
# Get error events from the last 24 hours$since = (Get-Date).AddHours(-24)Get-WinEvent -LogName "Application" -FilterHashtable @{ Level = 2 StartTime = $since} | Select-Object TimeCreated, Id, Message | Format-Table -AutoSize
Ask Claude to "analyze the application event log for anomalies," and it will run this query and interpret the results for you.
The PowerShell tool is fully integrated with Claude Code's /env command. Environment variables you set persist across both Bash and PowerShell tool invocations within the same session.
This makes it easy to simulate CI/CD environments or manage secrets locally during development.
Troubleshooting
Error: "Running scripts is disabled on this system"
File C:\...\script.ps1 cannot be loaded because running scripts is disabled on this system.
Fix: Check and update your PowerShell execution policy.
# See current policiesGet-ExecutionPolicy -List# Allow local scripts for the current user (recommended)Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Error: "pwsh is not found"
This happens when pwsh.exe can't be found and the fallback to powershell.exe (5.1) doesn't cover your case either. Installing PowerShell 7 is the reliable fix.
# Install PowerShell 7 via wingetwinget install --id Microsoft.PowerShell -e# Or download the MSI directly from GitHub Releases# https://github.com/PowerShell/PowerShell/releases
Restart Claude Code after installation.
Constant Confirmation Prompts (Not a Bug)
Getting a prompt every time Claude runs something as harmless as Get-ChildItem makes it feel like you misconfigured something. You didn't. This is how the preview behaves: the PowerShell tool doesn't support auto mode, so commands routed through PowerShell are never auto-approved. There is no blanket allow-list setting that switches this off today.
Two things actually help. The first is to pick "always allow" when a prompt appears — /permissions writes the matching rule for you, so you can accumulate approvals for read-only cmdlets without hand-writing rule syntax you'd have to look up anyway.
/permissions
The second is to move repetitive, well-understood work into a hook. Because a hook's "shell": "powershell" works independently of the opt-in flag, you can run fixed routines through PowerShell without a prompt in the loop. I moved formatting and linting there and left interactive commands prompting. What wears you down isn't the number of interruptions so much as not being able to predict them.
Two Switch Decisions That Trip People Up
PowerShell 5.1 vs. PowerShell 7 (pwsh)
Default to PowerShell 7. It's faster, cross-platform, has better security primitives, and supports newer syntax. The exception is when a Windows-only module like ActiveDirectory ships only for 5.1 — in that case, switch back per task. There's no global "right answer" here, but 7 is the right starting point.
Does the PowerShell tool make WSL2 obsolete?
Not quite. WSL2 still wins when you need Linux-specific tooling, Docker, or native Python/C builds. The PowerShell tool wins for Windows-native administration and .NET automation. The rule of thumb I use: "Linux-leaning task → WSL2, Windows-leaning task → PowerShell tool."
Recipe 1: Bootstrapping a Project with winget
Every README has a "install these tools" section, and most teams still install them by hand. Asking Claude to run a small winget block solves it once and gracefully skips already-installed tools.
# What runs when you ask Claude: "install everything this repo needs via winget"$tools = @("Microsoft.PowerShell", "GitHub.cli", "Microsoft.DotNet.SDK.9", "Microsoft.VisualStudioCode")foreach ($id in $tools) { if (-not (winget list --id $id -e --accept-source-agreements 2>$null | Select-String $id)) { winget install --id $id -e --silent --accept-source-agreements --accept-package-agreements } else { Write-Host "Skip: $id (already installed)" }}
The detail that matters is the winget list check before winget install. Skipping it leads Claude into double-installs that error out the whole script.
Recipe 2: Pairing PR Workflows with the gh CLI
GitHub CLI is fine in WSL, but installing gh on the Windows side lets you push and open PRs directly from PowerShell Tool calls. My favorite shortcut is to ask Claude to apply edits, commit, push, and open a PR in one go.
gh pr create --fill --web autofills the body and opens the browser, so you keep a final review checkpoint without slowing down. If you'd rather have Claude write the body, swap --fill for --body "$(cat .git/CLAUDE_NOTE.md)".
Recipe 3: One Command for dotnet Test + Coverage
dotnet test alone doesn't give you coverage; you usually need coverlet. Saving the right invocation as a recipe means Claude reproduces the same quality gate every time.
PowerShell's backtick line continuation feels odd if you came from Bash. Tell Claude once to break long commands with backticks and it sticks to that style.
Recipe 4: Crossing the WSL/PowerShell Boundary Safely
Even after PowerShell Tool gets traction, you still want WSL for tools that shine on Linux (latest ripgrep, jq, and friends). Calling WSL from PowerShell is the bridge — but path translation is where it bites.
# Correct way to grep a Windows path from WSL$winPath = "C:\Users\me\proj"$wslPath = wsl wslpath -a "$winPath"wsl rg --hidden --no-ignore "TODO" $wslPath
wslpath -a converts cleanly to POSIX form. Hand C:\Users\me\proj directly to WSL and you'll get "No such file" — Claude will keep doing this unless you record the recipe.
Recipe 5: Wiring Stripe and Firebase CLIs Into the Loop
I keep Stripe CLI and Firebase CLI on the Windows side. Once Claude can reach them through PowerShell Tool, debugging payments and AdMob feels notably less painful.
# Pull the last 100 events and surface only the failed payment intentsstripe events list --limit 100 --format json | ` ConvertFrom-Json | ` Where-Object { $_.type -like "*payment_intent.payment_failed*" } | ` Select-Object id, created, type, @{n="amount";e={$_.data.object.amount}} | Format-Table -AutoSize
Ask Claude "show me recent payment failures" and it will write and run something like this. Save the pattern in your CLAUDE.md ("for Stripe event analysis, use ConvertFrom-Json filters") so the next conversation skips the explanation.
Recipe 6: Restarting Windows Services Without Permission Surprises
Restart-Service often requires admin. Without guardrails, Claude tries it, hits a permission error, and silently moves on. I have Claude write a wrapper that explicitly nudges toward elevation when needed.
Through PowerShell Tool, -Verb RunAs opens a separate elevated process so the elevation prompt never blocks your existing session.
Before You Let These Run Unattended — Gate the Risky Operations
These recipes are comfortable when you watch each result. Running them unattended is a different proposition, because commands that rewrite your environment — winget install, Restart-Service — are sitting right there in the list.
As covered above, the PowerShell tool doesn't support auto mode today, so none of this runs fully unattended yet. But that's a side effect of the preview, not a safety guarantee, and it disappears the moment support lands. I try not to let "it stops on its own right now" stand in for an actual safeguard.
My rule of thumb is: let reads and lookups through, but pause on anything that changes state. The sturdiest PowerShell-side move is to add -WhatIf to state-changing cmdlets so Claude shows the plan first.
# Preview destructive operations with -WhatIf before applyingfunction Invoke-ServiceRestartSafely { param([string]$ServiceName, [switch]$Apply) if (-not $Apply) { Restart-Service -Name $ServiceName -WhatIf Write-Host "Plan only. Re-run with -Apply to execute." return } Restart-Service -Name $ServiceName -Force}
Note in your CLAUDE.md that destructive operations should be previewed with -WhatIf first, so cmdlets like Restart-Service or Remove-Item don't run for real on their own. Pair that with Claude Code's /permissions — allow lookups such as winget list, but require confirmation for installers like winget install — and even an unattended session keeps a hard stop right before anything that could break. It dovetails nicely with the elevation-prompt wrapper from Recipe 6.
Sharing Recipes Across a Team
You can keep these in your personal Microsoft.PowerShell_profile.ps1, but I prefer dropping them in .tools/recipes.ps1 at the repo root so the team picks them up. Note the path in CLAUDE.md ("dot-source .tools/recipes.ps1 before running PowerShell"), and Claude will load the same recipes every session.
A Quick Benchmark: Startup Overhead vs. Going Through WSL2
Rather than settling the switch decision purely in my head, I ran the same task through both paths on a Windows 11 machine and measured the startup overhead. The task is deliberately light: listing the .ts files under the current directory.
# Measured through the PowerShell toolMeasure-Command { Get-ChildItem -Recurse -Filter *.ts | Out-Null } | Select-Object -ExpandProperty TotalMilliseconds# The same work through WSL2 (bash + find)Measure-Command { wsl find . -name '*.ts' | Out-Null } | Select-Object -ExpandProperty TotalMilliseconds
Running each five times against the same repository (~1,200 files), the median results looked like this:
Path
First call (cold)
Subsequent (warm)
PowerShell tool (native)
~190ms
~150ms
Via WSL2 (wsl find)
~1,050ms
~430ms
The absolute numbers shift with the machine and disk state, of course. But the pattern — WSL2 adding a fixed cost to the first invocation — held every time I re-measured. For a single heavy task it disappears into the noise. For a workflow that re-reads environment variables and fires dozens of small commands in a row, that fixed cost starts to shape how fast the loop feels.
The PowerShell tool added in Claude Code v2.1.84 genuinely changes the Windows experience, if only by removing the WSL2 hop. It's also an area where the enablement path and the preview's limits are easy to get wrong unless you go back to primary sources. Here's what to take away:
Enabling it is one line: CLAUDE_CODE_USE_POWERSHELL_TOOL: "1" in the env block of settings.json (there is no UI toggle)
It runs alongside the Bash tool, giving Claude Code native access to Windows resources
Turning it on doesn't make Claude prefer it — route work with defaultShell or a per-hook shell
Auto mode isn't supported, so prompts continue; choose deliberately where you want to be stopped
Windows permission checks moved three times in August, with two changes reverted — keep checking claude --version
Ideal for Azure, Active Directory, event log analysis, and enterprise CI/CD workflows
The /env command works seamlessly across both PowerShell and Bash tools
Tomorrow morning, add one line to your repo's README: which PowerShell script Claude should run first via the PowerShell Tool. Even something as small as "run ./scripts/setup.ps1 before anything else" reshapes how Claude opens its first session. Recipes are an asset that compound — the work pays back the second time you reach for them.
Share
Thank You for Reading
Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.