Monitor: gate WiFi swap on SCEP cert + Phase 1 done on AESFMA connected

Two related fixes for the WiFi handoff timing:

1. WiFi swap (delete INTERNETACCESS + connect AESFMA) was firing on
   Phase 1 essentials being green (AAD + Intune + EmTask + baseline
   policies >=5). That signal flips ~minutes BEFORE the Intune SCEP
   machine cert actually lands in LocalMachine\My. Without the cert,
   AESFMA EAP-TLS auth fails and the bay has no path at all (we just
   deleted INTERNETACCESS). Stuck.

   New gate: walk Cert:\LocalMachine\My for any cert with Client
   Authentication EKU (1.3.6.1.5.5.7.3.2). When that's present, SCEP
   has delivered, AESFMA EAP-TLS will succeed. Swap then fires safely.

2. Phase 1 row on the on-bay Monitor display now ALSO requires
   AESFMA to be actively connected (parsed from netsh wlan show
   interfaces: SSID=AESFMA + State=connected). Phase 1 stays IN
   PROGRESS until the bay is operationally on corp WLAN, not just
   data-side enrolled. Matches user request "not complete phase 1
   until AESFMA is ready".

idx=7 dashboard push still fires on the original Phase 1 essentials
gate so the QR appears as soon as Intune registers the device,
independent of AESFMA join timing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-05-14 17:04:09 -04:00
parent a17b3fae6a
commit 842ef88ccb

View File

@@ -309,29 +309,41 @@ function Get-Phase1 {
} catch {} } catch {}
# Once Intune registration is fully landed (AAD-joined + Intune-enrolled # Once Intune registration is fully landed (AAD-joined + Intune-enrolled
# + EnterpriseMgmt task present + baseline policies arrived), three # + EnterpriseMgmt task present + baseline policies arrived):
# things must happen together: # - Push idx=7 to PXE dashboard with the DeviceId / QR.
# 1. Delete INTERNETACCESS WiFi profile (gets bay off 172.16.x) # The INTERNETACCESS -> AESFMA WiFi swap is GATED SEPARATELY on the
# 2. Connect AESFMA (gets bay onto corp 10.x via EAP-TLS - cert is # actual SCEP-provisioned machine cert landing in LocalMachine\My
# already in LocalMachine\My thanks to Intune SCEP) # with Client Authentication EKU. Phase 1 essentials flip earlier
# 3. Push idx=7 to the PXE dashboard with the captured DeviceId so # than the cert delivery, and tearing INTERNETACCESS without the
# the dashboard card shows the QR for the Intune device id. # cert present leaves the bay with no path (AESFMA EAP-TLS would
# All three fire in one shot per Monitor lifetime via cache flags. # fail). Wait for the cert before swapping.
$phase1Essential = ($script:cache.AzureAdJoined -and $phase1Essential = ($script:cache.AzureAdJoined -and
$script:cache.IntuneEnrolled -and $script:cache.IntuneEnrolled -and
$script:cache.EmTaskExists -and $script:cache.EmTaskExists -and
$policiesBaselineReady) $policiesBaselineReady)
if ($phase1Essential -and -not $script:cache.InternetAccessDeleted) { if (-not $script:cache.InternetAccessDeleted) {
# Look for any LocalMachine\My cert with Client Auth EKU
# (1.3.6.1.5.5.7.3.2). That's what AESFMA EAP-TLS uses.
$hasMachineClientAuthCert = $false
try { try {
Write-Host "Intune registration complete - deleting INTERNETACCESS profile + reconnecting to AESFMA..." $clientAuthEku = '1.3.6.1.5.5.7.3.2'
$delOut = netsh wlan delete profile name="INTERNETACCESS" 2>&1 | Out-String $hasMachineClientAuthCert = [bool](Get-ChildItem 'Cert:\LocalMachine\My' -ErrorAction SilentlyContinue |
Write-Host $delOut Where-Object {
Start-Sleep -Seconds 2 $_.EnhancedKeyUsageList.ObjectId -contains $clientAuthEku
$conOut = netsh wlan connect name="AESFMA" ssid="AESFMA" 2>&1 | Out-String } | Select-Object -First 1)
Write-Host $conOut } catch {}
$script:cache.InternetAccessDeleted = $true if ($hasMachineClientAuthCert) {
} catch { try {
Write-Warning "WiFi swap (INTERNETACCESS -> AESFMA) failed: $_" Write-Host "SCEP machine cert detected - swapping WiFi: delete INTERNETACCESS, connect AESFMA..."
$delOut = netsh wlan delete profile name="INTERNETACCESS" 2>&1 | Out-String
Write-Host $delOut
Start-Sleep -Seconds 2
$conOut = netsh wlan connect name="AESFMA" ssid="AESFMA" 2>&1 | Out-String
Write-Host $conOut
$script:cache.InternetAccessDeleted = $true
} catch {
Write-Warning "WiFi swap (INTERNETACCESS -> AESFMA) failed: $_"
}
} }
} }
if ($phase1Essential -and $script:cache.DeviceId -and -not $script:cache.DeviceIdReported) { if ($phase1Essential -and $script:cache.DeviceId -and -not $script:cache.DeviceIdReported) {
@@ -814,13 +826,27 @@ function Format-Snapshot {
# not just "arriving". Stops the category prompt firing pre-first-reboot # not just "arriving". Stops the category prompt firing pre-first-reboot
# when only ~4 subkeys are present (we tested this empirically; clicking # when only ~4 subkeys are present (we tested this empirically; clicking
# "assign category" at 4 subkeys = imaging stalls + re-image required). # "assign category" at 4 subkeys = imaging stalls + re-image required).
# AESFMA connected = bay has a live corp WLAN association on the
# machine-auth profile. That's the natural ground-truth that Phase 1
# is operationally done (not just the data-side flags). Check the
# WLAN state via netsh wlan show interfaces - look for SSID=AESFMA
# with state=connected.
$aesfmaConnected = $false
try {
$wlanOut = netsh wlan show interfaces 2>$null
if ($wlanOut -match '(?ms)SSID\s*:\s*AESFMA.*?State\s*:\s*connected') {
$aesfmaConnected = $true
}
} catch {}
$p1Done = ($Snap.Phase1.AzureAdJoined -and $Snap.Phase1.IntuneEnrolled -and $p1Done = ($Snap.Phase1.AzureAdJoined -and $Snap.Phase1.IntuneEnrolled -and
$Snap.Phase1.EmTaskExists -and $Snap.Phase1.PoliciesBaselineReady) $Snap.Phase1.EmTaskExists -and $Snap.Phase1.PoliciesBaselineReady -and
$aesfmaConnected)
$p1Status = Get-PhaseStatus @( $p1Status = Get-PhaseStatus @(
@{ Ok = $Snap.Phase1.AzureAdJoined; Failed = $false }, @{ Ok = $Snap.Phase1.AzureAdJoined; Failed = $false },
@{ Ok = $Snap.Phase1.IntuneEnrolled; Failed = $false }, @{ Ok = $Snap.Phase1.IntuneEnrolled; Failed = $false },
@{ Ok = $Snap.Phase1.EmTaskExists; Failed = $false }, @{ Ok = $Snap.Phase1.EmTaskExists; Failed = $false },
@{ Ok = $Snap.Phase1.PoliciesBaselineReady; Failed = $false } @{ Ok = $Snap.Phase1.PoliciesBaselineReady; Failed = $false },
@{ Ok = $aesfmaConnected; Failed = $false }
) )
# Phase 6 / Lockdown (shared by both flows, rendered last). # Phase 6 / Lockdown (shared by both flows, rendered last).