mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 04:32:32 +00:00
bugfix bootstrapper and update architecture.md
This commit is contained in:
@@ -39,8 +39,8 @@
|
||||
|
||||
.CHANGELOG
|
||||
2026-03-31 Replaced OS age + MDM pre-flight checks with multi-signal guard:
|
||||
registry deployment marker, OOBE state, WMI/filesystem user profile
|
||||
detection, and 12h bootstrap window. Fixes ghost sessions on hybrid
|
||||
registry deployment marker, WMI/filesystem user profile detection,
|
||||
and 12h bootstrap window. OOBEInProgress dropped (unreliable). Fixes ghost sessions on hybrid
|
||||
join pre-provisioned devices where Intune re-targets the bootstrap
|
||||
script after self-destruct.
|
||||
2026-03-30 Fixed non-ASCII characters (em-dashes, Unicode symbols) that broke
|
||||
@@ -111,10 +111,10 @@ try {
|
||||
# -- Pre-flight: Multi-signal guard to prevent installation on non-provisioning devices --
|
||||
# Layered approach: each guard catches a different scenario.
|
||||
# Guard 1: Ghost re-installs (registry marker from previous deployment)
|
||||
# Guard 2: Productive devices not in OOBE
|
||||
# Guard 3: Productive devices with stale OOBEInProgress flag (real user profile exists)
|
||||
# Guard 4: Ultra edge case (no key, OOBE stuck, no user, but device running too long)
|
||||
# Guard 5: Agent binary already present from a previous run
|
||||
# Guard 2: Productive devices (real user profile exists — WMI + filesystem)
|
||||
# Guard 3: Bootstrap window expired (device uptime > 12h without agent)
|
||||
# Guard 4: Agent binary already present from a previous run
|
||||
# NOTE: OOBEInProgress is NOT used — it is unreliable (observed =0 during active enrollment).
|
||||
|
||||
# Guard 1: Agent was already deployed on this device (registry marker survives self-destruct)
|
||||
$deployed = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\AutopilotMonitor' -Name 'Deployed' -ErrorAction SilentlyContinue).Deployed
|
||||
@@ -123,15 +123,7 @@ try {
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Guard 2: Device must be in OOBE (= actively provisioning)
|
||||
$oobeInProgress = (Get-ItemProperty -Path 'HKLM:\SYSTEM\Setup' -Name 'OOBEInProgress' -ErrorAction SilentlyContinue).OOBEInProgress
|
||||
Write-Log "OOBEInProgress=$oobeInProgress"
|
||||
if ($oobeInProgress -ne 1) {
|
||||
Write-Log "SKIP: Device is not in OOBE (OOBEInProgress=$oobeInProgress). Not a fresh enrollment."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Guard 3: No real user profile should exist yet (catches stale OOBEInProgress on productive devices)
|
||||
# Guard 2: No real user profile should exist yet (primary productive-device guard)
|
||||
# Combines WMI (Win32_UserProfile.Special flag) and filesystem for maximum reliability.
|
||||
$excludePattern = '^(defaultuser\d*|Public|Default( User)?|All Users)$'
|
||||
|
||||
@@ -154,7 +146,7 @@ try {
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Guard 4: Bootstrap window check (ultra edge case: no key, OOBE stuck, no user profiles)
|
||||
# Guard 3: Bootstrap window check (no key, no user profiles, but device running too long)
|
||||
# NOT "how long may enrollment take" -- agent handles that internally (6h emergency break).
|
||||
# This is "how old can the OOBE state be before I no longer trust it for initial install".
|
||||
# 12h bootstrap window vs 6h agent emergency break = consistent layered approach.
|
||||
@@ -167,7 +159,7 @@ try {
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Guard 5: Is the agent already installed? (leftover from previous run)
|
||||
# Guard 4: Is the agent already installed? (leftover from previous run)
|
||||
if (Test-Path $AgentBinPath) {
|
||||
$existingAgent = Get-ChildItem -Path $AgentBinPath -Filter "AutopilotMonitor.Agent.exe" -ErrorAction SilentlyContinue
|
||||
if ($existingAgent) {
|
||||
|
||||
@@ -58,22 +58,13 @@ if ($deployed) {
|
||||
Write-Step -Status 'PASS' -Message 'Guard 1: No previous deployment marker found.'
|
||||
}
|
||||
|
||||
# Guard 2: Device must be in OOBE (= actively provisioning)
|
||||
$oobeInProgress = Get-RegistryValueSafe -Path 'HKLM:\SYSTEM\Setup' -Name 'OOBEInProgress'
|
||||
if ($oobeInProgress -ne 1) {
|
||||
Write-Step -Status 'SKIP' -Message "Guard 2: Device is not in OOBE (OOBEInProgress=$oobeInProgress). Not a fresh enrollment."
|
||||
$wouldInstall = $false
|
||||
$reasons.Add("Not in OOBE (OOBEInProgress=$oobeInProgress)")
|
||||
} else {
|
||||
Write-Step -Status 'PASS' -Message 'Guard 2: Device is in OOBE (OOBEInProgress=1).'
|
||||
}
|
||||
|
||||
# Guard 3: No real user profile should exist yet
|
||||
# Guard 2: No real user profile should exist yet (primary productive-device guard)
|
||||
# NOTE: OOBEInProgress is NOT used -- it is unreliable (observed =0 during active enrollment).
|
||||
$excludePattern = '^(defaultuser\d*|Public|Default( User)?|All Users)$'
|
||||
$wmiProfileQueryFailed = $false
|
||||
|
||||
$profileNames = @(
|
||||
# WMI/CIM view
|
||||
# WMI/CIM view -- Special flag reliably excludes SYSTEM/LocalService/NetworkService
|
||||
try {
|
||||
Get-CimInstance Win32_UserProfile -ErrorAction Stop |
|
||||
Where-Object {
|
||||
@@ -88,7 +79,7 @@ $profileNames = @(
|
||||
$wmiProfileQueryFailed = $true
|
||||
}
|
||||
|
||||
# Filesystem view
|
||||
# Filesystem view -- catches profiles WMI might miss
|
||||
(Get-ChildItem 'C:\Users' -Directory -ErrorAction SilentlyContinue).Name
|
||||
) |
|
||||
Where-Object {
|
||||
@@ -97,23 +88,23 @@ Where-Object {
|
||||
Select-Object -Unique
|
||||
|
||||
if ($wmiProfileQueryFailed) {
|
||||
Write-Step -Status 'WARN' -Message 'Guard 3: WMI profile query failed, filesystem check still applied.'
|
||||
Write-Step -Status 'WARN' -Message 'Guard 2: WMI profile query failed, filesystem check still applied.'
|
||||
}
|
||||
|
||||
if ($profileNames) {
|
||||
$names = ($profileNames | Select-Object -First 3) -join ', '
|
||||
Write-Step -Status 'SKIP' -Message "Guard 3: Real user profile(s) found ($names). Device appears productive."
|
||||
Write-Step -Status 'SKIP' -Message "Guard 2: Real user profile(s) found ($names). Device appears productive."
|
||||
$wouldInstall = $false
|
||||
$reasons.Add("Real user profile(s) found: $names")
|
||||
} else {
|
||||
Write-Step -Status 'PASS' -Message 'Guard 3: No real user profiles found (combined WMI/filesystem view).'
|
||||
Write-Step -Status 'PASS' -Message 'Guard 2: No real user profiles found (combined WMI/filesystem view).'
|
||||
}
|
||||
|
||||
# Guard 4: Bootstrap window check
|
||||
# NOT "how long may enrollment take" — agent handles that internally (6h emergency break).
|
||||
# Guard 3: Bootstrap window check
|
||||
# NOT "how long may enrollment take" -- agent handles that internally (6h emergency break).
|
||||
# This is "how old can the OOBE state be before I no longer trust it for initial install".
|
||||
# 12h bootstrap window vs 6h agent emergency break = consistent layered approach.
|
||||
# Sleep/standby does NOT reset uptime — only real boot/restart does.
|
||||
# Sleep/standby does NOT reset uptime -- only real boot/restart does.
|
||||
$lastBoot = $null
|
||||
$uptimeHours = $null
|
||||
|
||||
@@ -122,24 +113,24 @@ try {
|
||||
$uptimeHours = ((Get-Date) - $lastBoot).TotalHours
|
||||
|
||||
if ($uptimeHours -gt $MaxBootstrapWindowHours) {
|
||||
Write-Step -Status 'SKIP' -Message "Guard 4: Device uptime is $([int]$uptimeHours)h. OOBE state is older than accepted bootstrap window of ${MaxBootstrapWindowHours}h."
|
||||
Write-Step -Status 'SKIP' -Message "Guard 3: Device uptime is $([int]$uptimeHours)h. Older than accepted bootstrap window of ${MaxBootstrapWindowHours}h."
|
||||
$wouldInstall = $false
|
||||
$reasons.Add("Uptime exceeds bootstrap window: $([int]$uptimeHours)h > ${MaxBootstrapWindowHours}h")
|
||||
} else {
|
||||
Write-Step -Status 'PASS' -Message "Guard 4: Device uptime is $([int]$uptimeHours)h and within bootstrap window of ${MaxBootstrapWindowHours}h."
|
||||
Write-Step -Status 'PASS' -Message "Guard 3: Device uptime is $([int]$uptimeHours)h and within bootstrap window of ${MaxBootstrapWindowHours}h."
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Step -Status 'WARN' -Message 'Guard 4: Could not determine LastBootUpTime / uptime.'
|
||||
Write-Step -Status 'WARN' -Message 'Guard 3: Could not determine LastBootUpTime / uptime.'
|
||||
}
|
||||
|
||||
# Guard 5 (existing): Agent binary already present
|
||||
# Guard 4: Agent binary already present
|
||||
if (Test-Path $AgentExePath) {
|
||||
Write-Step -Status 'SKIP' -Message "Guard 5: Agent already installed at '$AgentExePath'."
|
||||
Write-Step -Status 'SKIP' -Message "Guard 4: Agent already installed at '$AgentExePath'."
|
||||
$wouldInstall = $false
|
||||
$reasons.Add("Agent binary already present: $AgentExePath")
|
||||
} else {
|
||||
Write-Step -Status 'PASS' -Message "Guard 5: Agent binary not present at '$AgentExePath'."
|
||||
Write-Step -Status 'PASS' -Message "Guard 4: Agent binary not present at '$AgentExePath'."
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
@@ -166,10 +157,9 @@ if ($reasons.Count -eq 0) {
|
||||
Write-Host ''
|
||||
Write-Host '=== Raw Values ==='
|
||||
Write-Host "Deployed marker : $deployed"
|
||||
Write-Host "OOBEInProgress : $oobeInProgress"
|
||||
Write-Host "MaxBootstrapWindowHours : $MaxBootstrapWindowHours"
|
||||
Write-Host "LastBootUpTime : $lastBoot"
|
||||
Write-Host "UptimeHours : $([string]$uptimeHours)"
|
||||
Write-Host "AgentExePath : $AgentExePath"
|
||||
Write-Host "DetectedProfileNames : $($profileNames -join ', ')"
|
||||
Write-Host ''
|
||||
Write-Host ''
|
||||
|
||||
Reference in New Issue
Block a user