Written as a private engineering note, 23 June 2026, after upgrading PowerShell 7.6.2 to 7.6.3 on Windows. Republished here, lightly edited for a reader.
The problem#
Upgrading PowerShell 7 from inside a Claude Code session repeatedly killed the session. The terminal was left showing only:
Resume this session with:
claude --resume <id>
Why it happens#
Claude Code runs inside a pwsh.exe (PowerShell 7) terminal window. The PowerShell MSI replaces C:\Program Files\PowerShell\7\pwsh.exe. Windows Installer's Restart Manager detects every process holding that file — including the host terminal — and force-closes it. The act of installing closes the very terminal Claude is running in.
The key insight, and the thing that wasted the most time: opening a different terminal to launch the installer does not help. Restart Manager targets the process that holds the file, which is the host terminal — not the process that launched msiexec.
Two extra gotchas#
winget lags behind. It only knew about 7.6.2 when 7.6.3 was already out. Get the MSI straight from GitHub instead:
- Latest tag:
https://api.github.com/repos/PowerShell/PowerShell/releases/latest - MSI:
https://github.com/PowerShell/PowerShell/releases/download/v<VER>/PowerShell-<VER>-win-x64.msi
It needs admin. This is a per-machine install into Program Files, and the session normally runs non-elevated, so expect a UAC prompt.
The fix — never run the installer from inside the session#
Three options, in order of preference.
Option B — cleanest, and the one that worked#
- Download the MSI.
- Write a self-elevating
.cmdthat runsmsiexec /i "<msi>" /passive /norestart. - Then:
- Exit Claude and fully close the host PowerShell window. Exiting Claude alone leaves the
pwshwindow still holding the binary. - Double-click the
.cmd. It runs incmd, notpwsh. Answer Yes to UAC.
- Exit Claude and fully close the host PowerShell window. Exiting Claude alone leaves the
- It installs immediately and completely — no reboot needed. Reopen Claude afterwards.
The .cmd should check tasklist for pwsh.exe and pause with a warning if any PowerShell 7 process is still running.
Reference install-pwsh.cmd#
@echo off
setlocal
set "MSI=<path to>\PowerShell-7.6.3-win-x64.msi"
set "LOG=<path to>\install.log"
REM --- Self-elevate (UAC) if not already admin ---
net session >nul 2>&1
if %errorlevel% neq 0 (
echo Requesting administrator privileges...
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
exit /b
)
REM --- Warn if any pwsh.exe still running ---
tasklist /fi "imagename eq pwsh.exe" 2>nul | find /i "pwsh.exe" >nul
if %errorlevel%==0 (
echo [WARNING] pwsh.exe still running. Close ALL PowerShell 7 windows, then press any key.
pause >nul
)
msiexec /i "%MSI%" /passive /norestart /l*v "%LOG%"
echo Exit code: %errorlevel%
"C:\Program Files\PowerShell\7\pwsh.exe" -NoProfile -Command "$PSVersionTable.PSVersion.ToString()"
pauseOption A — install now, finalize on reboot#
Launch elevated msiexec with Restart Manager disabled:
msiexec /i "<msi>" /qn /norestart MSIRESTARTMANAGERCONTROL=Disable REBOOT=ReallySuppress
With Restart Manager disabled, the in-use pwsh.exe is queued via PendingFileRenameOperations and swapped on the next reboot; the current session survives. Costs one UAC click plus a later reboot.
Option C — scheduled task#
Register a one-time scheduled task with highest privileges to run the MSI at next logon, then self-delete. You get a clean install at logon, when no pwsh holds the binary. Costs one UAC to register plus a re-logon or reboot.
Verify success#
This works even while the old host is still live, because it checks the on-disk binary rather than the running process:
& "C:\Program Files\PowerShell\7\pwsh.exe" -NoProfile -Command '$PSVersionTable.PSVersion.ToString()'
(Get-Item "C:\Program Files\PowerShell\7\pwsh.exe").VersionInfo.ProductVersionNotes#
- Put the MSI, the
.cmdand the log in a scratch directory, and clean it up afterwards. - Confirmed working on 2026-06-23: upgraded 7.6.2 → 7.6.3 via Option B.