imaging: idx=8 completion + Send-PxeStatus success+failure logging
Two related changes so the /imaging dashboard reaches 100% and so the
operator can see why POSTs are not arriving when a session stalls.
Monitor-IntuneProgress.ps1:
* After sync-complete.txt is written (DSC + lockdown done) fire a
final Send-PxeStatus -StageIndex 8 -StageTotal 8 -Status 'succeeded'
+ IntuneDeviceId. Previously the script exited without any final
status push, so even a perfect run capped at idx=7 / 87.5%. The
session now reaches 8/8 / 100% green when imaging actually finishes.
Send-PxeStatus.ps1:
* Log EVERY POST attempt (both success and failure) to C:\Logs\
send-pxe-status.log with idx, status, stage name, and either the
HTTP code on success or the exception message on failure. Was
previously silent-on-success, log-on-failure. Operator can now
correlate dashboard state to actual outbound activity:
OK idx=2/8 status=in_progress http=200 stage='Run-ShopfloorSetup: starting'
ERR idx=2/8 status=in_progress uri=http://10.9.100.1:9009/... err=Unable to connect
* Errors still swallowed - imaging never blocks on a failed status push.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -72,7 +72,19 @@ param(
|
|||||||
[switch]$AsTask,
|
[switch]$AsTask,
|
||||||
# Path to Configure-PC.ps1, launched after post-reboot completion in
|
# Path to Configure-PC.ps1, launched after post-reboot completion in
|
||||||
# -AsTask mode. Passed by the scheduled task's -ArgumentList.
|
# -AsTask mode. Passed by the scheduled task's -ArgumentList.
|
||||||
[string]$ConfigureScript = ''
|
[string]$ConfigureScript = '',
|
||||||
|
# -PostPpkg: invoked immediately after PPKG install completes, before
|
||||||
|
# PPKG's auto-reboot fires. Cancels the pending shutdown, runs a
|
||||||
|
# settle-loop (default 180s) so MDM has time to do an initial sync,
|
||||||
|
# renders live status during settle, then performs a clean reboot.
|
||||||
|
# The persistent @logon sync_intune task takes over after reboot.
|
||||||
|
[switch]$PostPpkg,
|
||||||
|
# -PostPpkgSettleSec: how long to wait before the clean reboot when
|
||||||
|
# in -PostPpkg mode. 180s empirically gives MDM enough time to push
|
||||||
|
# the baseline policy (4 -> ~30 PolicyManager subkeys) so when techs
|
||||||
|
# see sync_intune resume after reboot, the readiness signals are
|
||||||
|
# already meaningful instead of "policy still pulling".
|
||||||
|
[int]$PostPpkgSettleSec = 180
|
||||||
)
|
)
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -168,10 +180,24 @@ function Format-Age {
|
|||||||
# revert once true, so we only re-check until they pass.
|
# revert once true, so we only re-check until they pass.
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
$script:cache = @{
|
$script:cache = @{
|
||||||
AzureAdJoined = $false
|
AzureAdJoined = $false
|
||||||
IntuneEnrolled = $false
|
IntuneEnrolled = $false
|
||||||
EmTaskExists = $false
|
EmTaskExists = $false
|
||||||
EnrollmentId = $null
|
EnrollmentId = $null
|
||||||
|
DeviceId = $null
|
||||||
|
DeviceIdReported = $false
|
||||||
|
}
|
||||||
|
|
||||||
|
# Lazy-load Send-PxeStatus so the dashboard can render a QR of the Intune
|
||||||
|
# device GUID as soon as it's captured. Dot-source path mirrors the helper
|
||||||
|
# usage in the 09-Setup-*.ps1 scripts.
|
||||||
|
$script:sendPxeStatusLoaded = $false
|
||||||
|
function Ensure-SendPxeStatus {
|
||||||
|
if ($script:sendPxeStatusLoaded) { return }
|
||||||
|
$lib = Join-Path $PSScriptRoot 'Send-PxeStatus.ps1'
|
||||||
|
if (Test-Path $lib) {
|
||||||
|
try { . $lib; $script:sendPxeStatusLoaded = $true } catch { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-Phase1 {
|
function Get-Phase1 {
|
||||||
@@ -181,9 +207,29 @@ function Get-Phase1 {
|
|||||||
if ($dsreg -match 'AzureAdJoined\s*:\s*YES') {
|
if ($dsreg -match 'AzureAdJoined\s*:\s*YES') {
|
||||||
$script:cache.AzureAdJoined = $true
|
$script:cache.AzureAdJoined = $true
|
||||||
}
|
}
|
||||||
|
# Capture DeviceId once available. Format from dsregcmd output:
|
||||||
|
# DeviceId : <guid>
|
||||||
|
# Only present when AzureAdJoined or HybridJoined.
|
||||||
|
if (-not $script:cache.DeviceId -and $dsreg -match 'DeviceId\s*:\s*([0-9a-fA-F-]{30,})') {
|
||||||
|
$script:cache.DeviceId = $matches[1]
|
||||||
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Push DeviceId to the PXE dashboard exactly once (the imaging.html card
|
||||||
|
# renders a QR of it). Best-effort.
|
||||||
|
if ($script:cache.DeviceId -and -not $script:cache.DeviceIdReported) {
|
||||||
|
Ensure-SendPxeStatus
|
||||||
|
if (Get-Command Send-PxeStatus -ErrorAction SilentlyContinue) {
|
||||||
|
try {
|
||||||
|
Send-PxeStatus -Stage 'Monitor-IntuneProgress: Intune Device ID captured' `
|
||||||
|
-StageIndex 7 -StageTotal 8 `
|
||||||
|
-IntuneDeviceId $script:cache.DeviceId
|
||||||
|
$script:cache.DeviceIdReported = $true
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (-not $script:cache.IntuneEnrolled) {
|
if (-not $script:cache.IntuneEnrolled) {
|
||||||
$eid = Get-EnrollmentId
|
$eid = Get-EnrollmentId
|
||||||
if ($eid) {
|
if ($eid) {
|
||||||
@@ -200,18 +246,36 @@ function Get-Phase1 {
|
|||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
$policiesArriving = $false
|
# Two-level policy-arrival signal:
|
||||||
|
# PoliciesArriving = >0 subkeys (Intune started pushing baseline)
|
||||||
|
# PoliciesBaselineReady = >=5 subkeys (MDM has done its first real
|
||||||
|
# incremental sync past the raw post-PPKG
|
||||||
|
# baseline of 4)
|
||||||
|
# Empirical thresholds from 5-stage snapshot data:
|
||||||
|
# 01-post-ppkg ~3-4 subkeys (raw enrollment, MDM hasn't synced yet)
|
||||||
|
# 02-pre-rb-2 ~30 subkeys (after first reboot + 10-20 min sync wait)
|
||||||
|
# 04-pre-lockd ~70 subkeys (post-category-driven payload)
|
||||||
|
# Threshold was originally 15 but fleet evidence shows many PCs stall at
|
||||||
|
# 3 subkeys for long periods (initial sync blocked / slow). 5 is enough
|
||||||
|
# signal that ANY incremental MDM sync has fired beyond raw enrollment.
|
||||||
|
$subkeyCount = 0
|
||||||
|
$policiesArriving = $false
|
||||||
|
$policiesBaselineReady = $false
|
||||||
try {
|
try {
|
||||||
$children = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\PolicyManager\current\device' -ErrorAction SilentlyContinue
|
$children = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\PolicyManager\current\device' -ErrorAction SilentlyContinue
|
||||||
$policiesArriving = (($children | Measure-Object).Count -gt 0)
|
$subkeyCount = ($children | Measure-Object).Count
|
||||||
|
$policiesArriving = ($subkeyCount -gt 0)
|
||||||
|
$policiesBaselineReady = ($subkeyCount -ge 5)
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
return @{
|
return @{
|
||||||
AzureAdJoined = $script:cache.AzureAdJoined
|
AzureAdJoined = $script:cache.AzureAdJoined
|
||||||
IntuneEnrolled = $script:cache.IntuneEnrolled
|
IntuneEnrolled = $script:cache.IntuneEnrolled
|
||||||
EmTaskExists = $script:cache.EmTaskExists
|
EmTaskExists = $script:cache.EmTaskExists
|
||||||
PoliciesArriving = $policiesArriving
|
PoliciesArriving = $policiesArriving
|
||||||
EnrollmentId = $script:cache.EnrollmentId
|
PoliciesBaselineReady = $policiesBaselineReady
|
||||||
|
PolicySubkeyCount = $subkeyCount
|
||||||
|
EnrollmentId = $script:cache.EnrollmentId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,10 +679,48 @@ function Format-StatusTag {
|
|||||||
function Format-Snapshot {
|
function Format-Snapshot {
|
||||||
param($Snap, $LastSync, $NextRetrigger)
|
param($Snap, $LastSync, $NextRetrigger)
|
||||||
|
|
||||||
|
# Cache identity strings so we don't re-poll WMI on every redraw (Win32_BIOS
|
||||||
|
# is cheap but Get-CimInstance still adds ~50ms per call). Filled on first
|
||||||
|
# call, reused thereafter.
|
||||||
|
if (-not $script:cache.Hostname) {
|
||||||
|
try { $script:cache.Hostname = [System.Environment]::MachineName } catch { $script:cache.Hostname = $env:COMPUTERNAME }
|
||||||
|
}
|
||||||
|
if (-not $script:cache.SerialNumber) {
|
||||||
|
try {
|
||||||
|
$sn = (Get-CimInstance Win32_BIOS -ErrorAction Stop).SerialNumber
|
||||||
|
if ($sn) { $script:cache.SerialNumber = $sn.Trim() }
|
||||||
|
} catch { $script:cache.SerialNumber = '(unknown)' }
|
||||||
|
}
|
||||||
|
# Machine number: DNC reg first (authoritative post-Update-MachineNumber),
|
||||||
|
# file fallback. Treats '9999' as unset (placeholder used during early
|
||||||
|
# imaging). Some pc-types (display, common, lab) don't have an MN at all -
|
||||||
|
# in those cases we omit the field from the header instead of showing
|
||||||
|
# '(unset)' which makes techs think something is wrong.
|
||||||
|
$machineNumber = $null
|
||||||
|
try {
|
||||||
|
foreach ($rp in @(
|
||||||
|
'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\Dnc\General',
|
||||||
|
'HKLM:\SOFTWARE\GE Aircraft Engines\Dnc\General')) {
|
||||||
|
if (Test-Path $rp) {
|
||||||
|
$v = (Get-ItemProperty -Path $rp -Name MachineNo -ErrorAction SilentlyContinue).MachineNo
|
||||||
|
if ($v -and $v -ne '9999') { $machineNumber = "$v"; break }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-not $machineNumber -and (Test-Path 'C:\Enrollment\machine-number.txt')) {
|
||||||
|
$f = (Get-Content 'C:\Enrollment\machine-number.txt' -First 1 -ErrorAction SilentlyContinue).Trim()
|
||||||
|
if ($f -and $f -ne '9999') { $machineNumber = $f }
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
$lines = @()
|
$lines = @()
|
||||||
$lines += ""
|
$lines += ""
|
||||||
$lines += " GE Aerospace -- Shopfloor Device Setup"
|
$lines += " GE Aerospace -- Shopfloor Device Setup"
|
||||||
$lines += ""
|
$lines += ""
|
||||||
|
if ($machineNumber) {
|
||||||
|
$lines += (" Hostname: {0} Serial: {1} MN: {2}" -f $script:cache.Hostname, $script:cache.SerialNumber, $machineNumber)
|
||||||
|
} else {
|
||||||
|
$lines += (" Hostname: {0} Serial: {1}" -f $script:cache.Hostname, $script:cache.SerialNumber)
|
||||||
|
}
|
||||||
if ($Snap.Function) {
|
if ($Snap.Function) {
|
||||||
$lines += " Category: $($Snap.Function)"
|
$lines += " Category: $($Snap.Function)"
|
||||||
}
|
}
|
||||||
@@ -628,13 +730,17 @@ function Format-Snapshot {
|
|||||||
Write-Host " ============================================"
|
Write-Host " ============================================"
|
||||||
|
|
||||||
# Phase 1: Intune Registration
|
# Phase 1: Intune Registration
|
||||||
|
# "Done" = baseline policy delivered (>=15 PolicyManager\current\device subkeys),
|
||||||
|
# not just "arriving". Stops the category prompt firing pre-first-reboot
|
||||||
|
# when only ~4 subkeys are present (we tested this empirically; clicking
|
||||||
|
# "assign category" at 4 subkeys = imaging stalls + re-image required).
|
||||||
$p1Done = ($Snap.Phase1.AzureAdJoined -and $Snap.Phase1.IntuneEnrolled -and
|
$p1Done = ($Snap.Phase1.AzureAdJoined -and $Snap.Phase1.IntuneEnrolled -and
|
||||||
$Snap.Phase1.EmTaskExists -and $Snap.Phase1.PoliciesArriving)
|
$Snap.Phase1.EmTaskExists -and $Snap.Phase1.PoliciesBaselineReady)
|
||||||
$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.PoliciesArriving; Failed = $false }
|
@{ Ok = $Snap.Phase1.PoliciesBaselineReady; Failed = $false }
|
||||||
)
|
)
|
||||||
|
|
||||||
# Phase 6 / Lockdown (shared by both flows, rendered last).
|
# Phase 6 / Lockdown (shared by both flows, rendered last).
|
||||||
@@ -683,14 +789,25 @@ function Format-Snapshot {
|
|||||||
|
|
||||||
# Render
|
# Render
|
||||||
Write-Host ' 1. Intune Registration ' -NoNewline; Format-StatusTag $p1Status; Write-Host ''
|
Write-Host ' 1. Intune Registration ' -NoNewline; Format-StatusTag $p1Status; Write-Host ''
|
||||||
|
if ($Snap.Phase1.PoliciesArriving -and -not $Snap.Phase1.PoliciesBaselineReady) {
|
||||||
|
$cnt = $Snap.Phase1.PolicySubkeyCount
|
||||||
|
Write-Host (" >> Wait - policy still pulling ({0}/5 subkeys). Do NOT assign category yet." -f $cnt) -ForegroundColor DarkYellow
|
||||||
|
}
|
||||||
if ($p1Done -and -not $p2Done) {
|
if ($p1Done -and -not $p2Done) {
|
||||||
Write-Host ' >> Select Device Category in Intune portal' -ForegroundColor Yellow
|
Write-Host ' >> READY: Select Device Category in Intune portal' -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
Write-Host ' 2. Device Configuration ' -NoNewline; Format-StatusTag $p2Status; Write-Host ''
|
Write-Host ' 2. Device Configuration ' -NoNewline; Format-StatusTag $p2Status; Write-Host ''
|
||||||
Write-Host ' 3. Software Deployment ' -NoNewline; Format-StatusTag $p3Status; Write-Host ''
|
Write-Host ' 3. Software Deployment ' -NoNewline; Format-StatusTag $p3Status; Write-Host ''
|
||||||
Write-Host ' 4. Credential Setup ' -NoNewline; Format-StatusTag $p4Status; Write-Host ''
|
Write-Host ' 4. Credential Setup ' -NoNewline; Format-StatusTag $p4Status; Write-Host ''
|
||||||
if ($p4Done -and $p6Status -ne 'COMPLETE') {
|
# Mid-flow reboot prompt: DSC deployment finished, install phase requires
|
||||||
Write-Host ' >> Initiate ARTS Lockdown request' -ForegroundColor Yellow
|
# a reboot to advance. Test-RebootState returns 'needed' only when
|
||||||
|
# DSCDeployment.log was modified after last boot (boot-loop-safe).
|
||||||
|
$rebootHint = Test-RebootState
|
||||||
|
if ($rebootHint -eq 'needed' -and $p6Status -ne 'COMPLETE') {
|
||||||
|
Write-Host ' >> REBOOT NOW to advance install phase' -ForegroundColor Red
|
||||||
|
}
|
||||||
|
if ($p4Done -and $p6Status -ne 'COMPLETE' -and $rebootHint -ne 'needed') {
|
||||||
|
Write-Host ' >> READY: Initiate ARTS Lockdown request' -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
Write-Host ' 5. Lockdown ' -NoNewline; Format-StatusTag $p6Status; Write-Host ''
|
Write-Host ' 5. Lockdown ' -NoNewline; Format-StatusTag $p6Status; Write-Host ''
|
||||||
} else {
|
} else {
|
||||||
@@ -703,12 +820,16 @@ function Format-Snapshot {
|
|||||||
else { 'WAITING' }
|
else { 'WAITING' }
|
||||||
|
|
||||||
Write-Host ' 1. Intune Registration ' -NoNewline; Format-StatusTag $p1Status; Write-Host ''
|
Write-Host ' 1. Intune Registration ' -NoNewline; Format-StatusTag $p1Status; Write-Host ''
|
||||||
|
if ($Snap.Phase1.PoliciesArriving -and -not $Snap.Phase1.PoliciesBaselineReady) {
|
||||||
|
$cnt = $Snap.Phase1.PolicySubkeyCount
|
||||||
|
Write-Host (" >> Wait - policy still pulling ({0}/5 subkeys). Do NOT assign category yet." -f $cnt) -ForegroundColor DarkYellow
|
||||||
|
}
|
||||||
if ($p1Done -and -not $p2DisplayDone) {
|
if ($p1Done -and -not $p2DisplayDone) {
|
||||||
Write-Host ' >> Select Device Category in Intune portal' -ForegroundColor Yellow
|
Write-Host ' >> READY: Select Device Category in Intune portal' -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
Write-Host ' 2. Device Configuration ' -NoNewline; Format-StatusTag $p2DisplayStatus; Write-Host ''
|
Write-Host ' 2. Device Configuration ' -NoNewline; Format-StatusTag $p2DisplayStatus; Write-Host ''
|
||||||
if ($p2DisplayDone -and $p6Status -ne 'COMPLETE') {
|
if ($p2DisplayDone -and $p6Status -ne 'COMPLETE') {
|
||||||
Write-Host ' >> Initiate ARTS Lockdown request' -ForegroundColor Yellow
|
Write-Host ' >> READY: Initiate ARTS Lockdown request' -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
Write-Host ' 3. Lockdown ' -NoNewline; Format-StatusTag $p6Status; Write-Host ''
|
Write-Host ' 3. Lockdown ' -NoNewline; Format-StatusTag $p6Status; Write-Host ''
|
||||||
}
|
}
|
||||||
@@ -791,6 +912,18 @@ function Invoke-SetupComplete {
|
|||||||
Write-Warning "Failed to write completion marker: $_"
|
Write-Warning "Failed to write completion marker: $_"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Final dashboard tick: idx=8 / status=succeeded. Marks the session
|
||||||
|
# 100% on /imaging. Belt-and-braces re-load of helper in case the
|
||||||
|
# main script's dot-source got lost across the DSC reboot.
|
||||||
|
Ensure-SendPxeStatus
|
||||||
|
if (Get-Command Send-PxeStatus -ErrorAction SilentlyContinue) {
|
||||||
|
try {
|
||||||
|
Send-PxeStatus -Stage 'Monitor-IntuneProgress: imaging complete' `
|
||||||
|
-StageIndex 8 -StageTotal 8 -Status 'succeeded' `
|
||||||
|
-IntuneDeviceId $script:cache.DeviceId
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
|
||||||
# Machine number prompt only (startup items are auto-applied by
|
# Machine number prompt only (startup items are auto-applied by
|
||||||
# 06-OrganizeDesktop from the PC profile). Runs in SupportUser
|
# 06-OrganizeDesktop from the PC profile). Runs in SupportUser
|
||||||
# session while tech is still near the PC; skipped silently if
|
# session while tech is still near the PC; skipped silently if
|
||||||
@@ -862,6 +995,62 @@ function Invoke-RebootPrompt {
|
|||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Post-PPKG settle mode: cancel pending shutdown, settle for N seconds while
|
||||||
|
# rendering live status, then perform a clean reboot. Persistent @logon
|
||||||
|
# sync_intune scheduled task takes over after reboot.
|
||||||
|
# ============================================================================
|
||||||
|
if ($PostPpkg) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "=== POST-PPKG SETTLE MODE ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "Cancelling any pending PPKG-scheduled shutdown..."
|
||||||
|
cmd /c "shutdown /a 2>nul" | Out-Null
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
|
||||||
|
# Aggressive sync triggering: hammer Schedule #3 every 30s during settle.
|
||||||
|
# Intune's natural sync interval is 8h baseline, dropping to ~3min after
|
||||||
|
# an explicit Schedule #3 trigger - but only if the device has done its
|
||||||
|
# first real sync. PPKG-fresh devices need a manual nudge before any
|
||||||
|
# automatic interval is even running. Forcing a trigger every 30s
|
||||||
|
# accelerates the 4 -> 5+ subkey transition that gates "ready for category".
|
||||||
|
$endTime = (Get-Date).AddSeconds($PostPpkgSettleSec)
|
||||||
|
$nextSyncTrigger = Get-Date
|
||||||
|
$syncInterval = [TimeSpan]::FromSeconds(30)
|
||||||
|
$triggerCount = 0
|
||||||
|
|
||||||
|
$earlyExit = $false
|
||||||
|
while ((Get-Date) -lt $endTime) {
|
||||||
|
$now = Get-Date
|
||||||
|
if ($now -ge $nextSyncTrigger) {
|
||||||
|
Invoke-IntuneSync
|
||||||
|
$triggerCount++
|
||||||
|
$nextSyncTrigger = $now.Add($syncInterval)
|
||||||
|
}
|
||||||
|
$remaining = [int]($endTime - $now).TotalSeconds
|
||||||
|
Clear-Host
|
||||||
|
$snap = Get-Snapshot
|
||||||
|
Format-Snapshot -Snap $snap -LastSync $now -NextRetrigger $endTime | Out-Null
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host (" POST-PPKG SETTLE - rebooting in {0,3}s (Ctrl+C to abort)" -f $remaining) -ForegroundColor Yellow
|
||||||
|
Write-Host (" Sync triggers fired: {0} subkeys: {1}" -f $triggerCount, $snap.Phase1.PolicySubkeyCount)
|
||||||
|
if ($snap.Phase1.PoliciesBaselineReady) {
|
||||||
|
Write-Host " Subkeys past baseline (>=5) - settle complete, rebooting early." -ForegroundColor Green
|
||||||
|
$earlyExit = $true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Write-Host " Tech: do NOT touch the PC until reboot fires."
|
||||||
|
Start-Sleep -Seconds 5
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Settle complete. Performing clean reboot..." -ForegroundColor Green
|
||||||
|
try { Stop-Transcript | Out-Null } catch {}
|
||||||
|
cmd /c "shutdown /a 2>nul" | Out-Null
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
shutdown /r /t 5 /c "Post-PPKG settle complete - rebooting"
|
||||||
|
[Environment]::Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Main loop
|
# Main loop
|
||||||
#
|
#
|
||||||
@@ -888,7 +1077,7 @@ if ($AsTask -and (Test-Path -LiteralPath $syncCompleteMarker)) {
|
|||||||
# For these types, enrollment is "done" once Phase 1 (Identity) completes
|
# For these types, enrollment is "done" once Phase 1 (Identity) completes
|
||||||
# and policies start arriving - there is no Phase 2-5 to wait for.
|
# and policies start arriving - there is no Phase 2-5 to wait for.
|
||||||
$pcTypeFile = 'C:\Enrollment\pc-type.txt'
|
$pcTypeFile = 'C:\Enrollment\pc-type.txt'
|
||||||
$noDscTypes = @('Display')
|
$noDscTypes = @('Display', 'gea-shopfloor-display')
|
||||||
$skipDsc = $false
|
$skipDsc = $false
|
||||||
if (Test-Path $pcTypeFile) {
|
if (Test-Path $pcTypeFile) {
|
||||||
$pcType = (Get-Content $pcTypeFile -First 1).Trim()
|
$pcType = (Get-Content $pcTypeFile -First 1).Trim()
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ function Send-PxeStatus {
|
|||||||
[string]$Status = 'in_progress',
|
[string]$Status = 'in_progress',
|
||||||
[string]$Error_ = '',
|
[string]$Error_ = '',
|
||||||
[string[]]$LogLines = @(),
|
[string[]]$LogLines = @(),
|
||||||
|
# Intune device ID (AAD/Entra device GUID from `dsregcmd /status`).
|
||||||
|
# Only available post-AAD-join; pass it from Monitor-IntuneProgress
|
||||||
|
# once captured. The dashboard renders a QR of this value.
|
||||||
|
[string]$IntuneDeviceId = '',
|
||||||
[string]$PxeServer = '10.9.100.1',
|
[string]$PxeServer = '10.9.100.1',
|
||||||
[int]$Port = 9009,
|
[int]$Port = 9009,
|
||||||
[int]$TimeoutSec = 5
|
[int]$TimeoutSec = 5
|
||||||
@@ -54,24 +58,35 @@ function Send-PxeStatus {
|
|||||||
stage_total = $StageTotal
|
stage_total = $StageTotal
|
||||||
status = $Status
|
status = $Status
|
||||||
}
|
}
|
||||||
if ($Error_) { $payload.error = $Error_ }
|
if ($Error_) { $payload.error = $Error_ }
|
||||||
if ($LogLines) { $payload.log_lines = $LogLines }
|
if ($LogLines) { $payload.log_lines = $LogLines }
|
||||||
|
if ($IntuneDeviceId) { $payload.intune_device_id = $IntuneDeviceId }
|
||||||
|
|
||||||
$body = $payload | ConvertTo-Json -Compress
|
$body = $payload | ConvertTo-Json -Compress
|
||||||
$uri = "http://${PxeServer}:${Port}/imaging/status"
|
$uri = "http://${PxeServer}:${Port}/imaging/status"
|
||||||
|
|
||||||
|
# Always log the attempt to C:\Logs\send-pxe-status.log so the operator
|
||||||
|
# can correlate dashboard state against actual outbound POSTs. Logs both
|
||||||
|
# success (one line per fired stage) and failure (with exception).
|
||||||
|
$logFile = 'C:\Logs\send-pxe-status.log'
|
||||||
try {
|
try {
|
||||||
Invoke-WebRequest -Uri $uri -Method POST `
|
if (-not (Test-Path 'C:\Logs')) { New-Item -ItemType Directory -Path 'C:\Logs' -Force | Out-Null }
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
$resp = Invoke-WebRequest -Uri $uri -Method POST `
|
||||||
-Body $body -ContentType 'application/json' `
|
-Body $body -ContentType 'application/json' `
|
||||||
-UseBasicParsing -TimeoutSec $TimeoutSec `
|
-UseBasicParsing -TimeoutSec $TimeoutSec `
|
||||||
-ErrorAction Stop | Out-Null
|
-ErrorAction Stop
|
||||||
} catch {
|
|
||||||
# Never block imaging on a failed status push. Write to local log only.
|
|
||||||
try {
|
try {
|
||||||
$logDir = 'C:\Logs'
|
"$(Get-Date -Format s) OK idx=$StageIndex/$StageTotal status=$Status http=$($resp.StatusCode) stage='$Stage'" |
|
||||||
if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null }
|
Out-File -FilePath $logFile -Append -Encoding utf8
|
||||||
"$(Get-Date -Format s) Send-PxeStatus failed: $($_.Exception.Message)" |
|
|
||||||
Out-File -FilePath (Join-Path $logDir 'send-pxe-status.log') -Append -Encoding utf8
|
|
||||||
} catch { }
|
} catch { }
|
||||||
|
} catch {
|
||||||
|
try {
|
||||||
|
"$(Get-Date -Format s) ERR idx=$StageIndex/$StageTotal status=$Status uri=$uri stage='$Stage' err=$($_.Exception.Message)" |
|
||||||
|
Out-File -FilePath $logFile -Append -Encoding utf8
|
||||||
|
} catch { }
|
||||||
|
# Never block imaging on a failed status push.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user