# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Build ```bash # Debug build dotnet build PatchProbe.Cli/PatchProbe.Cli.csproj # Self-contained single-file win-x64 release dotnet publish PatchProbe.Cli/PatchProbe.Cli.csproj -c Release # Output: PatchProbe.Cli/bin/Release/net10.0-windows/win-x64/publish/PatchProbe.exe ``` ## Run ```bash # Collect evidence, write JSON to output/ directory PatchProbe.exe scan # Write payload to a specific path PatchProbe.exe scan --output C:\temp\scan.json # Collect but print JSON to stdout instead of uploading PatchProbe.exe scan --no-upload ``` Note: must be run as administrator for full data access (WUA, event logs, WMI). --- # Project Overview I am building a Windows patch-management evidence collection and orchestration platform similar in concept to the patch-management component of major RMM tools. The goal is NOT to replace Windows Update Agent (WUA), CBS, DISM, or the Windows driver-selection stack. Instead, the platform should act as a centralized control plane that: * collects patch-related evidence from endpoints * evaluates compliance * manages policy/rings/approvals * eventually orchestrates installations * reports status and failures Windows itself remains authoritative for: * update applicability * prerequisites * supersedence * CBS/component servicing logic * driver matching/ranking * installation success/failure The collector should be: * portable * standalone * self-contained * executable as administrator * non-persistent * non-installed * safe/read-only initially The first milestone is NOT patch installation. The first milestone is proving that a one-shot executable can collect equivalent patch-management evidence to what an RMM platform sees. --- # Current State I have already: * created a new C# Console App * selected .NET 9 * chosen a self-contained single-file EXE architecture The collector executable should eventually be called: ```text PatchProbe.exe ``` --- # Architecture Requirements The application should use: * C# * .NET 9 * Generic Host * Dependency Injection * HttpClientFactory * Structured logging * Clean collector/service architecture The project should remain a console application. Do NOT use: * WinForms * WPF * ASP.NET * Worker Service * MAUI The collector flow is: ```text PatchProbe.exe → collect evidence → serialize to JSON → upload to backend → exit ``` The collector should not: * install updates * download updates * modify policy * create scheduled tasks * register services * persist locally beyond optional logs/cache --- # Desired Solution Structure The solution should be scaffolded approximately like this: ```text PatchProbe.sln │ ├── PatchProbe.Cli/ │ ├── Program.cs │ ├── Collectors/ │ ├── Models/ │ ├── Services/ │ └── Utils/ │ ├── PatchProbe.Shared/ │ ├── Models/ │ ├── Contracts/ │ └── Serialization/ │ └── PatchProbe.Engine.Contracts/ ├── ApiModels/ └── Versioning/ ``` Even if some projects begin mostly empty. --- # NuGet Packages To Use Immediately add: ```bash dotnet add package System.Management dotnet add package Serilog dotnet add package Serilog.Sinks.Console dotnet add package Serilog.Sinks.File dotnet add package System.CommandLine dotnet add package Microsoft.Extensions.Hosting dotnet add package Microsoft.Extensions.DependencyInjection dotnet add package Microsoft.Extensions.Http ``` --- # Program.cs Architecture Use Generic Host architecture. Example direction: ```csharp using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Serilog; var builder = Host.CreateApplicationBuilder(args); Log.Logger = new LoggerConfiguration() .WriteTo.Console() .WriteTo.File("logs/patchprobe.log") .CreateLogger(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); var host = builder.Build(); var deviceCollector = host.Services.GetRequiredService(); var wuCollector = host.Services.GetRequiredService(); var device = await deviceCollector.CollectAsync(); var updates = await wuCollector.CollectAsync(); Console.WriteLine("Collection complete."); ``` Maintain proper layering and separation of concerns. --- # Core Philosophy Treat collected data as immutable evidence. Meaning: ```text PatchProbe scan = factual snapshot ``` NOT: * interpreted state * compliance judgment * install decisions Those belong in the backend engine later. The backend evaluates: * policy * compliance * approval * orchestration * ring logic The collector only gathers evidence. --- # Windows Patch-Management Philosophy The engine does NOT replace: * Windows Update Agent * CBS * TrustedInstaller * DISM * Windows driver ranking Instead: ```text The platform provides: - policy - scheduling - approvals - maintenance windows - telemetry - compliance reporting - failure classification - orchestration Windows provides: - applicability - prerequisites - supersedence - servicing logic - driver selection - install success/failure ``` --- # Required Initial Collectors Implement collectors in this approximate order. ## 1. DeviceCollector Collect: * hostname * manufacturer * model * serial number * BIOS version * BIOS date * TPM presence/version * RAM * domain/workgroup * system type Use: * WMI/CIM * registry * environment info --- ## 2. OsCollector Collect: * ProductName * EditionID * DisplayVersion * ReleaseId * Build number * UBR * architecture * install date * last boot Registry path: ```text HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion ``` --- ## 3. WindowsUpdateCollector This is the core component. Use WUA COM APIs. Use: * Microsoft.Update.Session * CreateUpdateSearcher() Collect: * applicable updates * update titles * KB IDs * categories * severity * reboot requirements * WUA result codes * update history * WU source/policy state Search criteria: ```text IsInstalled=0 and IsHidden=0 ``` Use COM interop or dynamic COM access. Example direction: ```csharp Type sessionType = Type.GetTypeFromProgID("Microsoft.Update.Session"); dynamic session = Activator.CreateInstance(sessionType); dynamic searcher = session.CreateUpdateSearcher(); dynamic result = searcher.Search("IsInstalled=0 and IsHidden=0"); ``` The collector should ask Windows what is applicable rather than attempting to independently determine applicability. --- # Important Patch-Management Concepts Windows decides: * whether an update is applicable * whether prerequisites are met * supersedence * CBS/component servicing logic * driver ranking/matching * installation success The platform should observe and orchestrate, not replace these systems. --- # 4. PendingRebootCollector Collect pending reboot indicators from: * CBS * Windows Update * Session Manager * Computer rename state Registry locations include: ```text HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager ``` --- # 5. DriverCollector Collect: * device name * driver version * manufacturer * INF name * hardware IDs * device class * driver date Use: * Win32_PnPSignedDriver * pnputil where useful Important: Do NOT attempt to replace Windows driver ranking logic. --- # 6. CBS / DISM Collector Collect: * package state * servicing state * DISM package output Use: ```text dism /online /get-packages /format:table ``` Treat CBS as the servicing authority. --- # 7. Windows Update Policy Collector Collect policy/configuration from: * WSUS * WUfB * AU settings * deferrals Registry paths include: ```text HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings ``` --- # 8. Event Collector Collect recent relevant events from: * System * Microsoft-Windows-WindowsUpdateClient/Operational * Microsoft-Windows-UpdateOrchestrator/Operational Focus on: * failures * installs * servicing issues * reboot events --- # Payload Design The collector should produce a JSON payload approximately shaped like: ```json { "schemaVersion": "0.1", "collector": {}, "device": {}, "os": {}, "pendingReboot": {}, "windowsUpdate": { "applicableUpdates": [], "history": [], "policy": {} }, "installedHotfixes": [], "cbsPackages": [], "drivers": [], "recentUpdateEvents": [] } ``` This payload should be treated as immutable evidence. --- # CLI Shape The executable should eventually support: ```text PatchProbe.exe scan PatchProbe.exe upload PatchProbe.exe export PatchProbe.exe debug PatchProbe.exe validate ``` Initially only implement: ```text PatchProbe.exe scan ``` --- # Publishing Requirements The application should be published as: * self-contained * single-file * win-x64 executable Example publish command: ```bash dotnet publish ^ -c Release ^ -r win-x64 ^ --self-contained true ^ -p:PublishSingleFile=true ^ -p:EnableCompressionInSingleFile=true ``` Result: * one EXE * no installed runtime dependency --- # Important Design Constraints Do NOT: * tightly couple collection and analysis * tightly couple collection and orchestration * make compliance decisions in the collector Maintain: ```text Collector → evidence payload Backend → analysis/policy/compliance Frontend → visualization/reporting ``` --- # Future Evolution Path The architecture should naturally evolve into: ```text Phase 1: One-shot evidence collector Phase 2: Scheduled execution Phase 3: Patch orchestration Phase 4: Remediation engine Phase 5: Approval rings/policies Phase 6: Full RMM-style patch-management platform ``` --- # Current Request Based on all of the above: * scaffold the initial project architecture * implement the first collectors * implement payload models * implement logging * implement WUA scanning * implement JSON serialization * implement upload abstraction * implement clean DI architecture * implement a production-quality starting structure suitable for future expansion