using Microsoft.Win32; using System.Diagnostics; using System.Runtime.InteropServices; namespace TWASys_App.Models.ServerInfo { public record OsInfo(string Platform, string Name, string Version, string Kernel, string Architecture); public class OsInfoReader { public static OsInfo Get() { var arch = RuntimeInformation.OSArchitecture.ToString(); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return GetWindows(arch); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return GetLinux(arch); if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return GetMac(arch); return new OsInfo(RuntimeInformation.OSDescription, "Unknown", "Unknown", "Unknown", arch); } // ---------- Windows ---------- static OsInfo GetWindows(string arch) { string name = "Windows"; string version = "Unknown"; try { using var k = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"); var productName = k?.GetValue("ProductName")?.ToString(); var displayVer = k?.GetValue("DisplayVersion")?.ToString() ?? k?.GetValue("ReleaseId")?.ToString(); var build = k?.GetValue("CurrentBuildNumber")?.ToString(); var ubrObj = k?.GetValue("UBR"); var ubr = ubrObj is int i ? i.ToString() : ubrObj?.ToString(); name = productName ?? "Windows"; if (!string.IsNullOrWhiteSpace(build)) version = $"{(displayVer ?? "")}".Trim(); if (!string.IsNullOrWhiteSpace(build)) version = string.IsNullOrWhiteSpace(version) ? $"Build {build}.{ubr}" : $"{version} (Build {build}.{ubr})"; } catch { /* fallback below */ } var kernel = RuntimeInformation.OSDescription; // e.g. "Microsoft Windows 10.0.19045" return new OsInfo("Windows", name, version, kernel, arch); } // ---------- Linux ---------- static OsInfo GetLinux(string arch) { string name = "Linux"; string version = "Unknown"; try { var dict = ParseKeyValueFile("/etc/os-release"); // NAME, PRETTY_NAME, VERSION_ID... if (dict.TryGetValue("NAME", out var n)) name = TrimQuotes(n); if (dict.TryGetValue("PRETTY_NAME", out var pretty)) version = TrimQuotes(pretty); else if (dict.TryGetValue("VERSION", out var v)) version = TrimQuotes(v); else if (dict.TryGetValue("VERSION_ID", out var vid)) version = TrimQuotes(vid); } catch { /* ignore */ } var kernel = Run("uname", "-sr"); // e.g. "Linux 6.8.0-40-generic" if (string.IsNullOrWhiteSpace(kernel)) kernel = RuntimeInformation.OSDescription; return new OsInfo("Linux", name, version, kernel, arch); } // ---------- macOS ---------- static OsInfo GetMac(string arch) { var name = Run("sw_vers", "-productName"); // "macOS" var version = Run("sw_vers", "-productVersion"); // "14.6.1" if (string.IsNullOrWhiteSpace(name)) name = "macOS"; if (string.IsNullOrWhiteSpace(version)) version = "Unknown"; var kernel = Run("uname", "-sr"); // "Darwin 23.6.0" if (string.IsNullOrWhiteSpace(kernel)) kernel = RuntimeInformation.OSDescription; return new OsInfo("macOS", name.Trim(), version.Trim(), kernel.Trim(), arch); } // ---------- helpers ---------- static Dictionary ParseKeyValueFile(string path) { var d = new Dictionary(StringComparer.OrdinalIgnoreCase); if (!File.Exists(path)) return d; foreach (var raw in File.ReadAllLines(path)) { var line = raw.Trim(); if (line.Length == 0 || line.StartsWith("#")) continue; var i = line.IndexOf('='); if (i <= 0) continue; d[line[..i]] = line[(i + 1)..]; } return d; } static string TrimQuotes(string s) => s.Trim().Trim('"'); static string Run(string file, string args) { try { var p = new Process { StartInfo = new ProcessStartInfo { FileName = file, Arguments = args, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true } }; p.Start(); var s = p.StandardOutput.ReadToEnd().Trim(); p.WaitForExit(1500); return s; } catch { return ""; } } } }