
Windows Vm
- 211 installs
- 401 repo stars
- Updated June 1, 2026
- obra/superpowers-lab
Provision and use Windows VMs for cross-platform testing from agent-driven workflows.
About
Windows VM skill helps solo builders spin up Windows test environments for agent-driven cross-platform QA without leaving their primary dev machine workflow.
- Windows VM provisioning patterns for agents.
- Cross-platform test isolation from macOS/Linux hosts.
- Superpowers lab environment setup.
Windows Vm by the numbers
- 211 all-time installs (skills.sh)
- +10 installs in the week ending Jul 26, 2026 (Skillselion tracking)
- Ranked #454 of 1,041 Cloud & Infrastructure skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Jul 26, 2026 (Skillselion catalog sync)
npx skills add https://github.com/obra/superpowers-lab --skill windows-vmAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 211 |
|---|---|
| repo stars | ★ 401 |
| Security audit | 1 / 3 scanners passed |
| Last updated | June 1, 2026 |
| Repository | obra/superpowers-lab ↗ |
What it does
Provision and use Windows VMs for cross-platform testing from agent-driven workflows.
Files
Headless Windows 11 VM
Manage a headless Windows 11 VM running via dockur/windows in Docker with KVM acceleration. The VM is accessible via SSH only — no RDP or GUI required.
Host prerequisites
- Docker
- KVM support (
/dev/kvmmust exist — check withls /dev/kvm) sshpass(sudo apt install sshpass)imagemagick(optional, for screenshot debugging:sudo apt install imagemagick)
Configuration
- Container name:
windows11 - VM directory:
$HOME/windows-vm/ storage/— VM disk image (managed by dockur, wiped on recreate)iso/win11x64.iso— cached Windows ISO (7.3GB, persists across recreates)oem/install.bat— post-install script (installs OpenSSH Server)- Credentials: user / password
- SSH:
localhost:2222(bound to 127.0.0.1 only) - RDP:
localhost:3389(bound to 127.0.0.1 only, fallback) - Web console:
localhost:8006(VNC in browser, for debugging) - Resources: 8GB RAM, 4 CPU cores, 64GB disk
Actions
create — First-time setup or full recreate
1. Ensure directories exist:
mkdir -p "$HOME/windows-vm/oem" "$HOME/windows-vm/storage" "$HOME/windows-vm/iso"2. Ensure $HOME/windows-vm/oem/install.bat exists with OpenSSH setup:
@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.3. If recreating, remove the old container and disk:
docker stop windows11 && docker rm windows11
rm -f "$HOME/windows-vm/storage/data.img"4. Launch the container. There are two cases:
If cached ISO exists ($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/windowsFirst time (no cached ISO) — omit the /boot.iso mount and add 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/windowsAfter the ISO downloads and Windows boots, immediately copy the ISO out before the container is ever stopped (dockur wipes /storage on recreate):
cp "$HOME/windows-vm/storage/win11x64.iso" "$HOME/windows-vm/iso/win11x64.iso"5. Wait for Windows install + OpenSSH setup to complete. This takes 20-30 minutes for a fresh install (the OEM install.bat runs at the end of Windows OOBE and downloads OpenSSH from Microsoft, which is slow). Monitor with:
docker logs -f windows11You can also watch the VM screen via the web console at http://localhost:8006.
To check if SSH is up:
sshpass -p 'password' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p 2222 user@localhost "whoami"6. Once SSH is responding, install Node.js and Claude Code by piping a setup script via stdin (avoids PowerShell escaping hell over SSH):
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
PSNote: the connection will drop when sshd restarts — that's expected.
7. Clear the stale host key (new VM = new host key) and verify:
ssh-keygen -f ~/.ssh/known_hosts -R '[localhost]:2222'
sshpass -p 'password' ssh -o StrictHostKeyChecking=no -p 2222 user@localhost "claude --version"start — Start a stopped VM
docker start windows11stop — Stop the VM
docker stop windows11restart — Restart the VM
docker restart windows11status — Check VM status
docker ps -f name=windows11 --format "table {{.Status}}\t{{.Ports}}"
docker logs windows11 2>&1 | tail -5ssh — Connect to the VM
ssh -p 2222 user@localhostscreenshot — See what's on the VM screen (for debugging)
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.pngImportant Notes
- ISO caching: The
/storagevolume is managed by dockur and gets wiped on recreate. Store the ISO separately in$HOME/windows-vm/iso/and mount it as/boot.isoto skip the 7.3GB download. - `--cap-add NET_ADMIN` is required for port forwarding to work. Without it, QEMU falls back to user-mode networking and port forwarding silently fails.
- `--device /dev/kvm` is required for hardware acceleration.
- Boot time: Fresh install takes 20-30 min (Windows install + OpenSSH download from Microsoft). Subsequent boots from existing
data.imgare fast (~2 min). - Ports are bound to
127.0.0.1only — not exposed to the network. - Do NOT use
-e VERSION="win11"when mounting/boot.iso— the version is auto-detected from the ISO.
Post-install gotchas
- Node.js is not pre-installed — the Claude Code install script (
irm https://claude.ai/install.ps1 | iex) will report success butclaudewon't work without Node. Install Node.js via MSI first. - npm global bin not in PATH — Node's MSI adds
C:\Program Files\nodejsto PATH but notC:\Users\user\AppData\Roaming\npm(wherenpm install -gputs binaries). Must add it to the system PATH (not user PATH) because OpenSSH's sshd only reads system PATH. After changing system PATH, restart sshd. - PowerShell execution policy — Default policy is
Restricted, which blocksclaude.ps1. Must set toRemoteSignedat LocalMachine scope (not CurrentUser) for it to take effect in SSH sessions. - Escaping hell — Running PowerShell commands over SSH with nested quotes is unreliable. Pipe scripts via stdin using
powershell -ExecutionPolicy Bypass -Command -instead. - Interactive SSH sessions don't get full PATH — Windows OpenSSH sshd doesn't properly propagate the system PATH to interactive PowerShell sessions. Fix: create a system-wide PowerShell profile (
$PROFILE.AllUsersAllHosts) that rebuilds$env:Pathfrom the registry on every login. - winget may not work — The Microsoft Store certificate can fail in a VM. Use direct MSI/installer downloads instead.
- Host key changes — Each recreated VM gets new SSH host keys. Run
ssh-keygen -R '[localhost]:2222'to clear the old one.
Related skills
FAQ
Is Windows Vm safe to install?
skills.sh reports 1 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.