关于 windows-vm
windows-vm 是通过 Docker 和 KVM 运行的无头 Windows 11 虚拟机管理技能,面向需要 SSH 访问 Windows 环境的开发者。它涵盖虚拟机创建、生命周期管理、连接和屏幕调试。
主要功能
- 01Docker 中创建无头 Windows 11 VM
- 02通过 SSH 连接虚拟机
- 03启动、停止、重启和查看状态
- 04截取虚拟机屏幕用于调试
- 05缓存 ISO 以便重建
适用场景
- 01提供隔离的 Windows 命令行环境
- 02通过 SSH 管理 Windows VM
- 03调试虚拟机启动画面
- 04保留 ISO 以减少重建下载
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ obra/ superpowers-lab --skill windows-vm安装后在 Claude Code 中输入/windows-vm确认已加载。
详细介绍
无头 Windows 11 VM
在 Docker 中通过 dockur/windows 运行使用 KVM 加速的无头 Windows 11 VM。只能通过 SSH 访问 VM — 无需 RDP 或 GUI。
主机前置条件
- Docker
- 支持 KVM(必须存在
/dev/kvm— 使用ls /dev/kvm检查) sshpass(sudo apt install sshpass)imagemagick(可选,用于截图调试:sudo apt install imagemagick)
配置
- 容器名称:
windows11 - VM 目录:
$HOME/windows-vm/storage/— VM 磁盘映像(由 dockur 管理,重新创建时会清除)iso/win11x64.iso— 缓存的 Windows ISO(7.3GB,重新创建后仍会保留)oem/install.bat— 安装后脚本(安装 OpenSSH Server)
- 凭据:用户名 / 密码
- SSH:
localhost:2222(仅绑定到 127.0.0.1) - RDP:
localhost:3389(仅绑定到 127.0.0.1,备用) - Web 控制台:
localhost:8006(浏览器中的 VNC,用于调试) - 资源:8GB 内存、4 个 CPU 核心、64GB 磁盘
操作
create — 首次设置或完整重新创建
-
确保目录存在:
mkdir -p "$HOME/windows-vm/oem" "$HOME/windows-vm/storage" "$HOME/windows-vm/iso" -
确保
$HOME/windows-vm/oem/install.bat存在并包含 OpenSSH 设置:@echo off echo Installing OpenSSH Server... powershell -Command "Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0" 2>nul powershell -Command "Get-WindowsCapability -Online -Name OpenSSH.Server* | Add-WindowsCapability -Online" 2>nul dism /Online /Add-Capability /CapabilityName:OpenSSH.Server~~~~0.0.1.0 2>nul powershell -Command "Start-Service sshd" 2>nul powershell -Command "Set-Service -Name sshd -StartupType Automatic" powershell -Command "New-ItemProperty -Path 'HKLM:\SOFTWARE\OpenSSH' -Name DefaultShell -Value 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' -PropertyType String -Force" powershell -Command "New-NetFirewallRule -Name 'OpenSSH-Server' -DisplayName 'OpenSSH Server' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22" powershell -Command "Get-Service sshd" 2>nul echo Done. -
如果重新创建,请移除旧容器和磁盘:
docker stop windows11 && docker rm windows11 rm -f "$HOME/windows-vm/storage/data.img" -
启动容器。有两种情况:
如果缓存的 ISO 存在(
$HOME/windows-vm/iso/win11x64.iso):docker run -d \ --name windows11 \ -p 127.0.0.1:3389:3389 \ -p 127.0.0.1:2222:22 \ -p 127.0.0.1:8006:8006 \ -e RAM_SIZE="8G" \ -e CPU_CORES="4" \ -e DISK_SIZE="64G" \ -e USERNAME="user" \ -e PASSWORD="password" \ --cap-add NET_ADMIN \ --device /dev/kvm \ -v "$HOME/windows-vm/storage:/storage" \ -v "$HOME/windows-vm/oem:/oem" \ -v "$HOME/windows-vm/iso/win11x64.iso:/boot.iso" \ dockurr/windows首次创建(没有缓存的 ISO) — 省略
/boot.iso挂载并添加VERSION:docker run -d \ --name windows11 \ -p 127.0.0.1:3389:3389 \ -p 127.0.0.1:2222:22 \ -p 127.0.0.1:8006:8006 \ -e RAM_SIZE="8G" \ -e CPU_CORES="4" \ -e DISK_SIZE="64G" \ -e VERSION="win11" \ -e USERNAME="user" \ -e PASSWORD="password" \ --cap-add NET_ADMIN \ --device /dev/kvm \ -v "$HOME/windows-vm/storage:/storage" \ -v "$HOME/windows-vm/oem:/oem" \ dockurr/windowsISO 下载完成且 Windows 启动后,必须在停止容器之前立即将 ISO 复制出来(dockur 在重新创建时会清除
/storage):cp "$HOME/windows-vm/storage/win11x64.iso" "$HOME/windows-vm/iso/win11x64.iso" -
等待 Windows 安装和 OpenSSH 设置完成。全新安装需要 20-30 分钟,因为 OEM install.bat 会在 Windows OOBE 结束时运行,并从 Microsoft 下载 OpenSSH,过程较慢。使用以下命令监控:
docker logs -f windows11也可以通过
http://localhost:8006的 Web 控制台查看 VM 屏幕。检查 SSH 是否已启动:
sshpass -p 'password' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p 2222 user@localhost "whoami" -
SSH 可用后,通过 stdin 管道传入设置脚本来安装 Node.js 和 Claude Code(避免通过 SSH 使用 PowerShell 时繁琐的转义处理):
cat << 'PS' | sshpass -p 'password' ssh -o StrictHostKeyChecking=no -p 2222 user@localhost "powershell -ExecutionPolicy Bypass -Command -" # Download and install Node.js silently Invoke-WebRequest -Uri 'https://nodejs.org/dist/v22.14.0/node-v22.14.0-x64.msi' -OutFile 'C:\Users\user\node-install.msi' Start-Process msiexec.exe -ArgumentList '/i C:\Users\user\node-install.msi /qn /norestart' -Wait -Verb RunAs Write-Host "Node.js installed" # Install Claude Code globally & 'C:\Program Files\nodejs\npm.cmd' install -g @anthropic-ai/claude-code Write-Host "Claude Code installed" # Add npm global bin to SYSTEM PATH (user PATH is not read by sshd) $systemPath = [Environment]::GetEnvironmentVariable('Path', 'Machine') $additions = @() if ($systemPath -notlike '*AppData*npm*') { $additions += 'C:\Users\user\AppData\Roaming\npm' } if ($systemPath -notlike '*Git\cmd*') { $additions += 'C:\Program Files\Git\cmd' } if ($additions.Count -gt 0) { [Environment]::SetEnvironmentVariable('Path', $systemPath + ';' + ($additions -join ';'), 'Machine') Write-Host "Added to system PATH: $($additions -join ', ')" } # Set execution policy machine-wide (required for claude.ps1) Set-ExecutionPolicy RemoteSigned -Scope LocalMachine -Force -ErrorAction SilentlyContinue # Create system-wide PowerShell profile that rebuilds PATH from registry on login. # Without this, interactive SSH sessions don't pick up the full system PATH. $profileDir = Split-Path $PROFILE.AllUsersAllHosts if (-not (Test-Path $profileDir)) { New-Item -ItemType Directory -Path $profileDir -Force } @' $machinePath = [Environment]::GetEnvironmentVariable('Path', 'Machine') $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') $env:Path = "$machinePath;$userPath" '@ | Set-Content -Path $PROFILE.AllUsersAllHosts -Force Write-Host "PowerShell profile created" # Restart sshd so it picks up the new PATH Restart-Service sshd -Force PS注意:sshd 重启时连接会断开 — 这是正常现象。
-
清除过期的主机密钥(新 VM 会有新的主机密钥)并进行验证:
ssh-keygen -f ~/.ssh/known_hosts -R '[localhost]:2222' sshpass -p 'password' ssh -o StrictHostKeyChecking=no -p 2222 user@localhost "claude --version"
start — 启动已停止的 VM
docker start windows11
stop — 停止 VM
docker stop windows11
restart — 重启 VM
docker restart windows11
status — 检查 VM 状态
docker ps -f name=windows11 --format "table {{.Status}}\t{{.Ports}}"
docker logs windows11 2>&1 | tail -5
ssh — 连接到 VM
ssh -p 2222 user@localhost
screenshot — 查看 VM 屏幕内容(用于调试)
docker exec windows11 bash -c "echo 'screendump /tmp/screen.ppm' | nc -w 2 localhost 7100" > /dev/null 2>&1
sleep 1
docker cp windows11:/tmp/screen.ppm /tmp/screen.ppm
convert /tmp/screen.ppm /tmp/screen.png
重要说明
- ISO 缓存:
/storage卷由 dockur 管理,重新创建时会被清除。请将 ISO 单独存放在$HOME/windows-vm/iso/,并挂载为/boot.iso,以跳过 7.3GB 的下载。 --cap-add NET_ADMIN是端口转发正常工作的必需项。没有它,QEMU 会回退到用户模式网络,且端口转发会静默失效。--device /dev/kvm是硬件加速的必需项。- 启动时间:全新安装需要 20-30 分钟(安装 Windows 并从 Microsoft 下载 OpenSSH)。使用现有
data.img后续启动很快(约 2 分钟)。 - 端口仅绑定到
127.0.0.1— 不会暴露到网络。 - 挂载
/boot.iso时,不要使用-e VERSION="win11"— 版本会根据 ISO 自动检测。
安装后的注意事项
- 未预装 Node.js — Claude Code 安装脚本(
irm https://claude.ai/install.ps1 | iex)会报告成功,但没有 Node.js,claude将无法运行。请先通过 MSI 安装 Node.js。 - npm 全局二进制目录不在 PATH 中 — Node 的 MSI 会将
C:\Program Files\nodejs添加到 PATH,但不会添加C:\Users\user\AppData\Roaming\npm(npm install -g会将二进制文件放在此处)。必须将其添加到系统 PATH(而不是用户 PATH),因为 OpenSSH 的 sshd 只读取系统 PATH。更改系统 PATH 后,请重启 sshd。 - PowerShell 执行策略 — 默认策略为
Restricted,会阻止运行claude.ps1。必须在 LocalMachine 范围(而不是 CurrentUser)将策略设为RemoteSigned,这样才能在 SSH 会话中生效。 - 转义问题 — 通过 SSH 运行带有嵌套引号的 PowerShell 命令并不可靠。请使用
powershell -ExecutionPolicy Bypass -Command -,通过 stdin 传递脚本。 - 交互式 SSH 会话无法获取完整 PATH — Windows OpenSSH sshd 无法正确地将系统 PATH 传递到交互式 PowerShell 会话。解决方法:创建系统范围的 PowerShell 配置文件(
$PROFILE.AllUsersAllHosts),在每次登录时从注册表重建$env:Path。 - winget 可能无法使用 — Microsoft Store 证书在 VM 中可能会失效。请改用直接下载 MSI/安装程序。
- 主机密钥变更 — 每次重新创建 VM,都会生成新的 SSH 主机密钥。运行
ssh-keygen -R '[localhost]:2222'以清除旧密钥。