Install the VirtIO Arm64 drivers with pnputil; make OpenSSH a batch file
On Arm64 Windows the VirtIO guest tools installer is an x86 program and the VirtIO ISO has no Arm64 package for it, so the first-logon script failed there and the guest had no network (no NetKVM driver). Install the Arm64 NetKVM, vioserial, Balloon, viorng and vioinput drivers from their folders on the ISO with pnputil instead. The OpenSSH Server capability is downloaded through Windows Update, which can take very long and blocked the rest of the script. Move it, with the administrator authorized key, into 05-Install-OpenSSH-Admin.bat, which the script copies to the Installers folder on the desktop to run by hand. Update the vm-images submodule to the build script that runs on Debian. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1732ec39d0
commit
69dcfe1d9f
4 files changed
+104
-67
No files matched your search
@@ -168,13 +168,17 @@ from the shared Windows 11 QCOW2 base image:
|
|||||||
It creates a persistent 64G disk at `.vm/windows11/disk.qcow2`, automatically
|
It creates a persistent 64G disk at `.vm/windows11/disk.qcow2`, automatically
|
||||||
partitions it, completes OOBE, creates the local administrator `guofang` with
|
partitions it, completes OOBE, creates the local administrator `guofang` with
|
||||||
the initial password `wang`, and enables Remote Desktop on
|
the initial password `wang`, and enables Remote Desktop on
|
||||||
`localhost:3389`. During the first login it also installs and enables the
|
`localhost:3389`. During the first login it also silently installs the VirtIO
|
||||||
Windows OpenSSH Server on `localhost:2222` and silently installs the VirtIO
|
drivers (the guest tools installer on amd64, the Arm64 driver packages from the
|
||||||
Windows guest tools. It also installs the host's configured SSH public key for
|
VirtIO ISO with `pnputil` on arm64), without which the guest has no network on
|
||||||
passwordless administrator login. The installer includes the VirtIO drivers, SPICE vdagent,
|
arm64. The installer includes the VirtIO drivers, SPICE vdagent, and QEMU Guest
|
||||||
and QEMU Guest Agent. Connect with `ssh guofang@localhost -p 2222`. The launcher
|
Agent. The launcher exposes the vdagent channel for host/guest clipboard
|
||||||
exposes the vdagent channel for host/guest clipboard integration and the QEMU Guest Agent at
|
integration and the QEMU Guest Agent at `.vm/windows11/qemu-guest-agent.sock`.
|
||||||
`.vm/windows11/qemu-guest-agent.sock`. Change the password after first login.
|
Change the password after first login. The OpenSSH Server is downloaded through
|
||||||
|
Windows Update, which can be slow, so it is not installed automatically: run
|
||||||
|
`05-Install-OpenSSH-Admin.bat` from the `Installers` folder on the desktop as
|
||||||
|
administrator, then connect with `ssh guofang@localhost -p 2222`; it also installs
|
||||||
|
the host's configured SSH public key for passwordless administrator login.
|
||||||
The Windows VM hardware (8G memory, 8 CPUs, system disk, devices)
|
The Windows VM hardware (8G memory, 8 CPUs, system disk, devices)
|
||||||
is defined in `qemu/windows11.ini`, with the accelerators and machine type in
|
is defined in `qemu/windows11.ini`, with the accelerators and machine type in
|
||||||
`qemu/windows11-<os>-<arch>.ini`; the launcher renders the former to
|
`qemu/windows11-<os>-<arch>.ini`; the launcher renders the former to
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
title Install OpenSSH Server
|
||||||
|
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo Please right-click this file and choose "Run as administrator".
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
rem The capability is downloaded through Windows Update, which can be slow.
|
||||||
|
echo Installing the OpenSSH Server Windows capability...
|
||||||
|
dism.exe /Online /Add-Capability /CapabilityName:OpenSSH.Server~~~~0.0.1.0
|
||||||
|
set "RC=%ERRORLEVEL%"
|
||||||
|
if not "%RC%"=="0" if not "%RC%"=="3010" (
|
||||||
|
echo dism exited with code %RC%.
|
||||||
|
pause
|
||||||
|
exit /b %RC%
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Starting the sshd service...
|
||||||
|
sc.exe config sshd start= auto
|
||||||
|
net.exe start sshd >nul 2>&1
|
||||||
|
sc.exe query sshd | find "RUNNING" >nul
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo The sshd service is not running.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
netsh.exe advfirewall firewall show rule name="OpenSSH-Server-In-TCP" >nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
netsh.exe advfirewall firewall add rule name="OpenSSH-Server-In-TCP" ^
|
||||||
|
dir=in action=allow protocol=TCP localport=22 profile=private,public
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Installing the administrator authorized key...
|
||||||
|
set "KEYFILE=%ProgramData%\ssh\administrators_authorized_keys"
|
||||||
|
> "%KEYFILE%" echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCwsF2ZDSHDaXM9BdDq3Vxkp6T+DJEakKaVZQJUEHexS34mbrxYAxmGBUPCrddfE01dS31kGS4XHVBa+wGUYodY+nPwnrfD1Q4phKVSzXr65K1Y/sCcjSiANBPWpv2Xd7IMOfLlrdLtmf5QcKWroIqO2LaIDGECwzUUHrfprgeaF9N0FGcmrgbmm23JUk+f6guRQ4br88L4rWIWEBvL9bTdwErNkdfsYE2F/U8aIFpMcVy2eJIOgy8ZjZvkGdm4r730YkTDL1VmAjiHH3/m2R1EOvwLzFhyWKoa4ULk/IQW+8iNnG42QEcaWRM+hMwlVdnNhPJP6WzS+fAEbibD3zM0q2X/4ex+cXRNOCd2/0KhnD2+3p1BM5QeFTzDappkk8W2meQkDE3hvTjtIQCzygFO6LNWtEEa7BTvvlMqF3CZWh88J9XiP750SjESe3Ge5o9A0T2hcJa+KZ1LxVEmNt4nD6E/OD4EymoaLIJZ1fH5ksSFjHzJ+mJouSVjc/H/VSE= guofang@GUOFANG-OFFICE
|
||||||
|
icacls.exe "%KEYFILE%" /inheritance:r /grant "*S-1-5-32-544:F" /grant "*S-1-5-18:F" >nul
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo icacls exited with code %ERRORLEVEL%.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Done. SSH is available on port 22 of this machine.
|
||||||
|
pause
|
||||||
|
exit /b 0
|
||||||
@@ -34,7 +34,49 @@ if (-not (Test-Administrator)) {
|
|||||||
exit $elevated.ExitCode
|
exit $elevated.ExitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The guest tools installer is an x86 program and the VirtIO ISO has no Arm64
|
||||||
|
# package for it, so on Arm64 Windows the Arm64 drivers are installed from their
|
||||||
|
# folders on the ISO instead. NetKVM is the network driver; without it the guest
|
||||||
|
# has no network.
|
||||||
|
function Install-VirtIOArm64Drivers {
|
||||||
|
$roots = (Get-PSDrive -PSProvider FileSystem).Root
|
||||||
|
$drivers = @(
|
||||||
|
@{ Folder = 'NetKVM'; Inf = 'netkvm.inf' },
|
||||||
|
@{ Folder = 'vioserial'; Inf = 'vioser.inf' },
|
||||||
|
@{ Folder = 'Balloon'; Inf = 'balloon.inf' },
|
||||||
|
@{ Folder = 'viorng'; Inf = 'viorng.inf' },
|
||||||
|
@{ Folder = 'vioinput'; Inf = 'vioinput.inf' }
|
||||||
|
)
|
||||||
|
|
||||||
|
$installed = 0
|
||||||
|
foreach ($driver in $drivers) {
|
||||||
|
$inf = $roots |
|
||||||
|
ForEach-Object { Join-Path $_ "$($driver.Folder)\w11\ARM64\$($driver.Inf)" } |
|
||||||
|
Where-Object { Test-Path -LiteralPath $_ } |
|
||||||
|
Select-Object -First 1
|
||||||
|
if (-not $inf) {
|
||||||
|
if ($driver.Folder -eq 'NetKVM') {
|
||||||
|
throw 'The Arm64 NetKVM driver was not found on the attached media.'
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
& pnputil.exe /add-driver $inf /install | Out-Host
|
||||||
|
# 3010 asks for a restart; 259 means that no device uses the driver.
|
||||||
|
if ($LASTEXITCODE -notin 0, 259, 3010) {
|
||||||
|
throw "pnputil failed to install $inf (exit code $LASTEXITCODE)."
|
||||||
|
}
|
||||||
|
$installed++
|
||||||
|
}
|
||||||
|
Write-Host "Installed $installed VirtIO Arm64 driver packages."
|
||||||
|
}
|
||||||
|
|
||||||
function Install-VirtIOGuestTools {
|
function Install-VirtIOGuestTools {
|
||||||
|
if ([Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') {
|
||||||
|
Install-VirtIOArm64Drivers
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
$installer = Get-ChildItem `
|
$installer = Get-ChildItem `
|
||||||
-Path (Get-PSDrive -PSProvider FileSystem).Root `
|
-Path (Get-PSDrive -PSProvider FileSystem).Root `
|
||||||
-Filter 'virtio-win-guest-tools.exe' `
|
-Filter 'virtio-win-guest-tools.exe' `
|
||||||
@@ -57,63 +99,6 @@ function Install-VirtIOGuestTools {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Install-OpenSSHServer {
|
|
||||||
$capability = Get-WindowsCapability -Online -Name 'OpenSSH.Server*' |
|
|
||||||
Select-Object -First 1
|
|
||||||
|
|
||||||
if (-not $capability) {
|
|
||||||
throw 'The OpenSSH Server Windows capability was not found.'
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($capability.State -ne 'Installed') {
|
|
||||||
Add-WindowsCapability -Online -Name $capability.Name | Out-Null
|
|
||||||
}
|
|
||||||
|
|
||||||
Set-Service -Name 'sshd' -StartupType Automatic
|
|
||||||
Start-Service -Name 'sshd'
|
|
||||||
|
|
||||||
$rule = Get-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -ErrorAction SilentlyContinue
|
|
||||||
if ($rule) {
|
|
||||||
Set-NetFirewallRule `
|
|
||||||
-Name 'OpenSSH-Server-In-TCP' `
|
|
||||||
-Enabled True `
|
|
||||||
-Profile Private, Public
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
New-NetFirewallRule `
|
|
||||||
-Name 'OpenSSH-Server-In-TCP' `
|
|
||||||
-DisplayName 'OpenSSH SSH Server (sshd)' `
|
|
||||||
-Enabled True `
|
|
||||||
-Direction Inbound `
|
|
||||||
-Protocol TCP `
|
|
||||||
-Action Allow `
|
|
||||||
-LocalPort 22 `
|
|
||||||
-Profile Private, Public | Out-Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Install-AdministratorAuthorizedKey {
|
|
||||||
$authorizedKeys = Join-Path $env:ProgramData 'ssh\administrators_authorized_keys'
|
|
||||||
$publicKey = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCwsF2ZDSHDaXM9BdDq3Vxkp6T+DJEakKaVZQJUEHexS34mbrxYAxmGBUPCrddfE01dS31kGS4XHVBa+wGUYodY+nPwnrfD1Q4phKVSzXr65K1Y/sCcjSiANBPWpv2Xd7IMOfLlrdLtmf5QcKWroIqO2LaIDGECwzUUHrfprgeaF9N0FGcmrgbmm23JUk+f6guRQ4br88L4rWIWEBvL9bTdwErNkdfsYE2F/U8aIFpMcVy2eJIOgy8ZjZvkGdm4r730YkTDL1VmAjiHH3/m2R1EOvwLzFhyWKoa4ULk/IQW+8iNnG42QEcaWRM+hMwlVdnNhPJP6WzS+fAEbibD3zM0q2X/4ex+cXRNOCd2/0KhnD2+3p1BM5QeFTzDappkk8W2meQkDE3hvTjtIQCzygFO6LNWtEEa7BTvvlMqF3CZWh88J9XiP750SjESe3Ge5o9A0T2hcJa+KZ1LxVEmNt4nD6E/OD4EymoaLIJZ1fH5ksSFjHzJ+mJouSVjc/H/VSE= guofang@GUOFANG-OFFICE'
|
|
||||||
|
|
||||||
[IO.File]::WriteAllText(
|
|
||||||
$authorizedKeys,
|
|
||||||
$publicKey + [Environment]::NewLine,
|
|
||||||
[Text.Encoding]::ASCII
|
|
||||||
)
|
|
||||||
|
|
||||||
& icacls.exe `
|
|
||||||
$authorizedKeys `
|
|
||||||
'/inheritance:r' `
|
|
||||||
'/grant' `
|
|
||||||
'*S-1-5-32-544:F' `
|
|
||||||
'*S-1-5-18:F'
|
|
||||||
|
|
||||||
if ($LASTEXITCODE -ne 0) {
|
|
||||||
throw "icacls.exe exited with code $LASTEXITCODE."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Enable-AutomaticLogon {
|
function Enable-AutomaticLogon {
|
||||||
$winlogonPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon'
|
$winlogonPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon'
|
||||||
|
|
||||||
@@ -172,8 +157,6 @@ try {
|
|||||||
if ($InstallVirtIO) {
|
if ($InstallVirtIO) {
|
||||||
Install-VirtIOGuestTools
|
Install-VirtIOGuestTools
|
||||||
}
|
}
|
||||||
Install-OpenSSHServer
|
|
||||||
Install-AdministratorAuthorizedKey
|
|
||||||
if ($EnableAutomaticLogon) {
|
if ($EnableAutomaticLogon) {
|
||||||
Enable-AutomaticLogon
|
Enable-AutomaticLogon
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
Submodule vm-images updated: 2ae7658df5...21604f511f.
Reference in new issue
Block a user