Skip to content

Commit 61b4f04

Browse files
committed
better system stability waiting, added more blocking for windows defender and downloaded content, plus some additional qemu performance changes
1 parent c768500 commit 61b4f04

File tree

4 files changed

+51
-32
lines changed

4 files changed

+51
-32
lines changed

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,34 @@
11
# osrun
22

3-
A docker container to run a command in Windows 11 (via QEMU). On first run it will generate a Windows 11 ISO and run a VM to install it and create a system snapshot. On subsequent runs it will use the existing cached VM image.
3+
A docker container to run Windows commands and processes. On first run it will generate a Windows 11 ISO and run a VM to install it and create a system snapshot. On subsequent runs it will use the existing cached VM image.
44

55
## Usage
66

77
```bash
88
docker run -it --rm --device=/dev/kvm -v $(pwd)/cache:/cache ghcr.io/lg/osrun 'dir c:\windows\system32'
99
```
1010

11+
```text
12+
Usage: osrun [-v] [-h] <command>
13+
Short-lived containerized Windows instances
14+
15+
-h --help: Display this help
16+
-v --verbose: Verbose mode
17+
18+
Install
19+
-k --keep: Keep the installation cached artifacts after successful provisioning
20+
21+
Run
22+
-p --pause: Do not close the VM after the command finishes
23+
```
24+
1125
If you don't have kvm on your machine, you can skip the parameter, but things will be a lot slower. This mode is currently unreliable and may freeze during Windows 11 installation.
1226

1327
## Details
1428

