mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 04:32:32 +00:00
177 lines
6.0 KiB
PowerShell
177 lines
6.0 KiB
PowerShell
# Autopilot Monitor Bootstrap Guard Test
|
|
# Dry-run only: does not exit, does not install, only reports what WOULD happen.
|
|
|
|
param(
|
|
[string]$AgentBinPath = 'C:\ProgramData\AutopilotMonitor\Agent'
|
|
)
|
|
|
|
$ErrorActionPreference = 'SilentlyContinue'
|
|
|
|
function Write-Step {
|
|
param(
|
|
[string]$Status,
|
|
[string]$Message
|
|
)
|
|
|
|
$prefix = switch ($Status) {
|
|
'PASS' { '[PASS]' }
|
|
'SKIP' { '[SKIP]' }
|
|
'WARN' { '[WARN]' }
|
|
'INFO' { '[INFO]' }
|
|
default { '[....]' }
|
|
}
|
|
|
|
Write-Host "$prefix $Message"
|
|
}
|
|
|
|
function Get-RegistryValueSafe {
|
|
param(
|
|
[string]$Path,
|
|
[string]$Name
|
|
)
|
|
|
|
try {
|
|
return (Get-ItemProperty -Path $Path -Name $Name -ErrorAction Stop).$Name
|
|
}
|
|
catch {
|
|
return $null
|
|
}
|
|
}
|
|
|
|
$AgentExePath = Join-Path $AgentBinPath 'AutopilotMonitor.Agent.exe'
|
|
$MaxBootstrapWindowHours = 12
|
|
|
|
$wouldInstall = $true
|
|
$reasons = New-Object System.Collections.Generic.List[string]
|
|
|
|
Write-Host ''
|
|
Write-Host '=== Autopilot Monitor Bootstrap Guard Test (Dry Run) ==='
|
|
Write-Host ''
|
|
|
|
# Guard 1: Agent was already deployed on this device (survives self-destruct)
|
|
$deployed = Get-RegistryValueSafe -Path 'HKLM:\SOFTWARE\AutopilotMonitor' -Name 'Deployed'
|
|
if ($deployed) {
|
|
Write-Step -Status 'SKIP' -Message "Guard 1: Agent was previously deployed at '$deployed'."
|
|
$wouldInstall = $false
|
|
$reasons.Add("Previously deployed marker exists: $deployed")
|
|
} else {
|
|
Write-Step -Status 'PASS' -Message 'Guard 1: No previous deployment marker found.'
|
|
}
|
|
|
|
# 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 -- Special flag reliably excludes SYSTEM/LocalService/NetworkService
|
|
try {
|
|
Get-CimInstance Win32_UserProfile -ErrorAction Stop |
|
|
Where-Object {
|
|
-not $_.Special -and
|
|
$_.LocalPath -like 'C:\Users\*'
|
|
} |
|
|
ForEach-Object {
|
|
Split-Path $_.LocalPath -Leaf
|
|
}
|
|
}
|
|
catch {
|
|
$wmiProfileQueryFailed = $true
|
|
}
|
|
|
|
# Filesystem view -- catches profiles WMI might miss
|
|
(Get-ChildItem 'C:\Users' -Directory -ErrorAction SilentlyContinue).Name
|
|
) |
|
|
Where-Object {
|
|
$_ -and $_ -notmatch $excludePattern
|
|
} |
|
|
Select-Object -Unique
|
|
|
|
if ($wmiProfileQueryFailed) {
|
|
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 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 2: No real user profiles found (combined WMI/filesystem view).'
|
|
}
|
|
|
|
# Guard 3: LastLoggedOnUser -- during Device ESP no real user has logged on yet
|
|
$lastLoggedOnUser = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI' -Name 'LastLoggedOnUser' -EA SilentlyContinue).LastLoggedOnUser
|
|
if ($lastLoggedOnUser -and $lastLoggedOnUser -notmatch 'defaultuser\d*') {
|
|
Write-Step -Status 'SKIP' -Message "Guard 3: LastLoggedOnUser found ($lastLoggedOnUser). Device appears productive."
|
|
$wouldInstall = $false
|
|
$reasons.Add("LastLoggedOnUser found: $lastLoggedOnUser")
|
|
} else {
|
|
Write-Step -Status 'PASS' -Message "Guard 3: No real LastLoggedOnUser (value: '$lastLoggedOnUser')."
|
|
}
|
|
|
|
# Guard 4: 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.
|
|
$lastBoot = $null
|
|
$uptimeHours = $null
|
|
|
|
try {
|
|
$lastBoot = (Get-CimInstance Win32_OperatingSystem -ErrorAction Stop).LastBootUpTime
|
|
$uptimeHours = ((Get-Date) - $lastBoot).TotalHours
|
|
|
|
if ($uptimeHours -gt $MaxBootstrapWindowHours) {
|
|
Write-Step -Status 'SKIP' -Message "Guard 4: 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."
|
|
}
|
|
}
|
|
catch {
|
|
Write-Step -Status 'WARN' -Message 'Guard 4: Could not determine LastBootUpTime / uptime.'
|
|
}
|
|
|
|
# Guard 4: Agent binary already present
|
|
if (Test-Path $AgentExePath) {
|
|
Write-Step -Status 'SKIP' -Message "Guard 5: 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-Host ''
|
|
Write-Host '=== Result ==='
|
|
Write-Host ''
|
|
|
|
if ($wouldInstall) {
|
|
Write-Host '[DECISION] WOULD INSTALL agent on this device.'
|
|
} else {
|
|
Write-Host '[DECISION] WOULD SKIP agent installation on this device.'
|
|
}
|
|
|
|
Write-Host ''
|
|
Write-Host '=== Summary ==='
|
|
|
|
if ($reasons.Count -eq 0) {
|
|
Write-Host 'No blocking reasons found.'
|
|
} else {
|
|
foreach ($reason in $reasons) {
|
|
Write-Host " - $reason"
|
|
}
|
|
}
|
|
|
|
Write-Host ''
|
|
Write-Host '=== Raw Values ==='
|
|
Write-Host "Deployed marker : $deployed"
|
|
Write-Host "DetectedProfileNames : $($profileNames -join ', ')"
|
|
Write-Host "LastLoggedOnUser : $lastLoggedOnUser"
|
|
Write-Host "MaxBootstrapWindowHours : $MaxBootstrapWindowHours"
|
|
Write-Host "LastBootUpTime : $lastBoot"
|
|
Write-Host "UptimeHours : $([string]$uptimeHours)"
|
|
Write-Host "AgentExePath : $AgentExePath"
|
|
Write-Host ''
|