fix(toolchain): pin WU disabled across the DISM /ResetBase window
The disk-cleanup function stopped wuauserv before DISM /StartComponentCleanup /ResetBase but only re-enforced Start=4 AFTER it. /ResetBase drives heavy CBS servicing (TiWorker); during that window WaaSMedicSvc woke, flipped wuauserv Start back to Manual, and a "Schedule Scan" task started it. If the pass was interrupted there (reboot/crash), the template was left with WU running and Manual startup — a half-prepared state where Windows Update keeps firing on a supposedly-locked-down build template. Move the lockdown ahead of DISM: set wuauserv Start=4, apply the WaaSMedicSvc registry write-deny ACL (the only reliable lever — the service is protected and cannot itself be disabled), and disable the WindowsUpdate / UpdateOrchestrator scan tasks, all BEFORE /ResetBase rather than only after. The post-DISM re-enforce stays as a belt-and-suspenders check. Applied identically to the WinBuild2025 and WinBuild2022 toolchains.
This commit is contained in:
@@ -253,6 +253,41 @@ function Invoke-DiskCleanup {
|
||||
foreach ($svc in 'wuauserv', 'UsoSvc', 'bits', 'dosvc', 'TrustedInstaller') {
|
||||
Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
# Pin Windows Update down for the WHOLE DISM /ResetBase window below. /ResetBase
|
||||
# drives heavy CBS servicing (TiWorker); with wuauserv merely *stopped* and no
|
||||
# ACL yet, WaaSMedicSvc wakes, flips wuauserv Start back to Manual, and a
|
||||
# "Schedule Scan" task starts it mid-cleanup — so an interruption here leaves WU
|
||||
# running (exactly the half-prepared state seen on stuck templates). Force
|
||||
# Start=4, deny WaaSMedicSvc the registry write, and disable the scan tasks
|
||||
# BEFORE DISM, not only in the re-enforce after it.
|
||||
Set-Service -Name wuauserv -StartupType Disabled -ErrorAction SilentlyContinue
|
||||
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv' `
|
||||
-Name Start -Value 4 -Type DWord -Force -ErrorAction SilentlyContinue
|
||||
try {
|
||||
$svcRegPath = 'HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv'
|
||||
$acl = Get-Acl $svcRegPath
|
||||
$denyRule = New-Object System.Security.AccessControl.RegistryAccessRule(
|
||||
([System.Security.Principal.NTAccount]'NT SERVICE\WaaSMedicSvc'),
|
||||
[System.Security.AccessControl.RegistryRights]'SetValue,CreateSubKey,WriteKey',
|
||||
[System.Security.AccessControl.InheritanceFlags]::None,
|
||||
[System.Security.AccessControl.PropagationFlags]::None,
|
||||
[System.Security.AccessControl.AccessControlType]::Deny
|
||||
)
|
||||
$acl.AddAccessRule($denyRule)
|
||||
Set-Acl $svcRegPath $acl
|
||||
Write-Host "wuauserv: WaaSMedicSvc write-deny ACL applied (pre-DISM)."
|
||||
} catch {
|
||||
Write-Warning "wuauserv pre-DISM ACL deny skipped (non-fatal): $_"
|
||||
}
|
||||
foreach ($t in @(
|
||||
'\Microsoft\Windows\WindowsUpdate\Scheduled Start',
|
||||
'\Microsoft\Windows\UpdateOrchestrator\Schedule Scan',
|
||||
'\Microsoft\Windows\UpdateOrchestrator\Schedule Scan Static Task'
|
||||
)) {
|
||||
schtasks /Change /TN $t /Disable 2>&1 | Out-Null
|
||||
}
|
||||
|
||||
$sdDownload = 'C:\Windows\SoftwareDistribution\Download'
|
||||
Remove-Item $sdDownload -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Path $sdDownload -Force | Out-Null
|
||||
|
||||
@@ -254,6 +254,41 @@ function Invoke-DiskCleanup {
|
||||
foreach ($svc in 'wuauserv', 'UsoSvc', 'bits', 'dosvc', 'TrustedInstaller') {
|
||||
Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
# Pin Windows Update down for the WHOLE DISM /ResetBase window below. /ResetBase
|
||||
# drives heavy CBS servicing (TiWorker); with wuauserv merely *stopped* and no
|
||||
# ACL yet, WaaSMedicSvc wakes, flips wuauserv Start back to Manual, and a
|
||||
# "Schedule Scan" task starts it mid-cleanup — so an interruption here leaves WU
|
||||
# running (exactly the half-prepared state seen on stuck templates). Force
|
||||
# Start=4, deny WaaSMedicSvc the registry write, and disable the scan tasks
|
||||
# BEFORE DISM, not only in the re-enforce after it.
|
||||
Set-Service -Name wuauserv -StartupType Disabled -ErrorAction SilentlyContinue
|
||||
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv' `
|
||||
-Name Start -Value 4 -Type DWord -Force -ErrorAction SilentlyContinue
|
||||
try {
|
||||
$svcRegPath = 'HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv'
|
||||
$acl = Get-Acl $svcRegPath
|
||||
$denyRule = New-Object System.Security.AccessControl.RegistryAccessRule(
|
||||
([System.Security.Principal.NTAccount]'NT SERVICE\WaaSMedicSvc'),
|
||||
[System.Security.AccessControl.RegistryRights]'SetValue,CreateSubKey,WriteKey',
|
||||
[System.Security.AccessControl.InheritanceFlags]::None,
|
||||
[System.Security.AccessControl.PropagationFlags]::None,
|
||||
[System.Security.AccessControl.AccessControlType]::Deny
|
||||
)
|
||||
$acl.AddAccessRule($denyRule)
|
||||
Set-Acl $svcRegPath $acl
|
||||
Write-Host "wuauserv: WaaSMedicSvc write-deny ACL applied (pre-DISM)."
|
||||
} catch {
|
||||
Write-Warning "wuauserv pre-DISM ACL deny skipped (non-fatal): $_"
|
||||
}
|
||||
foreach ($t in @(
|
||||
'\Microsoft\Windows\WindowsUpdate\Scheduled Start',
|
||||
'\Microsoft\Windows\UpdateOrchestrator\Schedule Scan',
|
||||
'\Microsoft\Windows\UpdateOrchestrator\Schedule Scan Static Task'
|
||||
)) {
|
||||
schtasks /Change /TN $t /Disable 2>&1 | Out-Null
|
||||
}
|
||||
|
||||
$sdDownload = 'C:\Windows\SoftwareDistribution\Download'
|
||||
Remove-Item $sdDownload -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Path $sdDownload -Force | Out-Null
|
||||
|
||||
Reference in New Issue
Block a user