15-
This container uses [QEMU](https://www.qemu.org/) to run a Windows 11 VM. Windows 11 is built with the file list from [UUP dump](https://uupdump.net/) and files are downloaded directly from Microsoft's Windows Update servers. The UUP dump script generates a Windows ISO which we then inject [virtio drivers](https://docs.fedoraproject.org/en-US/quick-docs/creating-windows-virtual-machines-using-virtio-drivers/index.html) into along with an `autounattend.xml` script and a variety of Powershell scripts to automate the installation. To keep the VM small and fast we remove a lot of the default Windows components and services including Windows Defender, Windows Update, most default apps, and also disable things like paging, sleep and hibernation, plus the hard drive is compressed and trimmed to be <10GB. This image and VM state is then snapshotted and saved to a cache directory so that subsequent runs can use the cached VM state to startup quickly.
29+
This container uses [QEMU](https://www.qemu.org/) to run a Windows 11 VM. Windows 11 is built with the file list from [UUP dump](https://uupdump.net/) and files are downloaded directly from Microsoft's Windows Update servers. The UUP dump script generates a Windows ISO which we then inject an `autounattend.xml` script to start the installation automation. To keep the resultant VM small and fast we remove a lot of the default Windows components and services including Windows Defender, Windows Update, most default apps, and also disable things like paging, sleep and hibernation, plus the hard drive is compressed and trimmed to be <10GB. This image and VM state is then snapshotted and saved to a cache directory so that subsequent runs can use the cached VM state to startup quickly. On a reasonably fast machine the installation process takes about 20 minutes end-to-end and runs take about 3-4 seconds for simple commands like `dir`.
1630

17-
Communication between the VM and the host is done via the QEMU Agent and a QEMU-started Samba server (available on the host in `/tmp/qemu-status` or in the container in `\\10.0.2.4\qemu`). During installation and execution, multiple debugging services are started (you'll need to forward these ports using Docker):
31+
Communication between the VM and the host is done via the QEMU Agent and a QEMU-started Samba server (available in the host container in `/tmp/qemu-status` or in the VM in `\\10.0.2.4\qemu`). During installation and execution, multiple debugging services are started (you'll need to forward these ports using Docker if you want to use them):
1832
- a QEMU-run VNC server is available on port `5950` (not compatible with Apple Screen Sharing),
1933
- the QEMU Monitor is available on port `55556` (supported commands are [here](https://qemu-project.gitlab.io/qemu/system/monitor.html)), and
2034
- the QEMU Agent is available on port `44444` (protocol is [here](https://qemu.readthedocs.io/en/latest/interop/qemu-ga-ref.html)).

run.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ set -o errexit -o noclobber -o nounset -o pipefail
66
usage() {
77
echo -e \
88
"Usage: osrun [-v] [-h] <command>\n" \
9-
"Installs Windows 11 and runs commands in a VM.\n" \
9+
"Short-lived containerized Windows instances\n" \
1010
"\n" \
1111
" -h --help: Display this help\n" \
1212
" -v --verbose: Verbose mode\n" \
@@ -47,7 +47,7 @@ touch /tmp/qemu-status/status.txt
4747
tail -f /tmp/qemu-status/status.txt &
4848

4949
start_qemu() {
50-
KVM_PARAM=",accel=kvm"; CPU_PARAM="-cpu host"
50+
KVM_PARAM=",accel=kvm"; CPU_PARAM="-cpu host,hv_stimer,hv_time,hv_synic,hv_vpindex"
5151
if [ ! -e /dev/kvm ]; then
5252
echo -e "\033[33;49mKVM acceleration not found. Ensure you're using --device=/dev/kvm with docker. Virtualization will be very slow.\033[0m" > /dev/stderr
5353
KVM_PARAM=""; CPU_PARAM="-accel tcg"
@@ -140,7 +140,7 @@ if [ ! -e /cache/win11.qcow2 ]; then
140140
if [ ! -e "$STEP_ARTIFACT" ]; then
141141
rm -f /cache/win11-step$STEP-*.qcow2 # remove any previous artifacts for this step
142142
if [ "$STEP" = "0" ]; then
143-
qemu-img create -f qcow2 -o compression_type=zstd -q "$STEP_ARTIFACT" 15G
143+
qemu-img create -f qcow2 -o compression_type=zstd,extended_l2=on,cluster_size=128k -q "$STEP_ARTIFACT" 15G
144144
else
145145
cp "$PREV_STEP_ARTIFACT" "$STEP_ARTIFACT"
146146
fi

win11-init/boot-0.ps1

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ $executables = @(
5252
"c:\windows\system32\smartscreen.exe",
5353
"c:\windows\system32\sppsvc.exe",
5454
"c:\windows\system32\ctfmon.exe",
55-
"c:\windows\system32\Sgrm\SgrmBroker.exe"
55+
"c:\windows\system32\Sgrm\SgrmBroker.exe",
56+
"c:\Program Files\Windows Defender\MpCmdRun.exe"
5657
)
5758
foreach ($executable in $executables) {
5859
$acl = Get-Acl $executable ; $acl.SetAccessRuleProtection($true, $true) ; Set-Acl $executable $acl
@@ -224,7 +225,18 @@ Set-RegItem -PathWithName "HKU:\DefaultHive\Software\Microsoft\Windows\CurrentVe
224225
Set-RegItem -PathWithName "HKU:\DefaultHive\Software\Microsoft\Windows\CurrentVersion\AppHost\PreventOverride" -Value 0
225226

226227
Write-Output "Disabling Content Delivery Manager"
227-
Set-RegItem -PathWithName "HKU:\DefaultHive\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager\SilentInstalledAppsEnabled" -Value 0
228+
$ContentDeliveryKeys = @("ContentDeliveryAllowed", "FeatureManagementEnabled", "OemPreInstalledAppsEnabled",
229+
"PreInstalledAppsEnabled", "PreInstalledAppsEverEnabled", "SilentInstalledAppsEnabled", "SoftLandingEnabled",
230+
"SubscribedContentEnabled", "SystemPaneSuggestionsEnabled", "SubscribedContent-310093Enabled",
231+
"SubscribedContent-338388Enabled", "SubscribedContent-338389Enabled", "SubscribedContent-338393Enabled",
232+
"SubscribedContent-353694Enabled", "SubscribedContent-353696Enabled", "SubscribedContentEnabled")
233+
foreach ($key in $ContentDeliveryKeys) {
234+
Set-RegItem -PathWithName "HKU:\DefaultHive\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager\$key" -Value 0
235+
}
236+
Set-RegItem -PathWithName "HKLM:\Software\Policies\Microsoft\PushToInstall\DisablePushToInstall" -Value 1
237+
Set-RegItem -PathWithName "HKLM:\Software\Policies\Microsoft\MRT\DontOfferThroughWUAU" -Value 1
238+
Remove-Item "HKU:\DefaultHive\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager\Subscriptions" -Force -ErrorAction SilentlyContinue
239+
Remove-Item "HKU:\DefaultHive\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager\SuggestedApps" -Force -ErrorAction SilentlyContinue
228240

229241
Write-Output "Enabling Explorer performance settings"
230242
Set-RegItem -PathWithName "HKLM:\SYSTEM\CurrentControlSet\Control\PriorityControl\Win32PrioritySeparation" -Value 38

win11-init/boot-1.ps1

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,7 @@ $ErrorActionPreference = "Inquire"
66

77
Write-Output "Installing QEMU agent (virtio already installed)"
88
& "C:\virtio-win-guest-tools.exe" /install /quiet | Out-Null
9-
10-
Write-Output "Waiting for all packages to be installed"
11-
Do {
12-
Sleep 10
13-
$stagedPackages = Get-AppxPackage -AllUsers | Where-Object { $_.PackageUserInformation.InstallState -ne 'Installed' }
14-
Write-Output "[$(Get-Date)] Currently installing packages: $($stagedPackages.PackageFullName -join ', ')"
15-
} While ($stagedPackages)
16-
17-
Write-Output "Waiting for all scheduled tasks to finish"
18-
Do {
19-
Sleep 10
20-
$runningTasks = Get-ScheduledTask | Where-Object State -NE "Disabled" | Where-Object State -NE "Ready"
21-
Write-Output "[$(Get-Date)] Currently running tasks: $($runningTasks.TaskName -join ', ')"
22-
} While ($runningTasks)
23-
24-
#####
9+
Remove-Item -Path "C:\virtio-win-guest-tools.exe" -Force | Out-Null
2510

2611
Write-Output "Disabling all scheduled tasks with a scheduled time or idle trigger"
2712
Get-ScheduledTask | Where-Object State -NE "Disabled" |
@@ -33,11 +18,12 @@ Get-ScheduledTask | Where-Object State -NE "Disabled" |
3318
ForEach-Object { Disable-ScheduledTask -TaskName $_.TaskName -TaskPath $_.TaskPath -ErrorAction SilentlyContinue } |
3419
Out-Null
3520

36-
37-
#####
38-
39-
40-
21+
Write-Output "Waiting for installation processes to end"
22+
$BadProcesses = @("msiexec", "TiWorker", "backgroundTaskHost", "TrustedInstaller")
23+
While ($StillRunning = ($BadProcesses | ForEach-Object { Get-Process -Name $_ -ErrorAction SilentlyContinue }).Name) {
24+
Write-Output "Still running: $($StillRunning -join ', ')"
25+
Sleep 30
26+
}
4127

4228
#####
4329

@@ -52,12 +38,19 @@ Remove-Item -Path "C:\Users\Administrator\AppData\Local\Microsoft\Windows\INetCa
5238
Write-Output "Removing unused windows components"
5339
& Dism.exe /online /Cleanup-Image /StartComponentCleanup /ResetBase | Out-Null
5440

55-
Write-Output "Defragmenting and trimming"
56-
Optimize-Volume -DriveLetter C -Defrag -ReTrim -SlabConsolidate | Out-Null
57-
5841
Write-Output "Compressing drive"
5942
& compact.exe /compactos:always *>&1 | Out-Null
6043

44+
Write-Output "Defragmenting and trimming"
45+
Optimize-Volume -DriveLetter C -Defrag
46+
Optimize-Volume -DriveLetter C -ReTrim
47+
48+
Write-Output "Final wait for installation processes to end"
49+
While ($StillRunning = ($BadProcesses | ForEach-Object { Get-Process -Name $_ -ErrorAction SilentlyContinue }).Name) {
50+
Write-Output "Still running: $($StillRunning -join ', ')"
51+
Sleep 30
52+
}
53+
6154
Write-Output "Successfully provisioned image."
6255

6356
#####

0 commit comments

Comments
 (0)