From 0cd477b8efb03ecc660671dd1729a4ffc0c4cf61 Mon Sep 17 00:00:00 2001 From: Esdras Renan Date: Mon, 13 Oct 2025 16:34:28 -0300 Subject: [PATCH] Improve Windows OS metadata parsing --- .../machines/admin-machines-overview.tsx | 100 +++++++++++++----- 1 file changed, 73 insertions(+), 27 deletions(-) diff --git a/src/components/admin/machines/admin-machines-overview.tsx b/src/components/admin/machines/admin-machines-overview.tsx index c1e9442..ff8c44d 100644 --- a/src/components/admin/machines/admin-machines-overview.tsx +++ b/src/components/admin/machines/admin-machines-overview.tsx @@ -211,28 +211,53 @@ function parseWindowsInstallDate(value: unknown): Date | null { if (typeof value !== "string") return null const trimmed = value.trim() if (!trimmed) return null + const wmiMatch = trimmed.match(/Date\((\d+)\)/) if (wmiMatch) { const timestamp = Number(wmiMatch[1]) - if (Number.isFinite(timestamp)) { - return new Date(timestamp) - } + return Number.isFinite(timestamp) ? new Date(timestamp) : null } + + const isoValue = Date.parse(trimmed) + if (!Number.isNaN(isoValue)) return new Date(isoValue) + const digitsOnly = trimmed.replace(/[^0-9]/g, "") - if (digitsOnly.length >= 8 && digitsOnly.length <= 14) { - const year = Number(digitsOnly.slice(0, 4)) - const month = Number(digitsOnly.slice(4, 6)) - 1 - const day = Number(digitsOnly.slice(6, 8)) - const hours = Number(digitsOnly.slice(8, 10) || "0") - const minutes = Number(digitsOnly.slice(10, 12) || "0") - const seconds = Number(digitsOnly.slice(12, 14) || "0") - const parsed = new Date(Date.UTC(year, month, day, hours, minutes, seconds)) - if (!Number.isNaN(parsed.getTime())) { - return parsed + if (digitsOnly.length >= 8) { + const yyyy = Number(digitsOnly.slice(0, 4)) + const mm = Number(digitsOnly.slice(4, 6)) + const dd = Number(digitsOnly.slice(6, 8)) + const hh = Number(digitsOnly.slice(8, 10) || "0") + const mi = Number(digitsOnly.slice(10, 12) || "0") + const ss = Number(digitsOnly.slice(12, 14) || "0") + if (yyyy > 1900 && mm >= 1 && mm <= 12 && dd >= 1 && dd <= 31) { + const parsed = new Date(Date.UTC(yyyy, mm - 1, dd, hh, mi, ss)) + if (!Number.isNaN(parsed.getTime())) return parsed + } + const dd2 = Number(digitsOnly.slice(0, 2)) + const mm2 = Number(digitsOnly.slice(2, 4)) + const yyyy2 = Number(digitsOnly.slice(4, 8)) + if (yyyy2 > 1900 && mm2 >= 1 && mm2 <= 12 && dd2 >= 1 && dd2 <= 31) { + const parsed = new Date(Date.UTC(yyyy2, mm2 - 1, dd2)) + if (!Number.isNaN(parsed.getTime())) return parsed } } - const parsed = new Date(trimmed) - return Number.isNaN(parsed.getTime()) ? null : parsed + + const localMatch = trimmed.match( + /^(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})(?:\s+(\d{1,2}):(\d{2})(?::(\d{2}))?)?$/ + ) + if (localMatch) { + const dd = Number(localMatch[1]) + const mm = Number(localMatch[2]) + const yyyy = Number(localMatch[3]) + const hh = Number(localMatch[4] || "0") + const mi = Number(localMatch[5] || "0") + const ss = Number(localMatch[6] || "0") + if (yyyy > 1900 && mm >= 1 && mm <= 12 && dd >= 1 && dd <= 31) { + const parsed = new Date(Date.UTC(yyyy, mm - 1, dd, hh, mi, ss)) + if (!Number.isNaN(parsed.getTime())) return parsed + } + } + return null } type WindowsOsInfo = { @@ -251,30 +276,51 @@ type WindowsOsInfo = { function parseWindowsOsInfo(raw: unknown): WindowsOsInfo | null { if (!raw) return null const parseRecord = (value: Record) => { - const productName = readString(value, "ProductName", "productName") - const editionId = readString(value, "EditionID", "editionId") - const displayVersion = readString(value, "DisplayVersion", "displayVersion") - const releaseId = readString(value, "ReleaseId", "releaseId") - const currentBuild = readString(value, "CurrentBuild", "currentBuild") - const currentBuildNumber = readString(value, "CurrentBuildNumber", "currentBuildNumber") - const licenseStatus = readNumber(value, "LicenseStatus", "licenseStatus") - const isActivatedRaw = value["IsActivated"] + const read = (k: string, ...alts: string[]) => readString(value, k, ...alts) + const readNum = (...keys: string[]) => readNumber(value, ...keys) + + const productName = + read("ProductName", "productName", "Name", "name") ?? + (read("Family") && read("Edition") ? `${read("Family")} ${read("Edition")}` : undefined) + + const editionId = + read("EditionID", "editionId", "Edition", "edition", "SkuEdition", "skuEdition") ?? undefined + + const displayVersion = + read("DisplayVersion", "displayVersion", "Version", "version") ?? + read("ReleaseId", "releaseId") + + const baseBuild = + read("CurrentBuildNumber", "currentBuildNumber", "CurrentBuild", "currentBuild", "OSBuild", "osBuild") ?? + undefined + const ubr = read("UBR") ?? (readNum("UBR") ? String(readNum("UBR")) : undefined) + const currentBuildNumber = baseBuild ? (ubr && /^\d+$/.test(ubr) ? `${baseBuild}.${ubr}` : baseBuild) : undefined + const currentBuild = baseBuild + + const licenseStatus = readNum("LicenseStatus", "licenseStatus") + const isActivatedRaw = value["IsActivated"] ?? value["isActivated"] const isActivated = typeof isActivatedRaw === "boolean" ? isActivatedRaw : typeof isActivatedRaw === "string" ? isActivatedRaw.toLowerCase() === "true" - : undefined + : licenseStatus === 1 + const installDate = parseWindowsInstallDate(value["InstallDate"]) ?? parseWindowsInstallDate(value["InstallationDate"]) ?? - parseWindowsInstallDate(value["InstallDateTime"]) - const experience = readString(value, "Experience", "experience", "UBR") + parseWindowsInstallDate(value["InstallDateTime"]) ?? + parseWindowsInstallDate(value["InstalledOn"]) + + const experience = + read("Experience", "experience", "FeatureExperiencePack", "featureExperiencePack") ?? + (currentBuildNumber ? `OS Build ${currentBuildNumber}` : undefined) + return { productName, editionId, displayVersion, - releaseId, + releaseId: read("ReleaseId", "releaseId"), currentBuild, currentBuildNumber, licenseStatus,