windows-vm について
windows-vmは、DockerとKVMでヘッドレスのWindows 11 VMを実行・管理するスキルです。SSHで利用できるWindows環境が必要な開発者向けに、VMの操作や画面のデバッグを扱います。
主な機能
- 01DockerでヘッドレスWindows 11 VMを作成
- 02SSH経由でVMに接続
- 03VMの起動、停止、再起動、状態確認
- 04デバッグ用のVM画面キャプチャ
- 05再作成時に備えたISOのキャッシュ
活用シーン
- 01分離されたWindowsコマンドライン環境の提供
- 02SSH経由でのWindows VM管理
- 03VMの起動画面のデバッグ
- 04ISOの再利用による再ダウンロード回避
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ obra/ superpowers-lab --skill windows-vmインストール後、Claude Code で/windows-vmを入力して読み込まれたか確認します。
詳細
ヘッドレス Windows 11 VM
KVM アクセラレーション付きの Docker 上で実行される dockur/windows のヘッドレス Windows 11 VM を管理します。VM には SSH のみでアクセスでき、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 をインストール)
- 認証情報:user / password
- SSH:
localhost:2222(127.0.0.1 のみでバインド) - RDP:
localhost:3389(127.0.0.1 のみでバインド。フォールバック用) - Web コンソール:
localhost:8006(ブラウザー内の VNC。デバッグ用) - リソース:RAM 8GB、CPU 4 コア、ディスク 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" -
コンテナーを起動します。以下の 2 つのケースがあります:
キャッシュ済み 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 windows11http://localhost:8006の Web コンソールから VM の画面を見ることもできます。SSH が起動したかどうかを確認するには:
sshpass -p 'password' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p 2222 user@localhost "whoami" -
SSH 経由での PowerShell のエスケープ処理を避けるため、標準入力からセットアップスクリプトを渡して Node.js と Claude Code をインストールします:
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 回目以降の起動は高速です(約 2 分)。 - ポートは
127.0.0.1のみでバインドされ、ネットワークには公開されません。 /boot.isoをマウントする場合は、-e VERSION="win11"を使用しないでください。バージョンは ISO から自動検出されます。
インストール後の注意点
- Node.js は事前にインストールされていません — Claude Code のインストールスクリプト(
irm https://claude.ai/install.ps1 | iex)は成功したと表示されますが、Node をインストールしないとclaudeは動作しません。まず MSI で Node.js をインストールしてください。 - npm のグローバル bin が PATH に含まれていません — Node の MSI は
C:\Program Files\nodejsを PATH に追加しますが、npm install -gでバイナリが配置されるC:\Users\user\AppData\Roaming\npmは追加しません。OpenSSH の sshd はシステム PATH しか読み取らないため、ユーザー PATH ではなくシステム PATH に追加する必要があります。システム PATH を変更した後、sshd を再起動してください。 - PowerShell の実行ポリシー — 既定のポリシーは
Restrictedで、claude.ps1がブロックされます。SSH セッションで有効にするには、CurrentUser ではなく LocalMachine スコープでRemoteSignedに設定する必要があります。 - エスケープの問題 — 入れ子の引用符を含む PowerShell コマンドを SSH 経由で実行すると、正常に動作しないことがあります。代わりに、
powershell -ExecutionPolicy Bypass -Command -を使い、スクリプトを標準入力経由でパイプしてください。 - 対話型 SSH セッションでは完全な PATH が設定されません — Windows OpenSSH の sshd は、システム PATH を対話型 PowerShell セッションに正しく引き継ぎません。対処法:システム全体に適用される PowerShell プロファイル(
$PROFILE.AllUsersAllHosts)を作成し、ログインのたびにレジストリから$env:Pathを再構築してください。 - winget が動作しない場合があります — VM では Microsoft Store の証明書が原因で失敗することがあります。代わりに MSI またはインストーラーを直接ダウンロードしてください。
- ホストキーの変更 — VM を再作成するたびに、新しい SSH ホストキーが割り当てられます。
ssh-keygen -R '[localhost]:2222'を実行して古いキーを削除してください。