Files
PatchProbe-Server/PatchProbe.Cli/Collectors/CbsDismCollector.cs
2026-05-25 10:29:38 +08:00

85 lines
2.9 KiB
C#

using System.Diagnostics;
using Microsoft.Extensions.Logging;
using PatchProbe.Shared.Contracts;
using PatchProbe.Shared.Models;
namespace PatchProbe.Cli.Collectors;
public sealed class CbsDismCollector(ILogger<CbsDismCollector> logger) : ICollector<List<CbsPackage>>
{
public async Task<List<CbsPackage>> CollectAsync(CancellationToken cancellationToken = default)
{
logger.LogInformation("Collecting CBS/DISM package state");
var packages = new List<CbsPackage>();
try
{
var output = await RunDismAsync(cancellationToken);
packages = ParseDismOutput(output);
logger.LogInformation("Collected {Count} CBS packages", packages.Count);
}
catch (Exception ex)
{
logger.LogWarning(ex, "CBS/DISM collection failed");
}
return packages;
}
private static async Task<string> RunDismAsync(CancellationToken cancellationToken)
{
var psi = new ProcessStartInfo
{
FileName = "dism.exe",
Arguments = "/Online /Get-Packages /Format:Table",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
};
using var process = Process.Start(psi) ?? throw new InvalidOperationException("Failed to start dism.exe");
var output = await process.StandardOutput.ReadToEndAsync(cancellationToken);
await process.WaitForExitAsync(cancellationToken);
return output;
}
private static List<CbsPackage> ParseDismOutput(string output)
{
var packages = new List<CbsPackage>();
var lines = output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
// Skip header lines; data rows contain "Package Identity" columns separated by spaces/pipes
bool inDataSection = false;
foreach (var line in lines)
{
var trimmed = line.Trim();
if (trimmed.StartsWith("Package Identity", StringComparison.OrdinalIgnoreCase))
{
inDataSection = true;
continue;
}
if (!inDataSection || string.IsNullOrWhiteSpace(trimmed) || trimmed.StartsWith('-'))
continue;
// DISM table output uses multiple spaces as column separator
var parts = System.Text.RegularExpressions.Regex.Split(trimmed, @"\s{2,}");
if (parts.Length >= 2)
{
packages.Add(new CbsPackage
{
PackageIdentity = parts[0].Trim(),
State = parts.Length > 1 ? parts[1].Trim() : null,
ReleaseType = parts.Length > 2 ? parts[2].Trim() : null,
InstallTime = parts.Length > 3 ? parts[3].Trim() : null,
});
}
}
return packages;
}
}