using Microsoft.Extensions.Logging; using Microsoft.Win32; using PatchProbe.Shared.Contracts; using PatchProbe.Shared.Models; namespace PatchProbe.Cli.Collectors; public sealed class PendingRebootCollector(ILogger logger) : ICollector { public Task CollectAsync(CancellationToken cancellationToken = default) { logger.LogInformation("Collecting pending reboot indicators"); var info = new PendingRebootInfo { CbsRebootPending = KeyExists(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending") || KeyExists(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress"), WindowsUpdateRebootRequired = KeyExists(@"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired"), SessionManagerRebootRequired = HasPendingFileRenameOperations(), ComputerRenameRequired = HasPendingComputerRename(), }; logger.LogInformation("Pending reboot: {AnyPending} (CBS={Cbs}, WU={Wu}, SessionMgr={Sm}, Rename={Rename})", info.AnyPending, info.CbsRebootPending, info.WindowsUpdateRebootRequired, info.SessionManagerRebootRequired, info.ComputerRenameRequired); return Task.FromResult(info); } private static bool KeyExists(string subKeyPath) { try { using var key = Registry.LocalMachine.OpenSubKey(subKeyPath); return key != null; } catch { return false; } } private static bool HasPendingFileRenameOperations() { try { using var key = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Session Manager"); var value = key?.GetValue("PendingFileRenameOperations"); if (value is string[] arr) return arr.Length > 0; } catch { } return false; } private static bool HasPendingComputerRename() { try { using var key = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName"); using var pendingKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName"); var active = key?.GetValue("ComputerName")?.ToString(); var pending = pendingKey?.GetValue("ComputerName")?.ToString(); return !string.Equals(active, pending, StringComparison.OrdinalIgnoreCase); } catch { return false; } } }