diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..567609b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+build/
diff --git a/build-isos.sh b/build-isos.sh
new file mode 100755
index 0000000..04943fd
--- /dev/null
+++ b/build-isos.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+# Builds the answer-file ISOs into build/:
+# virtio-vms.iso latest virtio-win drivers + unattend/vms-WIPE-DISK.xml (as autounattend.xml) + oobe-vms.ps1
+# desktop.iso unattend/desktop-PROMPT-DISK.xml (as autounattend.xml) + oobe-desktop.ps1
+# The virtio-win ISO is only downloaded again when a new release is published.
+# Requires: curl, xorriso
+set -euo pipefail
+cd "$(dirname "$0")"
+
+VIRTIO_LATEST=https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso
+BUILD=build
+STAGE=$BUILD/stage
+# Joliet names so Windows sees oobe-*.ps1 and autounattend.xml unmangled (volume labels max 16 chars)
+JOLIET=(-joliet on -compliance joliet_long_names)
+
+# Root of the ISO as Windows reads it (Joliet, not Rock Ridge)
+show_root() {
+ echo "== $1"
+ xorriso -report_about WARNING -read_fs norock -indev "$1" -lsl / 2>/dev/null | grep -E -i 'autounattend|oobe-|guest-tools' | awk '{print " ", $NF}'
+}
+
+mkdir -p "$BUILD"
+
+# Resolve "latest" to the versioned file; Fedora's redirects drop to plain http, so force https
+VIRTIO_URL=$(curl -fsSIL -o /dev/null -w '%{url_effective}' "$VIRTIO_LATEST" | sed 's#^http://#https://#')
+VIRTIO_ISO=$BUILD/$(basename "$VIRTIO_URL")
+if [[ -f $VIRTIO_ISO ]]; then
+ echo "Using cached $VIRTIO_ISO"
+else
+ echo "Downloading $VIRTIO_URL"
+ curl -fL --retry 3 -o "$VIRTIO_ISO.part" "$VIRTIO_URL"
+ mv "$VIRTIO_ISO.part" "$VIRTIO_ISO"
+fi
+
+# a. VMs: virtio-win + VM answer file + oobe-vms.ps1
+# Files are added to a copy of the original image rather than extracting and repacking it:
+# virtio-win stores identical drivers once, and repacking would nearly double its size.
+rm -f "$BUILD/virtio-vms.iso"
+xorriso -report_about WARNING -indev "$VIRTIO_ISO" -outdev "$BUILD/virtio-vms.iso" "${JOLIET[@]}" -volid VIRTIO_VMS \
+ -map unattend/vms-WIPE-DISK.xml /autounattend.xml \
+ -map oobe-vms.ps1 /oobe-vms.ps1 \
+ -commit
+
+# b. Desktops: desktop answer file + oobe-desktop.ps1, no virtio
+rm -rf "$STAGE" "$BUILD/desktop.iso"
+mkdir -p "$STAGE"
+cp unattend/desktop-PROMPT-DISK.xml "$STAGE/autounattend.xml"
+cp oobe-desktop.ps1 "$STAGE/"
+xorriso -report_about WARNING -outdev "$BUILD/desktop.iso" "${JOLIET[@]}" -volid OOBE_DESKTOP -map "$STAGE" / -commit
+rm -rf "$STAGE"
+show_root "$BUILD/virtio-vms.iso"
+show_root "$BUILD/desktop.iso"
+ls -lh "$BUILD"/*.iso
diff --git a/oobe-desktop.ps1 b/oobe-desktop.ps1
new file mode 100644
index 0000000..9d76589
--- /dev/null
+++ b/oobe-desktop.ps1
@@ -0,0 +1,153 @@
+# OOBE for Windows LTSC desktops and laptops. Runs fully unattended (no prompts).
+# Pulled by autounattend.xml at first logon, or run by hand:
+# irm https://url.isworking.fyi/oobe-desktop | iex
+# Log: C:\ProgramData\OOBE\oobe-desktop.log
+
+# Check if running with elevated privileges
+if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
+ Write-Host "Please run this script as an administrator."
+ Exit 1
+}
+
+$MeshAgentUrl = "https://rmm.iamchrisama.com/meshagents?id=4&meshid=zxl@U2zM95zh9ZNqah@9mUEjCJ3ptGOE6s5cjsGniacVU1fjRXtVKCKlKJN4aJQW&installflags=0"
+
+$ErrorActionPreference = 'Continue'
+# The progress bar makes Invoke-WebRequest extremely slow on Windows PowerShell 5.1
+$ProgressPreference = 'SilentlyContinue'
+# Older LTSC builds don't enable TLS 1.2 by default, which breaks GitHub downloads
+[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
+
+$WorkDir = Join-Path $env:ProgramData 'OOBE'
+New-Item -ItemType Directory -Path $WorkDir -Force | Out-Null
+Start-Transcript -Path (Join-Path $WorkDir 'oobe-desktop.log') -Append | Out-Null
+
+function Save-Download($Uri, $OutFile) {
+ for ($Attempt = 1; $Attempt -le 3; $Attempt++) {
+ try {
+ Invoke-WebRequest -Uri $Uri -OutFile $OutFile -UseBasicParsing
+ return $true
+ } catch {
+ Write-Warning "Download attempt $Attempt of $Uri failed: $_"
+ Start-Sleep -Seconds 10
+ }
+ }
+ return $false
+}
+
+# Wait for internet access, the network may not be up yet during first logon
+function Wait-Network {
+ $MeshHost = ([uri]$MeshAgentUrl).Host
+ $Deadline = (Get-Date).AddMinutes(5)
+ while ((Get-Date) -lt $Deadline) {
+ $Client = New-Object System.Net.Sockets.TcpClient
+ try { if ($Client.ConnectAsync($MeshHost, 443).Wait(5000)) { return } } catch {} finally { $Client.Close() }
+ Write-Output "Waiting for network..."
+ Start-Sleep -Seconds 5
+ }
+ Write-Warning "No network after 5 minutes, continuing anyway."
+}
+
+# Balanced plan: dim the display after 5 minutes, sleep after 30 minutes.
+# Turning the display off stays at the plan default (10 minutes plugged in).
+$Balanced = '381b4222-f694-41f0-9685-ff5bb260df2e'
+powercfg /setactive $Balanced
+
+# "Dim display after" (seconds). Only has a visible effect on screens Windows can
+# control the brightness of (laptops, all-in-ones); external monitors ignore it.
+$DisplaySubgroup = '7516b95f-f776-4464-8c53-06167f40cc99'
+$DimTimeout = '17aaa29b-8b43-4b94-aafe-35f64daaf1ee'
+powercfg /setacvalueindex $Balanced $DisplaySubgroup $DimTimeout 300
+powercfg /setdcvalueindex $Balanced $DisplaySubgroup $DimTimeout 300
+
+powercfg /change standby-timeout-ac 30
+powercfg /change standby-timeout-dc 30
+powercfg /setactive $Balanced
+
+# Treat the network as Private and suppress the "allow this PC to be discoverable" prompt
+Wait-Network
+New-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Network\NewNetworkWindowOff' -Force | Out-Null
+Get-NetConnectionProfile | Where-Object NetworkCategory -ne 'DomainAuthenticated' | Set-NetConnectionProfile -NetworkCategory Private
+
+# Enable ping (ICMP Echo) requests
+if (-not (Get-NetFirewallRule -Name 'OOBE-ICMPv4-In' -ErrorAction SilentlyContinue)) {
+ New-NetFirewallRule -Name 'OOBE-ICMPv4-In' -DisplayName "Allow ICMP Echo Request" -Protocol ICMPv4 -IcmpType 8 -Enabled True | Out-Null
+}
+
+# Allow Remote Desktop (firewall groups are referenced by resource ID so this works on non-English installs)
+Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name "fDenyTSConnections" -Value 0
+Enable-NetFirewallRule -Group '@FirewallAPI.dll,-28752'
+
+# Enable c$ (AutoShareWks must be 1; 0 disables the admin shares)
+reg add "HKLM\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters" /f /v AutoShareWks /t REG_DWORD /d 1
+reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /v "LocalAccountTokenFilterPolicy" /t REG_DWORD /d 1 /f
+Enable-NetFirewallRule -Group '@FirewallAPI.dll,-28502'
+
+# Disable UAC prompt
+Set-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\policies\system' -Name "ConsentPromptBehaviorAdmin" -Value 0
+
+# Dark Mode and no mouse acceleration, for the current user and the default profile (future users)
+function Set-UserPreferences($Hive) {
+ reg add "$Hive\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" /v AppsUseLightTheme /t REG_DWORD /d 0 /f | Out-Null
+ reg add "$Hive\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" /v SystemUsesLightTheme /t REG_DWORD /d 0 /f | Out-Null
+ # "Enhance pointer precision" off
+ reg add "$Hive\Control Panel\Mouse" /v MouseSpeed /t REG_SZ /d 0 /f | Out-Null
+ reg add "$Hive\Control Panel\Mouse" /v MouseThreshold1 /t REG_SZ /d 0 /f | Out-Null
+ reg add "$Hive\Control Panel\Mouse" /v MouseThreshold2 /t REG_SZ /d 0 /f | Out-Null
+}
+Set-UserPreferences 'HKCU'
+$DefaultProfile = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList').Default
+reg load 'HKU\OOBEDefault' "$DefaultProfile\NTUSER.DAT" | Out-Null
+if ($LASTEXITCODE -eq 0) {
+ Set-UserPreferences 'HKU\OOBEDefault'
+ [gc]::Collect()
+ reg unload 'HKU\OOBEDefault' | Out-Null
+}
+
+# Install MeshCentral agent silently as a service
+if (Get-Service -Name 'Mesh Agent' -ErrorAction SilentlyContinue) {
+ Write-Output "Mesh Agent is already installed."
+} else {
+ $MeshInstaller = Join-Path $WorkDir 'meshagent.exe'
+ if (Save-Download $MeshAgentUrl $MeshInstaller) {
+ # -fullinstall installs and starts the service without showing the install dialog
+ Start-Process -FilePath $MeshInstaller -ArgumentList '-fullinstall' -WindowStyle Hidden -Wait
+ }
+ if (-not (Get-Service -Name 'Mesh Agent' -ErrorAction SilentlyContinue)) {
+ Write-Warning "Mesh Agent service was not found after install."
+ }
+}
+
+# Install OpenSSH
+foreach ($Capability in 'OpenSSH.Client~~~~0.0.1.0', 'OpenSSH.Server~~~~0.0.1.0') {
+ if ((Get-WindowsCapability -Online -Name $Capability).State -ne 'Installed') {
+ Add-WindowsCapability -Online -Name $Capability | Out-Null
+ }
+}
+
+Set-Service -Name sshd -StartupType 'Automatic'
+Start-Service sshd
+
+# Use PowerShell instead of cmd.exe for SSH sessions
+if (Test-Path 'HKLM:\SOFTWARE\OpenSSH') {
+ New-ItemProperty -Path 'HKLM:\SOFTWARE\OpenSSH' -Name DefaultShell -Value "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force | Out-Null
+}
+
+if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) {
+ Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..."
+ New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
+} else {
+ Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists."
+}
+
+# Install Winget (LTSC ships without the Store / App Installer)
+# Run in a child process: the installer script calls exit, which would end this script too
+$WingetInstaller = Join-Path $WorkDir 'winget-install.ps1'
+if (Save-Download 'https://github.com/asheroto/winget-install/releases/latest/download/winget-install.ps1' $WingetInstaller) {
+ & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $WingetInstaller -Force
+}
+
+# Restart to finish OpenSSH and driver installation.
+# Delayed so the script can exit cleanly and the log is flushed before Windows goes down.
+Write-Output "OOBE complete, restarting in 10 seconds."
+Stop-Transcript | Out-Null
+shutdown.exe /r /t 10 /d p:4:1 /c "OOBE complete, restarting to finish installation."
diff --git a/oobe-rm-ai.ps1 b/oobe-rm-ai.ps1
deleted file mode 100644
index 6123dc2..0000000
--- a/oobe-rm-ai.ps1
+++ /dev/null
@@ -1,63 +0,0 @@
-# Check if running with elevated privileges
-if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
- Write-Host "Please run this script as an administrator."
- Exit
-}
-
-# Enable ping (ICMP Echo) requests
-New-NetFirewallRule -DisplayName "Allow ICMP Echo Request" -Protocol ICMPv4 -IcmpType 8 -Enabled True
-
-# Turn on Dark Mode
-New-ItemProperty -Path HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize -Name AppsUseLightTheme -Value 0 -PropertyType DWORD -Force
-
-# Disable Mouse Acceleration
-Set-ItemProperty -Path "HKCU:\Control Panel\Mouse" -Name MouseSensitivity -Value 0
-
-# Allow Remote Desktop
-Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name "fDenyTSConnections" -Value 0
-Enable-NetFirewallRule -DisplayGroup "Remote Desktop"
-
-# Enable c$
-reg add "HKLM\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters" /f /v AutoShareWks /t REG_DWORD /d 0
-reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /v "LocalAccountTokenFilterPolicy" /t REG_DWORD /d 1 /f
-
-# Disable UAC prompt
-Set-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\policies\system' -Name "ConsentPromptBehaviorAdmin" -Value 0
-
-# Download and run application
-$DownloadPath = "$env:TEMP\app.exe"
-Invoke-WebRequest -Uri "https://rmm.iamchrisama.com/meshagents?id=4&meshid=zxl@U2zM95zh9ZNqah@9mUEjCJ3ptGOE6s5cjsGniacVU1fjRXtVKCKlKJN4aJQW&installflags=0" -OutFile $DownloadPath
-Start-Process -FilePath $DownloadPath -Wait
-
-# Remove Winows AI
-& ([scriptblock]::Create((irm "https://raw.githubusercontent.com/zoicware/RemoveWindowsAI/main/RemoveWindowsAi.ps1"))) -nonInteractive -AllOptions
-
-# Run commands in new PowerShell instance
-# Start-Process powershell.exe -ArgumentList "-NoProfile -Command {irm https://massgrave.dev/get | iex}"
-# Start-Process powershell.exe -ArgumentList "-NoProfile -Command {irm https://christitus.com/win | iex}"
-
-# Disable sleep and enable high performance mode, enable hibernation, and display black after 30 minutes
-powercfg -change -standby-timeout-ac 0
-powercfg -setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
-powercfg /hibernate on
-powercfg -change -monitor-timeout-ac 30
-
-# Install Winget
-#Add-AppxPackage -RegisterByFamilyName -MainPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe
-irm https://github.com/asheroto/winget-install/releases/latest/download/winget-install.ps1 | iex
-
-# Install OpenSSH
-Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
-Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
-Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
-
-Start-Service sshd
-
-Set-Service -Name sshd -StartupType 'Automatic'
-
-if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) {
- Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..."
- New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
-} else {
- Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists."
-}
diff --git a/oobe-ltsc.ps1 b/oobe-vms.ps1
similarity index 97%
rename from oobe-ltsc.ps1
rename to oobe-vms.ps1
index cf4ce1d..7d2ca66 100644
--- a/oobe-ltsc.ps1
+++ b/oobe-vms.ps1
@@ -1,6 +1,7 @@
-# OOBE for Windows LTSC virtual machines. Runs fully unattended (no prompts), e.g. from autounattend.xml:
-# powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Windows\Setup\Scripts\oobe-ltsc.ps1
-# Log: C:\ProgramData\OOBE\oobe-ltsc.log
+# OOBE for Windows LTSC virtual machines (Unraid / KVM with VirtIO). Runs fully unattended (no prompts).
+# Pulled by autounattend.xml at first logon, or run by hand:
+# irm https://url.isworking.fyi/oobe-vms | iex
+# Log: C:\ProgramData\OOBE\oobe-vms.log
# Check if running with elevated privileges
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
@@ -18,7 +19,7 @@ $ProgressPreference = 'SilentlyContinue'
$WorkDir = Join-Path $env:ProgramData 'OOBE'
New-Item -ItemType Directory -Path $WorkDir -Force | Out-Null
-Start-Transcript -Path (Join-Path $WorkDir 'oobe-ltsc.log') -Append | Out-Null
+Start-Transcript -Path (Join-Path $WorkDir 'oobe-vms.log') -Append | Out-Null
function Save-Download($Uri, $OutFile) {
for ($Attempt = 1; $Attempt -le 3; $Attempt++) {
diff --git a/unattend/desktop-PROMPT-DISK.xml b/unattend/desktop-PROMPT-DISK.xml
new file mode 100644
index 0000000..5b38494
--- /dev/null
+++ b/unattend/desktop-PROMPT-DISK.xml
@@ -0,0 +1,311 @@
+
+
+
+
+
+
+
+
+
+ en-US
+
+ 0409:00000409
+ en-US
+ en-US
+ en-US
+
+
+
+
+
+
+ D:\viostor\w10\amd64
+
+
+ E:\viostor\w10\amd64
+
+
+ F:\viostor\w10\amd64
+
+
+
+ D:\vioscsi\w10\amd64
+
+
+ E:\vioscsi\w10\amd64
+
+
+ F:\vioscsi\w10\amd64
+
+
+
+ D:\NetKVM\w10\amd64
+
+
+ E:\NetKVM\w10\amd64
+
+
+ F:\NetKVM\w10\amd64
+
+
+
+
+
+
+
+
+
+
+
+
+ /IMAGE/INDEX
+ 1
+
+
+ OnError
+
+
+
+
+
+
+ M7XTQ-FN8P6-TTKYV-9D4CC-J462D
+ OnError
+
+ true
+ IT
+ Contoso
+
+
+
+
+
+
+
+
+
+
+ *
+
+ Pacific Standard Time
+ IT
+ Contoso
+
+
+
+ true
+
+
+
+
+ false
+
+
+
+ 1
+ 2
+
+
+
+
+
+
+
+
+ 0409:00000409
+ en-US
+ en-US
+ en-US
+
+
+
+
+
+ true
+ true
+ true
+ true
+ true
+ Work
+ 3
+
+
+
+
+
+ mdwelcome
+ true
+
+
+
+
+ labadmin
+ Lab Admin
+ Local administrator for automated builds
+ Administrators
+
+ mdwelcome
+ true
+
+
+
+
+
+
+
+ true
+ labadmin
+ 1
+
+ mdwelcome
+ true
+
+
+
+ false
+
+
+
+
+
+ 1
+ Show file extensions
+ reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v HideFileExt /t REG_DWORD /d 0 /f
+ false
+
+
+
+ 2
+ Allow signed PowerShell scripts
+ powershell -NoProfile -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force"
+ false
+
+
+
+
+ 3
+ Install VirtIO guest tools
+ powershell -NoProfile -ExecutionPolicy Bypass -Command "Get-Volume | Where-Object DriveLetter | ForEach-Object { $exe = $_.DriveLetter + ':\virtio-win-guest-tools.exe'; if (Test-Path $exe) { Start-Process $exe -ArgumentList '/install','/quiet','/norestart' -Wait } }"
+ false
+
+
+
+
+ 4
+ Run oobe-desktop.ps1 (url.isworking.fyi, else ISO copy)
+ powershell -NoProfile -ExecutionPolicy Bypass -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $s = $null; for ($i = 1; $i -le 10; $i++) { try { $s = Invoke-RestMethod 'https://url.isworking.fyi/oobe-desktop'; break } catch { Start-Sleep -Seconds 15 } }; if (-not $s) { $f = Get-PSDrive -PSProvider FileSystem | ForEach-Object { Join-Path $_.Root 'oobe-desktop.ps1' } | Where-Object { Test-Path $_ } | Select-Object -First 1; if ($f) { $s = Get-Content -Raw $f } }; if ($s) { Invoke-Expression $s } else { Write-Warning 'oobe-desktop.ps1 not found online or on any drive'; Start-Sleep -Seconds 60 }"
+ false
+
+
+
+
+
+
+
+
diff --git a/unattend/vms-WIPE-DISK.xml b/unattend/vms-WIPE-DISK.xml
index fb2522f..0bf4b55 100644
--- a/unattend/vms-WIPE-DISK.xml
+++ b/unattend/vms-WIPE-DISK.xml
@@ -5,12 +5,12 @@
Target: Unraid / KVM virtual machine, UEFI firmware, GPT disk
Storage: VirtIO (or VirtIO-SCSI) vdisk - drivers injected into WinPE
Behavior: Wipes Disk 0, creates ESP/MSR/Windows, installs, autologons,
- then runs oobe-ltsc.ps1 (VirtIO guest tools, MeshCentral, settings).
+ installs the VirtIO guest tools, then downloads and runs
+ oobe-vms.ps1 from https://url.isworking.fyi/oobe-vms.
- PLACE AT: the ROOT of the merged VirtIO ISO, renamed to autounattend.xml,
- alongside virtio-win-guest-tools.exe AND oobe-ltsc.ps1. The ISO
- needs Joliet names so oobe-ltsc.ps1 isn't mangled to 8.3.
- Attach that ISO in the Unraid VM's
+ BUILD: ./build-isos.sh produces build/virtio-vms.iso with this file as
+ autounattend.xml plus oobe-vms.ps1 (offline fallback) at the
+ root of the latest virtio-win ISO. Attach that ISO in the Unraid VM's
"VirtIO Drivers ISO" slot; leave "OS Install ISO" on the LTSC image.
>>> DESTRUCTIVE: WillWipeDisk erases Disk 0 with no prompt. <<<
@@ -325,16 +325,28 @@
false
-
+
3
- Run oobe-ltsc.ps1 provisioning script
- powershell -NoProfile -ExecutionPolicy Bypass -Command "$s = Get-PSDrive -PSProvider FileSystem | ForEach-Object { Join-Path $_.Root 'oobe-ltsc.ps1' } | Where-Object { Test-Path $_ } | Select-Object -First 1; if ($s) { & $s } else { Write-Warning 'oobe-ltsc.ps1 not found on any drive'; Start-Sleep -Seconds 60 }"
+ Install VirtIO guest tools
+ powershell -NoProfile -ExecutionPolicy Bypass -Command "Get-Volume | Where-Object DriveLetter | ForEach-Object { $exe = $_.DriveLetter + ':\virtio-win-guest-tools.exe'; if (Test-Path $exe) { Start-Process $exe -ArgumentList '/install','/quiet','/norestart' -Wait } }"
+ false
+
+
+
+
+ 4
+ Run oobe-vms.ps1 (url.isworking.fyi, else ISO copy)
+ powershell -NoProfile -ExecutionPolicy Bypass -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $s = $null; for ($i = 1; $i -le 10; $i++) { try { $s = Invoke-RestMethod 'https://url.isworking.fyi/oobe-vms'; break } catch { Start-Sleep -Seconds 15 } }; if (-not $s) { $f = Get-PSDrive -PSProvider FileSystem | ForEach-Object { Join-Path $_.Root 'oobe-vms.ps1' } | Where-Object { Test-Path $_ } | Select-Object -First 1; if ($f) { $s = Get-Content -Raw $f } }; if ($s) { Invoke-Expression $s } else { Write-Warning 'oobe-vms.ps1 not found online or on any drive'; Start-Sleep -Seconds 60 }"
false