diff --git a/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 b/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 index fae2450..a851b24 100644 --- a/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 +++ b/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 @@ -311,39 +311,35 @@ function Get-Phase1 { # Once Intune registration is fully landed (AAD-joined + Intune-enrolled # + EnterpriseMgmt task present + baseline policies arrived): # - Push idx=7 to PXE dashboard with the DeviceId / QR. - # The INTERNETACCESS -> AESFMA WiFi swap is GATED SEPARATELY on the - # actual SCEP-provisioned machine cert landing in LocalMachine\My - # with Client Authentication EKU. Phase 1 essentials flip earlier - # than the cert delivery, and tearing INTERNETACCESS without the - # cert present leaves the bay with no path (AESFMA EAP-TLS would - # fail). Wait for the cert before swapping. + # The INTERNETACCESS -> AESFMA WiFi swap uses a VERIFY-BEFORE-DELETE + # pattern so the bay never ends up with no path: + # 1. Phase 1 essentials must be COMPLETE (Intune registration done). + # 2. Attempt netsh wlan connect AESFMA while INTERNETACCESS still up. + # 3. Wait ~8s, parse netsh wlan show interfaces for SSID=AESFMA + + # State=connected. + # 4. ONLY after operationally connected to AESFMA, delete INTERNETACCESS. + # 5. If connect fails (cert not provisioned yet, etc), keep + # INTERNETACCESS, retry next tick. $phase1Essential = ($script:cache.AzureAdJoined -and $script:cache.IntuneEnrolled -and $script:cache.EmTaskExists -and $policiesBaselineReady) - 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 + if ($phase1Essential -and -not $script:cache.InternetAccessDeleted) { try { - $clientAuthEku = '1.3.6.1.5.5.7.3.2' - $hasMachineClientAuthCert = [bool](Get-ChildItem 'Cert:\LocalMachine\My' -ErrorAction SilentlyContinue | - Where-Object { - $_.EnhancedKeyUsageList.ObjectId -contains $clientAuthEku - } | Select-Object -First 1) - } catch {} - if ($hasMachineClientAuthCert) { - try { - Write-Host "SCEP machine cert detected - swapping WiFi: delete INTERNETACCESS, connect AESFMA..." + Write-Host "Phase 1 essentials complete - attempting AESFMA join (verify-before-delete)..." + $null = netsh wlan connect name="AESFMA" ssid="AESFMA" 2>&1 | Out-String + Start-Sleep -Seconds 8 + $wlanState = netsh wlan show interfaces 2>$null | Out-String + if ($wlanState -match '(?ms)SSID\s*:\s*AESFMA.*?State\s*:\s*connected') { + Write-Host "AESFMA connected. Deleting INTERNETACCESS profile..." $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: $_" + } else { + Write-Host "AESFMA connect not yet operational - keeping INTERNETACCESS, will retry next tick." } + } catch { + Write-Warning "AESFMA verify-before-delete attempt failed: $_" } } # idx=7 push fires AS SOON AS DeviceId is captured. We want the QR