fix(setup): defeat WaaSMedicSvc wuauserv healing + AutoAdminLogon Final gate
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>
This commit is contained in:
@@ -573,6 +573,12 @@ Write-Step "Disabling Windows Update permanently (post-update snapshot lockdown)
|
||||
# Stop + disable main WU service
|
||||
Stop-Service -Name wuauserv -Force -ErrorAction SilentlyContinue
|
||||
Set-Service -Name wuauserv -StartupType Disabled
|
||||
# Write Start=4 directly to the service registry key in addition to the SCM call.
|
||||
# Set-Service calls ChangeServiceConfig (SCM API) which WaaSMedicSvc can override via its
|
||||
# own SCM call. The registry Start value requires WaaSMedicSvc to have registry write
|
||||
# access — denied by the ACL block below.
|
||||
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv' `
|
||||
-Name Start -Value 4 -Type DWord -Force
|
||||
|
||||
# Stop + disable Update Orchestrator Service (UsoSvc) — WU client in Server 2025
|
||||
Stop-Service -Name UsoSvc -Force -ErrorAction SilentlyContinue
|
||||
@@ -603,6 +609,30 @@ foreach ($taskName in @('Scheduled Start', 'WakeTimer', 'Automatic App Update',
|
||||
}
|
||||
Write-Host "Windows Update scheduled tasks disabled (best-effort)."
|
||||
|
||||
# Deny WaaSMedicSvc write access to the wuauserv service registry key so it cannot
|
||||
# reset Start back to Manual (2) or Automatic (3) after we set it to Disabled (4).
|
||||
# WaaSMedicSvc is a protected service that cannot itself be disabled; ACL denial
|
||||
# is the only reliable way to prevent it from healing the service startup type.
|
||||
# Best-effort: wrapped in try/catch so that a WinRM session permission failure is
|
||||
# non-fatal (the GPO keys + Start=4 still provide a good baseline).
|
||||
try {
|
||||
$svcRegPath = 'HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv'
|
||||
$acl = Get-Acl $svcRegPath
|
||||
$medicSid = [System.Security.Principal.NTAccount]'NT SERVICE\WaaSMedicSvc'
|
||||
$denyRule = New-Object System.Security.AccessControl.RegistryAccessRule(
|
||||
$medicSid,
|
||||
[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."
|
||||
} catch {
|
||||
Write-Warning "wuauserv ACL deny skipped (non-fatal — GPO keys + Start=4 still in place): $_"
|
||||
}
|
||||
|
||||
# Validation
|
||||
Assert-Step 'WUDisable' 'wuauserv StartType Disabled' {
|
||||
(Get-Service wuauserv -ErrorAction Stop).StartType -eq 'Disabled'
|
||||
@@ -991,6 +1021,8 @@ Write-Host "Disk cleanup complete."
|
||||
foreach ($svc in 'wuauserv', 'UsoSvc') {
|
||||
Set-Service -Name $svc -StartupType Disabled -ErrorAction SilentlyContinue
|
||||
}
|
||||
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv' `
|
||||
-Name Start -Value 4 -Type DWord -Force -ErrorAction SilentlyContinue
|
||||
|
||||
# Validation — leftover artifacts from this run should be gone
|
||||
# Note: do NOT assert SoftwareDistribution\Download empty.
|
||||
@@ -1007,6 +1039,27 @@ Assert-Step 'Cleanup' 'wuauserv StartType Disabled after cache clear' {
|
||||
}
|
||||
} # end if (-not $SkipCleanup)
|
||||
|
||||
# ── Pre-Final re-affirmation ──────────────────────────────────────────────────
|
||||
# Steps 7-10 (installs, cleanup, DISM) can take hours. During that window background
|
||||
# tasks or WaaSMedicSvc may reset AutoAdminLogon or wuauserv. Re-affirm both here
|
||||
# immediately before the Final gate so the snapshot captures clean state.
|
||||
|
||||
$wlKey = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon'
|
||||
$wlNow = Get-ItemProperty -Path $wlKey -ErrorAction SilentlyContinue
|
||||
if ($wlNow.AutoAdminLogon -ne '1' -or $wlNow.DefaultUserName -ne 'Administrator') {
|
||||
Set-ItemProperty -Path $wlKey -Name AutoAdminLogon -Value '1' -Type String -Force
|
||||
Set-ItemProperty -Path $wlKey -Name DefaultUserName -Value 'Administrator' -Type String -Force
|
||||
Set-ItemProperty -Path $wlKey -Name DefaultDomainName -Value '.' -Type String -Force
|
||||
}
|
||||
if ($AdminPassword -ne '') {
|
||||
Set-ItemProperty -Path $wlKey -Name DefaultPassword -Value $AdminPassword -Type String -Force
|
||||
}
|
||||
|
||||
Stop-Service -Name wuauserv -Force -ErrorAction SilentlyContinue
|
||||
Set-Service -Name wuauserv -StartupType Disabled
|
||||
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv' `
|
||||
-Name Start -Value 4 -Type DWord -Force
|
||||
|
||||
# ── Final pre-snapshot validation ────────────────────────────────────────────
|
||||
Write-Step "Final pre-snapshot validation"
|
||||
|
||||
@@ -1028,6 +1081,10 @@ Assert-Step 'Final' 'dotnet, python, msbuild all resolvable' {
|
||||
(Test-Path 'C:\Python\python.exe' -PathType Leaf) -and
|
||||
(Test-Path $msbuildPath -PathType Leaf)
|
||||
}
|
||||
Assert-Step 'Final' 'AutoAdminLogon=1, DefaultUserName=Administrator' {
|
||||
$wl = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -ErrorAction Stop
|
||||
$wl.AutoAdminLogon -eq '1' -and $wl.DefaultUserName -eq 'Administrator'
|
||||
}
|
||||
Assert-Step 'Final' 'Windows Update permanently disabled' {
|
||||
(Get-Service wuauserv -ErrorAction Stop).StartType -eq 'Disabled'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user