From 76a3ba513ca683a9e0a4d689c8bb4d6b24ff1b89 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Fri, 15 May 2026 08:25:37 -0400 Subject: [PATCH] Monitor: drop cert pre-gate + force Report IP after AESFMA connect Two fixes for the AESFMA swap path: 1. Removed the X509Chain root-thumbprint pre-check. Bay user reported "claims connect not yet operational, but i was able to manually connect" - meaning the cert IS in LocalMachine\My but $chain.Build() returns a partial chain (probably missing an intermediate in the local trust store), so our root-thumbprint match returned false and Monitor never even tried the netsh connect. Letting netsh attempt directly - it's the source of truth on whether EAP-TLS auth succeeds. Rate-limited to 30s between attempts to avoid log spam when AESFMA truly isn't reachable. 2. Bumped post-connect verify sleep 8s -> 15s. WLAN auth + DHCP can take longer than 8s on first attempt. 3. New: once Test-AESFMAConnected returns true and INTERNETACCESS is deleted, force-run GE_ReportIP_3_v1.EXE /ForceUpdate=True /S so the webhook gets the corp-AESFMA IP immediately instead of waiting for the next DHCP-change trigger (which may never fire if AESFMA was the bay's first 10.x lease). $script:cache. ReportIpForced caches the one-shot fire. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Shopfloor/lib/Monitor-IntuneProgress.ps1 | 60 +++++++++++-------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 b/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 index 7821cfb..4e34683 100644 --- a/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 +++ b/playbook/shopfloor-setup/Shopfloor/lib/Monitor-IntuneProgress.ps1 @@ -189,6 +189,7 @@ $script:cache = @{ SfldPolicyPushed = $false CredsReadyPushed = $false LockdownCompletePushed = $false + ReportIpForced = $false InternetAccessDeleted = $false } @@ -348,49 +349,56 @@ function Get-Phase1 { return $false } - # Fast path: AESFMA already connected (cert + WLAN service handled - # it without our help, or a prior tick connected). Delete - # INTERNETACCESS if still present, flip cache flag, stop trying. if (Test-AESFMAConnected) { - Write-Host "AESFMA already connected - cleaning up INTERNETACCESS..." + # Already connected (either via WLAN auto-join, prior tick's + # attempt, or an operator manual connect). Clean up + # INTERNETACCESS, force a Report IP push from the AESFMA-attached + # corp address, and stop trying. + Write-Host "AESFMA connected - cleaning up INTERNETACCESS..." $null = netsh wlan delete profile name="INTERNETACCESS" 2>&1 | Out-String $script:cache.InternetAccessDeleted = $true - } else { - # Slow path: walk LocalMachine\My for any cert chained to the - # GE Aerospace FreeRADIUS root (thumbprint from AESFMA.xml). - $aesfmaRootThumb = '27F0C9A22B28CE7687B115A29E31BF4B3ABB180F' - $hasAesfmaCert = $false - try { - foreach ($cert in (Get-ChildItem 'Cert:\LocalMachine\My' -ErrorAction SilentlyContinue)) { - $chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain - $chain.ChainPolicy.RevocationMode = 'NoCheck' - $null = $chain.Build($cert) - foreach ($el in $chain.ChainElements) { - if ($el.Certificate.Thumbprint -eq $aesfmaRootThumb) { - $hasAesfmaCert = $true; break - } + # Force the GE Report IP exe to post the new (AESFMA corp) IP + # to the Tines webhook immediately - default trigger is on + # DHCP event + slow interval, this skips the wait. + if (-not $script:cache.ReportIpForced) { + $rip = 'C:\ProgramData\ReportIP\GE_ReportIP_3_v1.EXE' + if (Test-Path $rip) { + try { + Start-Process -FilePath $rip -ArgumentList '/ForceUpdate=True','/S' -WindowStyle Hidden -ErrorAction Stop + Write-Host "Forced GE Report IP push (corp-AESFMA IP)." + $script:cache.ReportIpForced = $true + } catch { + Write-Warning "Force GE Report IP failed: $_" } - if ($hasAesfmaCert) { break } } - } catch {} - - if ($hasAesfmaCert) { + } + } else { + # Not connected. Try without pre-gating on a cert chain check - + # the X509Chain.Build can return a partial chain (e.g. missing + # intermediate) which made the strict root-thumbprint match + # false even when EAP-TLS would actually succeed. Let netsh + # itself be the source of truth via the connect attempt. + # Rate-limit: at most one attempt every 30 seconds to avoid + # spam when AESFMA isn't actually reachable. + $now = Get-Date + if (-not $script:cache.AesfmaNextAttempt -or $now -ge $script:cache.AesfmaNextAttempt) { try { - Write-Host "AESFMA cert detected (chains to GE RADIUS root) - connecting AESFMA..." + Write-Host "Attempting AESFMA connect (INTERNETACCESS stays up as fallback)..." $null = netsh wlan connect name="AESFMA" ssid="AESFMA" 2>&1 | Out-String - Start-Sleep -Seconds 8 + Start-Sleep -Seconds 15 if (Test-AESFMAConnected) { Write-Host "AESFMA connected. Deleting INTERNETACCESS profile..." $null = netsh wlan delete profile name="INTERNETACCESS" 2>&1 | Out-String $script:cache.InternetAccessDeleted = $true } else { - Write-Host "AESFMA cert present but connect not yet operational - retry next tick." + Write-Host "AESFMA connect not yet operational - will retry in 30s." + $script:cache.AesfmaNextAttempt = $now.AddSeconds(30) } } catch { Write-Warning "AESFMA connect/swap attempt failed: $_" + $script:cache.AesfmaNextAttempt = $now.AddSeconds(30) } } - # else: cert not delivered yet. INTERNETACCESS stays. Retry next tick. } } # idx=7 push fires AS SOON AS DeviceId is captured. We want the QR