533 lines
18 KiB
C#
533 lines
18 KiB
C#
using Microsoft.Win32;
|
|
using System.IO;
|
|
using System.Management;
|
|
using System.Diagnostics;
|
|
using System.Net.NetworkInformation;
|
|
using Newtonsoft.Json;
|
|
using System.Windows;
|
|
|
|
namespace LD_SysInfo
|
|
{
|
|
public class AppConfig
|
|
{
|
|
[JsonProperty("ServerUrl")]
|
|
public string ServerUrl { get; set; } = "https://yourserver.com/api/status";
|
|
|
|
[JsonProperty("EnableLogging")]
|
|
public bool EnableLogging { get; set; } = true;
|
|
|
|
[JsonProperty("KeepAlivePeriod")]
|
|
public int KeepAlivePeriod { get; set; } = 30; // Ping/heartbeat every 30 seconds
|
|
|
|
[JsonProperty("SystemInfoInterval")]
|
|
public int SystemInfoInterval { get; set; } = 60; // Full system info POST every 60 seconds
|
|
|
|
[JsonProperty("ClientIdentifier")]
|
|
public string ClientIdentifier { get; set; } = "your-default-client-id";
|
|
|
|
[JsonProperty("Auth")]
|
|
public AuthConfig Auth { get; set; } = new AuthConfig();
|
|
}
|
|
|
|
|
|
public class AuthConfig
|
|
{
|
|
[JsonProperty("Username")]
|
|
public string Username { get; set; } = "testuser";
|
|
|
|
[JsonProperty("Password")]
|
|
public string Password { get; set; } = "testpassword";
|
|
}
|
|
|
|
|
|
public static class ConfigManager
|
|
{
|
|
private static readonly string ConfigPath =
|
|
Path.Combine(AppContext.BaseDirectory, "config.json");
|
|
|
|
public static AppConfig LoadConfig(string configPath)
|
|
{
|
|
//System.Windows.MessageBox.Show($"[DEBUG] Calling LoadConfig from:\n{ConfigPath}");
|
|
|
|
if (File.Exists(ConfigPath))
|
|
{
|
|
string json = File.ReadAllText(ConfigPath);
|
|
return JsonConvert.DeserializeObject<AppConfig>(json);
|
|
}
|
|
|
|
throw new FileNotFoundException("❌ Config file not found at:\n" + ConfigPath);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public class InstalledApplication
|
|
{
|
|
public string Name { get; set; }
|
|
public string Version { get; set; }
|
|
public string Publisher { get; set; }
|
|
}
|
|
|
|
public class WindowsUpdate
|
|
{
|
|
[JsonProperty("hotFixID")]
|
|
public string HotFixID { get; set; }
|
|
|
|
[JsonProperty("description")]
|
|
public string Description { get; set; }
|
|
|
|
[JsonProperty("installedOn")]
|
|
public string InstalledOn { get; set; }
|
|
|
|
[JsonProperty("installedBy")]
|
|
public string InstalledBy { get; set; }
|
|
}
|
|
|
|
public class AppXPackage
|
|
{
|
|
[JsonProperty("name")]
|
|
public string Name { get; set; }
|
|
|
|
[JsonProperty("version")]
|
|
public string Version { get; set; }
|
|
|
|
[JsonProperty("publisher")]
|
|
public string Publisher { get; set; }
|
|
|
|
[JsonProperty("packageFullName")]
|
|
public string PackageFullName { get; set; }
|
|
}
|
|
|
|
public class DriveInfoSummary
|
|
{
|
|
[JsonProperty("name")]
|
|
public string Name { get; set; }
|
|
|
|
[JsonProperty("totalSizeGB")]
|
|
public double TotalSizeGB { get; set; }
|
|
|
|
[JsonProperty("freeSpaceGB")]
|
|
public double FreeSpaceGB { get; set; }
|
|
|
|
[JsonProperty("driveType")]
|
|
public string DriveType { get; set; }
|
|
}
|
|
|
|
public class NetworkInterfaceInfo
|
|
{
|
|
[JsonProperty("interfaceName")]
|
|
public string InterfaceName { get; set; }
|
|
|
|
[JsonProperty("ipAddress")]
|
|
public string IpAddress { get; set; }
|
|
|
|
[JsonProperty("macAddress")]
|
|
public string MacAddress { get; set; }
|
|
}
|
|
|
|
|
|
public class SystemInfo
|
|
{
|
|
[JsonProperty("osName")]
|
|
public string OSName { get; set; }
|
|
|
|
[JsonProperty("osVersion")]
|
|
public string OSVersion { get; set; }
|
|
|
|
[JsonProperty("windowsVersion")]
|
|
public string WindowsVersion { get; set; }
|
|
|
|
[JsonProperty("windowsBuild")]
|
|
public string WindowsBuild { get; set; }
|
|
|
|
[JsonProperty("osArchitecture")]
|
|
public string OSArchitecture { get; set; }
|
|
|
|
[JsonProperty("processorName")]
|
|
public string ProcessorName { get; set; }
|
|
|
|
[JsonProperty("processorArchitecture")]
|
|
public string ProcessorArchitecture { get; set; }
|
|
|
|
[JsonProperty("hostname")]
|
|
public string Hostname { get; set; }
|
|
|
|
[JsonProperty("gpuNames")]
|
|
public List<string> GpuNames { get; set; }
|
|
|
|
[JsonProperty("totalMemory")]
|
|
public string TotalMemory { get; set; }
|
|
|
|
[JsonProperty("ipAddresses")]
|
|
public List<NetworkInterfaceInfo> IpAddresses { get; set; } = new();
|
|
|
|
[JsonProperty("lastBootTime")]
|
|
public string LastBootTime { get; set; }
|
|
|
|
[JsonProperty("collectedAt")]
|
|
public string CollectedAt { get; set; }
|
|
|
|
[JsonProperty("installedApplications")]
|
|
public List<InstalledApplication> InstalledApplications { get; set; }
|
|
|
|
[JsonProperty("userInstalledApplications")]
|
|
public List<InstalledApplication> UserInstalledApplications { get; set; } = new();
|
|
|
|
[JsonProperty("windowsUpdates")]
|
|
public List<WindowsUpdate> WindowsUpdates { get; set; } = new();
|
|
|
|
[JsonProperty("appXPackages")]
|
|
public List<AppXPackage> AppXPackages { get; set; } = new();
|
|
|
|
[JsonProperty("drives")]
|
|
public List<DriveInfoSummary> Drives { get; set; } = new();
|
|
|
|
|
|
private const string WindowsCurrentVersionKey = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion";
|
|
|
|
public static SystemInfo GetSystemInfo()
|
|
{
|
|
var sysInfo = new SystemInfo();
|
|
|
|
try
|
|
{
|
|
// Capture collection timestamp with timezone info
|
|
sysInfo.CollectedAt = DateTimeOffset.Now.ToString("o");
|
|
|
|
sysInfo.Hostname = Environment.MachineName;
|
|
sysInfo.OSName = GetOSFriendlyName();
|
|
sysInfo.OSVersion = Environment.OSVersion.Version.ToString();
|
|
sysInfo.WindowsVersion = GetRegistryValue(WindowsCurrentVersionKey, "DisplayVersion");
|
|
sysInfo.WindowsBuild = GetRegistryValue(WindowsCurrentVersionKey, "CurrentBuild");
|
|
sysInfo.OSArchitecture = Environment.Is64BitOperatingSystem ? "x64" : "x86";
|
|
sysInfo.ProcessorName = GetProcessorName();
|
|
sysInfo.ProcessorArchitecture = Environment.Is64BitProcess ? "x64" : "x86";
|
|
sysInfo.GpuNames = GetGpuNames();
|
|
sysInfo.TotalMemory = GetTotalMemory();
|
|
var allInterfaces = GetNetworkInterfaces();
|
|
sysInfo.IpAddresses = allInterfaces
|
|
.Where(i => !string.IsNullOrWhiteSpace(i.InterfaceName))
|
|
.ToList();
|
|
sysInfo.LastBootTime = GetLastBootTime();
|
|
|
|
PopulateDriveInfo(sysInfo);
|
|
|
|
// Populate new collections for comprehensive system information
|
|
sysInfo.UserInstalledApplications = GetUserInstalledApplications();
|
|
sysInfo.WindowsUpdates = GetInstalledPatches();
|
|
sysInfo.AppXPackages = GetAppXPackages();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "LD_SysInfo", "SysInfo_ErrorLog.txt");
|
|
Directory.CreateDirectory(Path.GetDirectoryName(logPath));
|
|
File.AppendAllText(logPath, $"[{DateTime.Now}] ERROR: {ex.Message}\n");
|
|
}
|
|
|
|
return sysInfo;
|
|
}
|
|
|
|
private static void PopulateDriveInfo(SystemInfo info)
|
|
{
|
|
foreach (var drive in DriveInfo.GetDrives())
|
|
{
|
|
if (!drive.IsReady) continue;
|
|
|
|
info.Drives.Add(new DriveInfoSummary
|
|
{
|
|
Name = drive.Name,
|
|
TotalSizeGB = Math.Round(drive.TotalSize / (1024.0 * 1024 * 1024), 2),
|
|
FreeSpaceGB = Math.Round(drive.AvailableFreeSpace / (1024.0 * 1024 * 1024), 2),
|
|
DriveType = drive.DriveType.ToString()
|
|
});
|
|
}
|
|
}
|
|
|
|
private static string GetRegistryValue(string key, string valueName)
|
|
{
|
|
using RegistryKey rk = Registry.LocalMachine.OpenSubKey(key);
|
|
return rk?.GetValue(valueName)?.ToString();
|
|
}
|
|
|
|
private static string GetOSFriendlyName()
|
|
{
|
|
string productName = GetRegistryValue(WindowsCurrentVersionKey, "ProductName");
|
|
string build = GetRegistryValue(WindowsCurrentVersionKey, "CurrentBuild");
|
|
|
|
if (int.TryParse(build, out int buildNumber) && buildNumber >= 22000)
|
|
return "Windows 11 Pro";
|
|
|
|
return productName ?? "Unknown OS";
|
|
}
|
|
|
|
private static string GetProcessorName()
|
|
{
|
|
const string key = @"HARDWARE\DESCRIPTION\System\CentralProcessor\0";
|
|
return GetRegistryValue(key, "ProcessorNameString");
|
|
}
|
|
|
|
private static List<string> GetGpuNames()
|
|
{
|
|
var gpuNames = new List<string>();
|
|
|
|
try
|
|
{
|
|
using var searcher = new ManagementObjectSearcher("SELECT Name FROM Win32_VideoController");
|
|
|
|
foreach (var obj in searcher.Get())
|
|
{
|
|
string name = obj["Name"]?.ToString();
|
|
if (!string.IsNullOrEmpty(name))
|
|
{
|
|
gpuNames.Add(name);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
gpuNames.Add($"Error: {ex.Message}");
|
|
}
|
|
|
|
return gpuNames;
|
|
}
|
|
|
|
|
|
private static string GetTotalMemory()
|
|
{
|
|
try
|
|
{
|
|
using var searcher = new ManagementObjectSearcher("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem");
|
|
foreach (var obj in searcher.Get())
|
|
{
|
|
long bytes = Convert.ToInt64(obj["TotalPhysicalMemory"]);
|
|
return $"{bytes / (1024 * 1024)} MB";
|
|
}
|
|
}
|
|
catch { }
|
|
return null;
|
|
}
|
|
|
|
private static List<NetworkInterfaceInfo> GetNetworkInterfaces()
|
|
{
|
|
var interfaces = new List<NetworkInterfaceInfo>();
|
|
|
|
try
|
|
{
|
|
foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces())
|
|
{
|
|
if (adapter.OperationalStatus != OperationalStatus.Up) continue;
|
|
|
|
var ip = adapter.GetIPProperties().UnicastAddresses
|
|
.FirstOrDefault(a => a.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
|
|
|
|
var mac = adapter.GetPhysicalAddress();
|
|
var macAddress = mac?.GetAddressBytes().Length > 0
|
|
? string.Join(":", mac.GetAddressBytes().Select(b => b.ToString("X2")))
|
|
: null;
|
|
|
|
if (ip != null || macAddress != null)
|
|
{
|
|
interfaces.Add(new NetworkInterfaceInfo
|
|
{
|
|
InterfaceName = adapter.Name,
|
|
IpAddress = ip?.Address.ToString(),
|
|
MacAddress = macAddress
|
|
});
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"❌ Failed to gather network interfaces: {ex.Message}");
|
|
}
|
|
|
|
return interfaces;
|
|
}
|
|
|
|
|
|
private static string GetLastBootTime()
|
|
{
|
|
try
|
|
{
|
|
using var searcher = new ManagementObjectSearcher("SELECT LastBootUpTime FROM Win32_OperatingSystem WHERE Primary='true'");
|
|
foreach (var obj in searcher.Get())
|
|
{
|
|
string lastBoot = obj["LastBootUpTime"]?.ToString();
|
|
// Convert to local time and ensure timezone info is preserved
|
|
DateTime localBootTime = ManagementDateTimeConverter.ToDateTime(lastBoot);
|
|
// Use DateTimeOffset to ensure timezone information is included
|
|
DateTimeOffset bootTimeWithZone = new DateTimeOffset(localBootTime, TimeZoneInfo.Local.GetUtcOffset(localBootTime));
|
|
return bootTimeWithZone.ToString("o");
|
|
}
|
|
}
|
|
catch { }
|
|
return null;
|
|
}
|
|
|
|
public static List<InstalledApplication> GetInstalledApplicationsFromRegistry()
|
|
{
|
|
var applications = new List<InstalledApplication>();
|
|
string[] registryKeys = {
|
|
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
|
|
@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
|
|
};
|
|
|
|
foreach (string key in registryKeys)
|
|
{
|
|
using var regKey = Registry.LocalMachine.OpenSubKey(key);
|
|
if (regKey == null) continue;
|
|
|
|
foreach (string subKeyName in regKey.GetSubKeyNames())
|
|
{
|
|
using var subKey = regKey.OpenSubKey(subKeyName);
|
|
string name = subKey?.GetValue("DisplayName")?.ToString();
|
|
if (!string.IsNullOrWhiteSpace(name))
|
|
{
|
|
applications.Add(new InstalledApplication
|
|
{
|
|
Name = name,
|
|
Version = subKey?.GetValue("DisplayVersion")?.ToString(),
|
|
Publisher = subKey?.GetValue("Publisher")?.ToString()
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return applications;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets user-context installed applications from HKEY_CURRENT_USER registry.
|
|
/// </summary>
|
|
public static List<InstalledApplication> GetUserInstalledApplications()
|
|
{
|
|
var applications = new List<InstalledApplication>();
|
|
string registryKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall";
|
|
|
|
try
|
|
{
|
|
using var regKey = Registry.CurrentUser.OpenSubKey(registryKey);
|
|
if (regKey == null) return applications;
|
|
|
|
foreach (string subKeyName in regKey.GetSubKeyNames())
|
|
{
|
|
using var subKey = regKey.OpenSubKey(subKeyName);
|
|
string name = subKey?.GetValue("DisplayName")?.ToString();
|
|
if (!string.IsNullOrWhiteSpace(name))
|
|
{
|
|
applications.Add(new InstalledApplication
|
|
{
|
|
Name = name,
|
|
Version = subKey?.GetValue("DisplayVersion")?.ToString(),
|
|
Publisher = subKey?.GetValue("Publisher")?.ToString()
|
|
});
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"❌ Failed to gather user-installed applications: {ex.Message}");
|
|
}
|
|
|
|
return applications;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets Windows Updates and patches installed on the system using WMI.
|
|
/// </summary>
|
|
public static List<WindowsUpdate> GetInstalledPatches()
|
|
{
|
|
var patches = new List<WindowsUpdate>();
|
|
|
|
try
|
|
{
|
|
using var searcher = new ManagementObjectSearcher(
|
|
"SELECT HotFixID, Description, InstalledOn, InstalledBy FROM Win32_QuickFixEngineering");
|
|
|
|
foreach (var obj in searcher.Get())
|
|
{
|
|
patches.Add(new WindowsUpdate
|
|
{
|
|
HotFixID = obj["HotFixID"]?.ToString(),
|
|
Description = obj["Description"]?.ToString(),
|
|
InstalledOn = obj["InstalledOn"]?.ToString(),
|
|
InstalledBy = obj["InstalledBy"]?.ToString()
|
|
});
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"❌ Failed to gather Windows Updates: {ex.Message}");
|
|
}
|
|
|
|
return patches;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets Windows Store (AppX) packages installed on the system using WMI.
|
|
/// Note: This may require elevated permissions for complete results.
|
|
/// </summary>
|
|
public static List<AppXPackage> GetAppXPackages()
|
|
{
|
|
var packages = new List<AppXPackage>();
|
|
|
|
try
|
|
{
|
|
// Try using Win32_InstalledStoreProgram (Windows 10+)
|
|
using var searcher = new ManagementObjectSearcher(
|
|
"SELECT Name, Version, Publisher FROM Win32_InstalledStoreProgram");
|
|
|
|
foreach (var obj in searcher.Get())
|
|
{
|
|
var name = obj["Name"]?.ToString();
|
|
if (!string.IsNullOrWhiteSpace(name))
|
|
{
|
|
packages.Add(new AppXPackage
|
|
{
|
|
Name = name,
|
|
Version = obj["Version"]?.ToString(),
|
|
Publisher = obj["Publisher"]?.ToString(),
|
|
PackageFullName = name // Win32_InstalledStoreProgram doesn't provide PackageFullName
|
|
});
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"❌ Failed to gather AppX packages: {ex.Message}");
|
|
}
|
|
|
|
return packages;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a specific Windows Update patch is installed on the system.
|
|
/// </summary>
|
|
/// <param name="kbNumber">The KB number to check (e.g., "KB5034441")</param>
|
|
/// <returns>True if the patch is installed, false otherwise</returns>
|
|
public static bool IsPatchInstalled(string kbNumber)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(kbNumber))
|
|
return false;
|
|
|
|
try
|
|
{
|
|
// Normalize KB number format
|
|
string normalizedKB = kbNumber.ToUpper().Trim();
|
|
if (!normalizedKB.StartsWith("KB"))
|
|
normalizedKB = "KB" + normalizedKB;
|
|
|
|
using var searcher = new ManagementObjectSearcher(
|
|
$"SELECT HotFixID FROM Win32_QuickFixEngineering WHERE HotFixID = '{normalizedKB}'");
|
|
|
|
return searcher.Get().Count > 0;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"❌ Failed to check patch {kbNumber}: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|