mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 20:53:06 +00:00
3016c15919
Bridges the OOBE / hybrid-AAD-join race window where the agent fires before AADTenantID / CloudDomainJoin\TenantInfo are written to the registry. Field evidence (GardnerMedia, 2026-04-30): the agent fired ~5 minutes before the AAD device cert landed; an event-driven wait of 10 minutes recovers the run instead of bailing and waiting for next reboot. Mechanism (V2 only — V1 keeps the fast-fail path): * New TenantIdAwaiter.WaitForTenantId(timeoutSec, logger, ct) sets up a CompositeRegistryChangeSignal over HKLM\SOFTWARE\Microsoft\Enrollments and HKLM\SYSTEM\...\CloudDomainJoin (Registry64 view, recursive, Name+LastSet+ThreadAgnostic filter), re-probes silently on every change, and returns the resolved TenantId or null on timeout. * 30 s belt-and-suspenders periodic re-probe protects against a missed RegNotifyChangeKeyValue notification. * 100 ms debounce after each signal so multi-value enrollment transactions land before the re-probe. Configuration: * Opt-in via --tenant-id-wait <sec>. Default 0 = no wait (legacy fast-fail). The PS1 bootstrap script owns the production default; the agent itself never assumes one. * CLI value persisted to bootstrap-config.json by --install so the Scheduled Task picks it up on each restart. * Install-AutopilotMonitor-v2.ps1 sets $tenantIdWaitSec = 600. Admins override per tenant by editing this single line and re-deploying. Testability: * IRegistryChangeSignal abstraction lets unit tests drive the loop with a fake signal and scripted probe — 8 deterministic cases cover timeout, signal hit, multi-signal, cancellation, periodic re-probe, whitespace/empty/null handling, zero-timeout short-circuit, and argument validation. * RegistryWatcherIntegrationTests exercise the real Win32 plumbing (RegNotifyChangeKeyValue → Changed event) against HKCU so no elevation is required and the test runs in standard CI. * Both classes opt out of xUnit parallelisation — the timing-sensitive Thread.Sleep handshakes are unreliable on a busy parallel pool. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>