# Upgrading PowerShell 7 Without Killing Your Claude Code Session

> Installing a PowerShell 7 update from inside a Claude Code session force-closes the session, and opening a second terminal does not help. Why Windows Restart Manager does this, and three ways around it.

Source: https://chanmeng.org/blog/upgrading-powershell-without-killing-claude-code
Author: Chan Meng — https://chanmeng.org
Published: 2026-06-24
Tags: Claude Code, DevOps

---

*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

1. Download the MSI.
2. Write a self-elevating `.cmd` that runs `msiexec /i "<msi>" /passive /norestart`.
3. Then:
   - Exit Claude **and fully close the host PowerShell window.** Exiting Claude alone leaves the `pwsh` window still holding the binary.
   - Double-click the `.cmd`. It runs in `cmd`, not `pwsh`. Answer **Yes** to UAC.
4. 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`

```bat
@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()"
pause
```

### Option 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:

```powershell
& "C:\Program Files\PowerShell\7\pwsh.exe" -NoProfile -Command '$PSVersionTable.PSVersion.ToString()'
(Get-Item "C:\Program Files\PowerShell\7\pwsh.exe").VersionInfo.ProductVersion
```

## Notes

- Put the MSI, the `.cmd` and 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.
