fix(templates): bump WinRM quotas + desktop heap for parallel Win builds
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>
This commit is contained in:
@@ -639,11 +639,29 @@ try {
|
||||
New-NetFirewallRule -DisplayName 'WinRM-HTTPS' -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow -Profile Any -RemoteAddress '192.168.79.0/24' | Out-Null
|
||||
L 'WinRM HTTPS listener configured (port 5986, restricted to 192.168.79.0/24)'
|
||||
} catch { L "WinRM HTTPS failed: `$(`$_.Exception.Message)" }
|
||||
winrm set winrm/config/winrs '@{MaxProcessesPerShell="25"}' | Out-Null
|
||||
winrm set winrm/config/winrs '@{MaxProcessesPerShell="100"}' | Out-Null
|
||||
Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB 2048 -Force 3>`$null
|
||||
Set-Item WSMan:\localhost\Shell\IdleTimeOut 7200000 -Force 3>`$null
|
||||
# Plugin-level quota: pypsrp (Linux→Win) uses Microsoft.PowerShell endpoint,
|
||||
# which has its own MaxMemoryPerShellMB independent of the Shell quota above.
|
||||
# Without this, parallel native processes (e.g. 3x cl.exe in MSBuild fan-out)
|
||||
# fail with MSB6003 / Win32 1816 'Not enough quota'.
|
||||
Set-Item 'WSMan:\localhost\Plugin\Microsoft.PowerShell\Quotas\MaxMemoryPerShellMB' 2048 -Force 3>`$null
|
||||
Set-Service -Name WinRM -StartupType Automatic 3>`$null
|
||||
L 'WinRM shell limits: MaxMemory=2048MB IdleTimeout=2h MaxProcesses=25; StartType=Automatic'
|
||||
Restart-Service -Name WinRM -Force 3>`$null
|
||||
L 'WinRM limits: Shell+Plugin MaxMemory=2048MB, IdleTimeout=2h, MaxProcesses=100; StartType=Automatic'
|
||||
|
||||
# ── Non-interactive desktop heap (csrss SharedSection) ───────────────────
|
||||
# WinRM sessions run in Session 0 non-interactive window station; default
|
||||
# desktop heap is 768 KB. CreateProcess fails with ERROR_NOT_ENOUGH_QUOTA
|
||||
# (Win32 1816 → MSB6003) when multiple compiler processes spawn in parallel.
|
||||
# Bump the third SharedSection field to 4096 KB. Change is read by csrss only
|
||||
# at boot — the post-install shutdown at the end of this script applies it.
|
||||
`$subsysKey = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems'
|
||||
`$subsysCur = (Get-ItemProperty -Path `$subsysKey -Name Windows).Windows
|
||||
`$subsysNew = `$subsysCur -replace 'SharedSection=(\d+),(\d+),\d+', 'SharedSection=`$1,`$2,4096'
|
||||
Set-ItemProperty -Path `$subsysKey -Name Windows -Value `$subsysNew
|
||||
L "Desktop heap (non-interactive) SharedSection 3rd field set to 4096 KB (takes effect after reboot)"
|
||||
|
||||
# ── Server Manager / WAC popup / first-logon UX ──────────────────────────
|
||||
# Server Manager auto-start off — machine-wide + current Administrator + Default
|
||||
|
||||
Reference in New Issue
Block a user