mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 12:42:38 +00:00
fixed OS info in sessions table
This commit is contained in:
+16
-15
@@ -7,6 +7,7 @@ using System.Net.NetworkInformation;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using AutopilotMonitor.Agent.Core.Logging;
|
||||
using AutopilotMonitor.Agent.Core.Monitoring.Core;
|
||||
using AutopilotMonitor.Shared.Models;
|
||||
using Microsoft.Win32;
|
||||
|
||||
@@ -138,27 +139,27 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Collectors
|
||||
// Emit os_info event
|
||||
try
|
||||
{
|
||||
// Read individual registry values; reuse DeviceInfoProvider helpers where possible
|
||||
var edition = (Registry.GetValue(RegKeyWindowsCurrentVersion, "EditionID", string.Empty) ?? string.Empty).ToString();
|
||||
var compositionEdition = (Registry.GetValue(RegKeyWindowsCurrentVersion, "CompositionEditionID", string.Empty) ?? string.Empty).ToString();
|
||||
var currentBuild = (Registry.GetValue(RegKeyWindowsCurrentVersion, "CurrentBuild", string.Empty) ?? string.Empty).ToString();
|
||||
var buildBranch = (Registry.GetValue(RegKeyWindowsCurrentVersion, "BuildBranch", string.Empty) ?? string.Empty).ToString();
|
||||
var displayVersion = DeviceInfoProvider.GetOsDisplayVersion();
|
||||
var buildRevision = (Registry.GetValue(RegKeyWindowsCurrentVersion, "UBR", string.Empty) ?? string.Empty).ToString();
|
||||
|
||||
var data = new Dictionary<string, object>
|
||||
{
|
||||
{ "version", Environment.OSVersion.Version.ToString() },
|
||||
{ "osVersion", osName },
|
||||
{ "edition", (Registry.GetValue(RegKeyWindowsCurrentVersion, "EditionID", string.Empty) ?? string.Empty).ToString() },
|
||||
{ "compositionEdition", (Registry.GetValue(RegKeyWindowsCurrentVersion, "CompositionEditionID", string.Empty) ?? string.Empty).ToString() },
|
||||
{ "currentBuild", (Registry.GetValue(RegKeyWindowsCurrentVersion, "CurrentBuild", string.Empty) ?? string.Empty).ToString() },
|
||||
{ "buildBranch", (Registry.GetValue(RegKeyWindowsCurrentVersion, "BuildBranch", string.Empty) ?? string.Empty).ToString() },
|
||||
{ "displayVersion", (Registry.GetValue(RegKeyWindowsCurrentVersion, "DisplayVersion", string.Empty) ?? string.Empty).ToString() },
|
||||
{ "buildRevision", (Registry.GetValue(RegKeyWindowsCurrentVersion, "UBR", string.Empty) ?? string.Empty).ToString() }
|
||||
{ "edition", edition },
|
||||
{ "compositionEdition", compositionEdition },
|
||||
{ "currentBuild", currentBuild },
|
||||
{ "buildBranch", buildBranch },
|
||||
{ "displayVersion", displayVersion },
|
||||
{ "buildRevision", buildRevision }
|
||||
};
|
||||
|
||||
object osVersionValue;
|
||||
object displayVersionValue;
|
||||
object currentBuildValue;
|
||||
object buildRevisionValue;
|
||||
|
||||
var osVersion = data.TryGetValue("osVersion", out osVersionValue) ? osVersionValue?.ToString() ?? string.Empty : string.Empty;
|
||||
var displayVersion = data.TryGetValue("displayVersion", out displayVersionValue) ? displayVersionValue?.ToString() ?? string.Empty : string.Empty;
|
||||
var currentBuild = data.TryGetValue("currentBuild", out currentBuildValue) ? currentBuildValue?.ToString() ?? string.Empty : string.Empty;
|
||||
var buildRevision = data.TryGetValue("buildRevision", out buildRevisionValue) ? buildRevisionValue?.ToString() ?? string.Empty : string.Empty;
|
||||
var osVersion = osName;
|
||||
|
||||
var message = string.IsNullOrWhiteSpace(osVersion) ? "OS information collected" : osVersion;
|
||||
if (!string.IsNullOrWhiteSpace(displayVersion))
|
||||
|
||||
@@ -82,5 +82,63 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Core
|
||||
catch { }
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the OS product name, e.g. "Microsoft Windows 11 Pro".
|
||||
/// Uses WMI Win32_OperatingSystem.Caption which is the authoritative source.
|
||||
/// </summary>
|
||||
public static string GetOsName()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var searcher = new System.Management.ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem"))
|
||||
{
|
||||
foreach (var obj in searcher.Get())
|
||||
{
|
||||
return obj["Caption"]?.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the real OS build string, e.g. "26220.7934" (CurrentBuild.UBR).
|
||||
/// Falls back to CurrentBuild alone if UBR is unavailable.
|
||||
/// </summary>
|
||||
public static string GetOsBuild()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"))
|
||||
{
|
||||
var currentBuild = key?.GetValue("CurrentBuild")?.ToString();
|
||||
if (string.IsNullOrEmpty(currentBuild))
|
||||
return string.Empty;
|
||||
|
||||
var ubr = key?.GetValue("UBR");
|
||||
return ubr != null ? $"{currentBuild}.{ubr}" : currentBuild;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the OS display version, e.g. "25H2", "24H2".
|
||||
/// </summary>
|
||||
public static string GetOsDisplayVersion()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"))
|
||||
{
|
||||
return key?.GetValue("DisplayVersion")?.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -490,7 +490,9 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Core
|
||||
Manufacturer = DeviceInfoProvider.GetManufacturer(),
|
||||
Model = DeviceInfoProvider.GetModel(),
|
||||
DeviceName = Environment.MachineName,
|
||||
OsBuild = Environment.OSVersion.Version.ToString(),
|
||||
OsName = DeviceInfoProvider.GetOsName(),
|
||||
OsBuild = DeviceInfoProvider.GetOsBuild(),
|
||||
OsDisplayVersion = DeviceInfoProvider.GetOsDisplayVersion(),
|
||||
OsEdition = DeviceInfoProvider.GetOsEdition(),
|
||||
OsLanguage = System.Globalization.CultureInfo.CurrentCulture.Name,
|
||||
StartedAt = DateTime.UtcNow,
|
||||
|
||||
@@ -99,7 +99,9 @@ namespace AutopilotMonitor.Agent
|
||||
Manufacturer = DeviceInfoProvider.GetManufacturer(),
|
||||
Model = DeviceInfoProvider.GetModel(),
|
||||
DeviceName = Environment.MachineName,
|
||||
OsBuild = Environment.OSVersion.Version.ToString(),
|
||||
OsName = DeviceInfoProvider.GetOsName(),
|
||||
OsBuild = DeviceInfoProvider.GetOsBuild(),
|
||||
OsDisplayVersion = DeviceInfoProvider.GetOsDisplayVersion(),
|
||||
OsEdition = DeviceInfoProvider.GetOsEdition(),
|
||||
OsLanguage = System.Globalization.CultureInfo.CurrentCulture.Name,
|
||||
StartedAt = DateTime.UtcNow,
|
||||
|
||||
@@ -1 +1 @@
|
||||
303
|
||||
306
|
||||
|
||||
@@ -132,7 +132,9 @@ namespace AutopilotMonitor.Functions.Services
|
||||
["Manufacturer"] = registration.Manufacturer ?? string.Empty,
|
||||
["Model"] = registration.Model ?? string.Empty,
|
||||
["DeviceName"] = registration.DeviceName ?? string.Empty,
|
||||
["OsName"] = registration.OsName ?? string.Empty,
|
||||
["OsBuild"] = registration.OsBuild ?? string.Empty,
|
||||
["OsDisplayVersion"] = registration.OsDisplayVersion ?? string.Empty,
|
||||
["OsEdition"] = registration.OsEdition ?? string.Empty,
|
||||
["OsLanguage"] = registration.OsLanguage ?? string.Empty,
|
||||
["IsUserDriven"] = registration.IsUserDriven,
|
||||
@@ -1017,7 +1019,9 @@ namespace AutopilotMonitor.Functions.Services
|
||||
IsPreProvisioned = entity.GetBoolean("IsPreProvisioned") ?? false,
|
||||
IsHybridJoin = entity.GetBoolean("IsHybridJoin") ?? false,
|
||||
ResumedAt = SafeGetDateTime(entity, "ResumedAt"),
|
||||
OsName = entity.GetString("OsName") ?? string.Empty,
|
||||
OsBuild = entity.GetString("OsBuild") ?? string.Empty,
|
||||
OsDisplayVersion = entity.GetString("OsDisplayVersion") ?? string.Empty,
|
||||
OsEdition = entity.GetString("OsEdition") ?? string.Empty,
|
||||
OsLanguage = entity.GetString("OsLanguage") ?? string.Empty,
|
||||
IsUserDriven = entity.GetBoolean("IsUserDriven") ?? false,
|
||||
|
||||
@@ -186,7 +186,9 @@ namespace AutopilotMonitor.Shared.Models
|
||||
public bool IsHybridJoin { get; set; }
|
||||
|
||||
// Device detail fields — stored in the Sessions table but omitted from earlier versions
|
||||
public string OsName { get; set; }
|
||||
public string OsBuild { get; set; }
|
||||
public string OsDisplayVersion { get; set; }
|
||||
public string OsEdition { get; set; }
|
||||
public string OsLanguage { get; set; }
|
||||
public bool IsUserDriven { get; set; }
|
||||
|
||||
@@ -38,10 +38,20 @@ namespace AutopilotMonitor.Shared.Models
|
||||
public string DeviceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OS build number
|
||||
/// OS product name, e.g. "Microsoft Windows 11 Pro"
|
||||
/// </summary>
|
||||
public string OsName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Real OS build number, e.g. "26220.7934" (CurrentBuild.UBR from registry)
|
||||
/// </summary>
|
||||
public string OsBuild { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OS display version, e.g. "25H2", "24H2"
|
||||
/// </summary>
|
||||
public string OsDisplayVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OS edition (e.g., "Pro", "Enterprise")
|
||||
/// </summary>
|
||||
|
||||
@@ -26,7 +26,9 @@ const ALL_COLUMNS: ColumnDef[] = [
|
||||
{ key: "started", label: "Started", defaultVisible: true, sortKey: "startedAt" },
|
||||
{ key: "country", label: "Country", defaultVisible: false, sortKey: "geoCountry", filterKey: "geoCountry" },
|
||||
{ key: "agentVersion", label: "Agent Version", defaultVisible: false, sortKey: "agentVersion", filterKey: "agentVersion" },
|
||||
{ key: "osName", label: "OS Name", defaultVisible: false, sortKey: "osName", filterKey: "osName" },
|
||||
{ key: "osBuild", label: "OS Build", defaultVisible: false, sortKey: "osBuild", filterKey: "osBuild" },
|
||||
{ key: "osDisplayVersion", label: "OS Version", defaultVisible: false, sortKey: "osDisplayVersion", filterKey: "osDisplayVersion" },
|
||||
{ key: "osEdition", label: "OS Edition", defaultVisible: false, sortKey: "osEdition", filterKey: "osEdition" },
|
||||
{ key: "osLanguage", label: "OS Language", defaultVisible: false, sortKey: "osLanguage", filterKey: "osLanguage" },
|
||||
{ key: "actions", label: "Actions", defaultVisible: true, adminOnly: true },
|
||||
@@ -337,7 +339,7 @@ export function SessionTable({
|
||||
currentSort={sortColumn}
|
||||
direction={sortDirection}
|
||||
onSort={onSort}
|
||||
className={["eventCount", "duration", "started", "country", "agentVersion", "osBuild", "osEdition", "osLanguage"].includes(col.key) ? "px-3" : undefined}
|
||||
className={["eventCount", "duration", "started", "country", "agentVersion", "osName", "osBuild", "osDisplayVersion", "osEdition", "osLanguage"].includes(col.key) ? "px-3" : undefined}
|
||||
filterKey={col.filterKey}
|
||||
filterValues={col.filterKey ? getUniqueValues(col.filterKey) : undefined}
|
||||
activeFilter={col.filterKey ? columnFilters[col.filterKey] : undefined}
|
||||
@@ -569,6 +571,13 @@ function SessionCell({
|
||||
);
|
||||
}
|
||||
|
||||
case "osName":
|
||||
return (
|
||||
<td className="px-3 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{session.osName || <span className="text-gray-300">—</span>}
|
||||
</td>
|
||||
);
|
||||
|
||||
case "osBuild":
|
||||
return (
|
||||
<td className="px-3 py-4 whitespace-nowrap text-sm text-gray-500 font-mono">
|
||||
@@ -576,6 +585,13 @@ function SessionCell({
|
||||
</td>
|
||||
);
|
||||
|
||||
case "osDisplayVersion":
|
||||
return (
|
||||
<td className="px-3 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{session.osDisplayVersion || <span className="text-gray-300">—</span>}
|
||||
</td>
|
||||
);
|
||||
|
||||
case "osEdition":
|
||||
return (
|
||||
<td className="px-3 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
|
||||
@@ -510,7 +510,9 @@ export default function Home() {
|
||||
session.geoRegion,
|
||||
session.geoCity,
|
||||
session.agentVersion,
|
||||
session.osName,
|
||||
session.osBuild,
|
||||
session.osDisplayVersion,
|
||||
session.osEdition,
|
||||
session.osLanguage,
|
||||
].join(" ").toLowerCase();
|
||||
|
||||
@@ -17,7 +17,9 @@ export interface Session {
|
||||
geoCountry?: string;
|
||||
geoRegion?: string;
|
||||
geoCity?: string;
|
||||
osName?: string;
|
||||
osBuild?: string;
|
||||
osDisplayVersion?: string;
|
||||
osEdition?: string;
|
||||
osLanguage?: string;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,9 @@ export interface SessionCsvData {
|
||||
deviceName: string;
|
||||
manufacturer: string;
|
||||
model: string;
|
||||
osName?: string;
|
||||
osBuild?: string;
|
||||
osDisplayVersion?: string;
|
||||
osEdition?: string;
|
||||
osLanguage?: string;
|
||||
isUserDriven?: boolean;
|
||||
@@ -105,7 +107,7 @@ export function generateSessionCsvExport(session: SessionCsvData): string {
|
||||
const esc = (v: string | undefined | null) => `"${String(v ?? "").replace(/"/g, '""')}"`;
|
||||
// Columns match the Sessions Azure Table Storage schema exactly
|
||||
// PartitionKey = TenantId, RowKey = SessionId
|
||||
const header = "PartitionKey,RowKey,SerialNumber,DeviceName,Manufacturer,Model,OsBuild,OsEdition,OsLanguage,IsUserDriven,IsPreProvisioned,StartedAt,CompletedAt,AgentVersion,EnrollmentType,CurrentPhase,Status,EventCount,FailureReason,LastEventAt,DurationSeconds,DiagnosticsBlobName";
|
||||
const header = "PartitionKey,RowKey,SerialNumber,DeviceName,Manufacturer,Model,OsName,OsBuild,OsDisplayVersion,OsEdition,OsLanguage,IsUserDriven,IsPreProvisioned,StartedAt,CompletedAt,AgentVersion,EnrollmentType,CurrentPhase,Status,EventCount,FailureReason,LastEventAt,DurationSeconds,DiagnosticsBlobName";
|
||||
const row = [
|
||||
esc(session.tenantId),
|
||||
esc(session.sessionId),
|
||||
@@ -113,7 +115,9 @@ export function generateSessionCsvExport(session: SessionCsvData): string {
|
||||
esc(session.deviceName),
|
||||
esc(session.manufacturer),
|
||||
esc(session.model),
|
||||
esc(session.osName),
|
||||
esc(session.osBuild),
|
||||
esc(session.osDisplayVersion),
|
||||
esc(session.osEdition),
|
||||
esc(session.osLanguage),
|
||||
String(session.isUserDriven ?? ""),
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user