WSMan TrustedHosts is a Windows WinRM client concept — does not exist
on Linux. Guard the configure+restore blocks with $isLinuxHost so the
Prepare scripts run without elevation errors from a Linux host.
-SkipCACheck/-SkipCNCheck in sessionOptions is sufficient on Linux.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Parameter not available in PS 7 on Linux. -SkipCACheck -SkipCNCheck
sufficient for self-signed lab certs; revocation check is irrelevant
for self-signed certs regardless.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Test-NetConnection is Windows-only. Replace with cross-platform TcpClient
async-connect helper (same pattern as Measure-CIBenchmark.ps1) so the
Prepare scripts run on the Linux host under PowerShell.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Windows (Prepare-WinBuild2025/2022): read ci-static-ip.ps1 from
guest-setup/windows/ on the host, push content over WinRM, register the
CI-StaticIp scheduled task (AtStartup/SYSTEM). Adds StaticIpTask and
StaticIpScript post-setup assertions.
Linux (Install-CIToolchain-Linux2404.sh): embed ci-report-ip.sh and
ci-report-ip.service content inline via heredoc tee, replacing the broken
cp-from-relative-path approach (the script runs inside the VM where the
host-side guest-setup/ directory does not exist).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
template/guest-setup/linux/ci-report-ip.sh
Updated version: checks guestinfo.ip-assignment first (static path),
falls back to DHCP detection if absent. Applies static IP before
network-online.target so SSH starts on the correct address immediately.
template/guest-setup/linux/ci-report-ip.service
Drops 'network.target' from After= — runs before network is up so the
static IP is configured before SSH/other services start.
template/guest-setup/windows/ci-static-ip.ps1
Reads guestinfo.ip-assignment via vmware-rpctool at system startup (SYSTEM
account Task Scheduler task). Disables DHCP, applies static IP+gateway,
reports back via guestinfo.ci-ip. No-op when ip-assignment is absent.
template/Install-CIToolchain-Linux2404.sh
Step 7b now copies scripts from guest-setup/linux/ instead of embedding
the old DHCP-only inline script.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Parallel MSBuild fan-out (e.g. ns7zip x86/x64/x86-ansi) over pypsrp
Linux→Win fails with MSBuild MSB6003 / Win32 1816 'Not enough quota'
because two default guest limits are too tight for concurrent native
processes via WinRM:
- Plugin Microsoft.PowerShell MaxMemoryPerShellMB = 150 MB
(pypsrp uses the plugin endpoint, not the Shell endpoint that
Deploy was previously bumping)
- Non-interactive desktop heap SharedSection 3rd field = 768 KB
(Session 0 csrss; CreateProcess fails when 3+ cl.exe spawn)
Pre-migration Win→Win went through Invoke-Command on PSSession with
quotas inherited from the local process, so the limits never bit.
Changes:
- Deploy-WinBuild2025.ps1 / Deploy-WinBuild2022.ps1: also set the
plugin-level MaxMemoryPerShellMB=2048, bump MaxProcessesPerShell
25→100, patch SharedSection 3rd field 768→4096 (reboot needed for
csrss to pick up, applied by post-install shutdown).
- Install-CIToolchain-WinBuild2025/2022.ps1: add Assert-Step for
plugin quota, MaxProcessesPerShell≥100, SharedSection≥4096; fail
hard if any are under threshold.
- docs/WINDOWS-TEMPLATE-SETUP.md: new "WinRM quotas e desktop heap"
section explaining the diagnosis + one-shot patch for legacy
templates; updated Step 3 validation row + troubleshooting entry.
- AGENTS.md: error #13 with symptom, root cause, and pointer to docs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Get-CIJobSummary.ps1: already present with full implementation (marked done)
- Get-BuildArtifacts.ps1: add -JobId/-Commit params; Write-ArtifactManifest writes
manifest.json (name, size, sha256, commit, jobId) after both Linux and Windows
artifact collection branches
- Invoke-CIJob.ps1: add -GuestCPU/-GuestMemoryMB params; insert post-clone VMX
override block (numvcpus/memsize rewrite) before vmrun start; pass -JobId/-Commit
to Get-BuildArtifacts calls
- Watch-RunnerHealth.ps1: add -GiteaUrl/-GiteaCredentialTarget params; optional
GET /api/v1/admin/runners check in Running branch warns if 0 online runners
- Install-CIToolchain-WinBuild2025.ps1: fill SHA256 hashes for Python 3.13.3,
7-Zip 26.01, Node.js 22.14.0, dotnet-install.ps1
- Measure-CIBenchmark.ps1: add deltaKB field (linked-clone disk footprint in KB)
measured post-clone; added to result object and summary Format-Table
Each Ubuntu clone derived from the same snapshot shared an identical
machine-id, causing systemd-networkd to use the same DHCP client-id
and receive the same NAT IP triggering IP collision failures.
Step 7b truncates /etc/machine-id and removes /var/lib/dbus/machine-id
before the snapshot is taken. On first boot each clone generates a
fresh machine-id from /dev/urandom -> unique DHCP client-id -> unique IP.
Setup-WinBuild2025.ps1:
- New [switch] \ param (after \)
- Step 12 block wrapped with if (\) { skip-message } else { ... }
- Final gate Tier-2 Assert-Step wrapped with if (-not \)
Prepare-WinBuild2025.ps1:
- New [switch] \ param forwarded to Setup via setupArgs
Validate-SetupState.ps1:
- New [switch] \ param
- \ passed into both remote scriptblocks via -ArgumentList
- Tier-2 Chk calls guarded with if (-not \) in both blocks
Setup-WinBuild2025.ps1: default SevenZipVersion '24.07' → '26.01'
TODO.md: Tier-1 table + bullet list updated to current versions
TEST-PLAN: expected version strings and checklist updated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: Assert-Step 'Final' 'dotnet/python/msbuild' block contains a
registry PATH refresh that overwrites $env:PATH, discarding the temporary
session injection added in §6.6. Next assertion (7z command available) then fails.
Fix: use SetEnvironmentVariable('PATH', ..., 'Machine') to permanently register
C:\Program Files\7-Zip in the system PATH — same pattern used for dotnet and MSBuild.
Follow-up registry refresh ensures $env:PATH is also current.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two root causes:
1. Git skip check used C:\BuildTools\Git but Git installs to
C:\Program Files\Git (default). Changed $gitDir to correct path.
2. 7-Zip MSI does not register in system PATH. Registry refresh
(GetEnvironmentVariable Machine+User) was picking up empty result.
Fixed: inject sevenZipDir directly into $env:PATH if not present.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PATH refresh was inside the 'else' block (only during fresh install).
If tools already exist from previous run, PATH not refreshed → validation fails.
Move PATH refresh outside if/else for both Git and 7-Zip:
- Already installed: skip download+install, but refresh PATH anyway
- Fresh install: download+install, then refresh PATH
Ensures validations can always resolve git/7z commands, even on retry runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7-Zip MSI installer adds to system PATH but PowerShell session doesn't
see it until PATH is refreshed. Refresh via:
$env:PATH = [System.Environment]::GetEnvironmentVariable('PATH', 'Machine') + ';' +
[System.Environment]::GetEnvironmentVariable('PATH', 'User')
Same pattern already used for Git installer. Fixes validation error:
'7z command resolvable' now passes after installation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GitHub release tag: v2.54.0.windows.1
Filename in release: Git-2.54.0-64-bit.exe (no .windows.1)
Extract base version for filename via regex:
$gitVersionBase = $GitVersion -replace '\.windows\.\d+$', ''
URL now correctly formed as:
.../download/v2.54.0.windows.1/Git-2.54.0-64-bit.exe
Reverted GitVersion back to '2.54.0.windows.1' (needed for tag).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Version 2.47.0.windows.1 no longer available on GitHub (network errors).
Updated to latest stable 2.54.0.windows.1 with SHA256 hash pinning (§1.3).
Hash: 2b96e7854f0520f0f6b709c21041d9801b1be44d5e1a0d9fa621b2fbc40f1983
Source: https://github.com/git-for-windows/git/releases
This fixes download failures in Setup-WinBuild2025 Step 11 (Tier-1 Toolchain).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
§6.6 Tier-1 Toolchain (Git for Windows, 7-Zip) now included in final
state validation. Checks:
- 'Git for Windows (git.exe in PATH)'
- '7-Zip (7z.exe in PATH)'
Added to both initial validation pass and re-validation pass (post-remediation).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement §6.6 minimal viable product: install Git for Windows and 7-Zip
to the template VM. Critical prerequisites for §3.3 (In-VM Git clone).
Step 11 additions:
- Git for Windows (latest LTS configurable) — silent installer, adds to PATH
- 7-Zip (latest stable configurable) — MSI installer to Program Files
- SHA256 hash pinning for both tools (currently unpinned, warn at runtime)
- Assert-Step validation for git/7z command availability
- Final pre-snapshot gate checks for both tools + cleanup of installers
Parameters added:
- -GitVersion (default: 2.47.0.windows.1)
- -SevenZipVersion (default: 24.07)
Rationale:
- Enables §3.3 in-VM Git clone (git clone directly in VM instead of host-zip-transfer)
- Supports cross-platform builds and multi-tool workflows
- Fallback from §3.2 7-Zip compression finally available in template
- Positions for future expansion of Tier-1 tools (NSIS, CMake, Node.js, WiX, etc.)
Updated documentation:
- Setup-WinBuild2025.ps1 docstring: Step 11 added to list + step ordering rationale
- Removed NOTE about Git not being installed
- Final validation now checks: 9 assertions (was 7)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Activates Windows against kms8.msguides.com before Windows Update runs
so WU sees correct license state. Uses cscript //NoLogo to route slmgr
output to stdout (dialogs hang in WinRM sessions). Best-effort: activation
failure emits a warning but does not abort Setup — CI builds function
within the grace period.
Placed between Step 3 (WinRM/network confirmed) and Step 4 (user creation).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
$sdFiles is $null when SoftwareDistribution\Download is empty. StrictMode
throws on $null.Count. @($sdFiles).Count safely returns 0 for null.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PS 5.1 treats GenericMeasureInfo.Sum as absent (not null) when the input pipe
is empty. StrictMode throws 'property Sum cannot be found'. Replace Measure-Object
with an explicit foreach loop for SoftwareDistribution size reporting.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two persistent Validate-SetupState failures despite §7.4 fixes:
1. wuauserv — Setup's Assert-Steps pass at exit but WaaSMedicSvc (tamper-protected,
cannot be disabled) polls SCM ~30-60s and resets StartType to Manual.
Fix: write Start=4 directly to registry key (SCM API alone is overrideable);
deny WaaSMedicSvc write access to wuauserv registry key via ACL (best-effort,
non-fatal if WinRM session lacks permission); re-enforce Start=4 after DISM
in Cleanup; add Pre-Final re-affirmation block before Final gate.
2. AutoAdminLogon — Step 5c re-affirms it mid-script, but Steps 7-10 take hours
and no Final gate check catches a late reset. Fix: add Pre-Final re-affirmation
block (same as wuauserv) + add Assert-Step 'Final' 'AutoAdminLogon=1' to Final gate.
Also update WinISO default path to April 2026 refresh ISO.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Test-WSMan in Windows PowerShell 5.1 does not support -SessionOption (WSManSessionOption),
causing "Cannot find a parameter matching the name 'SessionOption'" at runtime.
Prepare-WinBuild2025.ps1:
- Remove Test-WSMan connectivity check step entirely
- Open New-PSSession directly (handles -SkipCACheck via PSSessionOption)
- Wrap New-PSSession in try/catch with the same actionable error message
- Remove $wsmOpt (WSManSessionOption) — no longer needed
Wait-GuestWinRMReady: replace Test-WSMan probe with New-PSSession probe + Remove-PSSession
Wait-VMReady.ps1:
- Remove $wsmOpt entirely
- Replace Test-WSMan -UseSSL -SessionOption with Test-NetConnection -Port 5986
(TCP open on 5986 = HTTPS listener up = VM ready; credentials not available here)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix emerged during §7.4 e2e test run (2026-05-10):
- Deploy: set UsoSvc to Manual explicitly (Server 2025 default = Automatic)
- Setup cleanup: re-apply Set-Service Disabled on wuauserv/UsoSvc after DISM
StartComponentCleanup (WaaSMedicSvc resets StartType during component store cleanup)
- Deploy + Setup: add Administrator autologin (AutoAdminLogon, DefaultUserName,
DefaultPassword, DefaultDomainName) in post-install.ps1; Assert-Step 5c validates it
- Add Validate-DeployState.ps1: standalone host-side check of all Deploy-set state
- Add Validate-SetupState.ps1: standalone host-side check of full post-Setup state
- Mark §7.4, §7.1 and §7.2 e2e validation items as complete in TODO.md
- Update docs: WINDOWS-TEMPLATE-SETUP.md (arch table, validation scripts section,
autologin in confine Deploy/Setup); TEST-7.4-e2e.md checklist marked done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>