Improve Windows OS metadata parsing
This commit is contained in:
parent
cf31158a9e
commit
0cd477b8ef
1 changed files with 73 additions and 27 deletions
|
|
@ -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<string, unknown>) => {
|
||||
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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue