85 lines
2.9 KiB
C#
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;
|
|
}
|
|
}
|