Files
psg-oversight-app/LD-SysInfo/Services/PatchComplianceTask.cs
sonderau d880ebeedb Migration to a ServiceWorker for most tasks.
Implementation of basic PatchComplianceTask. First real iteration, basic/raw asf.
2025-11-04 13:55:04 +08:00

133 lines
4.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace LD_SysInfo.Services
{
/// <summary>
/// Scheduled task that collects Windows update history using osquery
/// and sends it to the backend API
/// </summary>
public class PatchComplianceTask : ScheduledTask
{
private readonly AppConfig _config;
private readonly ApiClient _apiClient;
public override string TaskName => "PatchCompliance";
public override TimeSpan Interval =>
TimeSpan.FromHours(_config.PatchCompliance.CheckIntervalHours);
public PatchComplianceTask(AppConfig config, ApiClient apiClient)
{
_config = config;
_apiClient = apiClient;
// Initialize LastRun from config if available
LastRun = _config.PatchCompliance.LastCheckTime;
}
public override bool ShouldRun()
{
// Don't run if disabled in config
if (!_config.PatchCompliance.Enabled)
return false;
return base.ShouldRun();
}
public override async Task ExecuteAsync()
{
try
{
// Query windows_update_history from osquery
var updates = OsqueryService.Query(@"
SELECT
date,
title,
update_id
FROM windows_update_history
ORDER BY date DESC;
");
if (!updates.Any())
{
LogInfo("No Windows update history found.");
return;
}
// Transform to API-friendly format
var patchData = updates.Select(u => new
{
date = u.GetValueOrDefault("date"),
title = u.GetValueOrDefault("title"),
updateId = u.GetValueOrDefault("update_id")
}).ToList();
LogInfo($"Collected {patchData.Count} Windows updates.");
// Send to API
await _apiClient.PostPatchComplianceAsync(patchData);
// Update config with last check time
_config.PatchCompliance.LastCheckTime = DateTime.Now;
SaveConfig();
LogInfo("Patch compliance data sent successfully.");
}
catch (Exception ex)
{
LogError($"PatchComplianceTask failed: {ex.Message}");
throw;
}
}
private void SaveConfig()
{
try
{
var configPath = System.IO.Path.Combine(AppContext.BaseDirectory, "config.json");
var json = Newtonsoft.Json.JsonConvert.SerializeObject(_config, Newtonsoft.Json.Formatting.Indented);
System.IO.File.WriteAllText(configPath, json);
}
catch (Exception ex)
{
LogError($"Failed to save config: {ex.Message}");
}
}
private void LogInfo(string message)
{
if (!_config.EnableLogging) return;
try
{
var logDir = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"PSG-Oversight"
);
System.IO.Directory.CreateDirectory(logDir);
var logPath = System.IO.Path.Combine(logDir, "patch_compliance.log");
System.IO.File.AppendAllText(logPath, $"[{DateTime.Now}] INFO: {message}\n");
}
catch { }
}
private void LogError(string message)
{
try
{
var logDir = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"PSG-Oversight"
);
System.IO.Directory.CreateDirectory(logDir);
var logPath = System.IO.Path.Combine(logDir, "patch_compliance.log");
System.IO.File.AppendAllText(logPath, $"[{DateTime.Now}] ERROR: {message}\n");
}
catch { }
}
}
}