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
|
if (typeof value !== "string") return null
|
||||||
const trimmed = value.trim()
|
const trimmed = value.trim()
|
||||||
if (!trimmed) return null
|
if (!trimmed) return null
|
||||||
|
|
||||||
const wmiMatch = trimmed.match(/Date\((\d+)\)/)
|
const wmiMatch = trimmed.match(/Date\((\d+)\)/)
|
||||||
if (wmiMatch) {
|
if (wmiMatch) {
|
||||||
const timestamp = Number(wmiMatch[1])
|
const timestamp = Number(wmiMatch[1])
|
||||||
if (Number.isFinite(timestamp)) {
|
return Number.isFinite(timestamp) ? new Date(timestamp) : null
|
||||||
return new Date(timestamp)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isoValue = Date.parse(trimmed)
|
||||||
|
if (!Number.isNaN(isoValue)) return new Date(isoValue)
|
||||||
|
|
||||||
const digitsOnly = trimmed.replace(/[^0-9]/g, "")
|
const digitsOnly = trimmed.replace(/[^0-9]/g, "")
|
||||||
if (digitsOnly.length >= 8 && digitsOnly.length <= 14) {
|
if (digitsOnly.length >= 8) {
|
||||||
const year = Number(digitsOnly.slice(0, 4))
|
const yyyy = Number(digitsOnly.slice(0, 4))
|
||||||
const month = Number(digitsOnly.slice(4, 6)) - 1
|
const mm = Number(digitsOnly.slice(4, 6))
|
||||||
const day = Number(digitsOnly.slice(6, 8))
|
const dd = Number(digitsOnly.slice(6, 8))
|
||||||
const hours = Number(digitsOnly.slice(8, 10) || "0")
|
const hh = Number(digitsOnly.slice(8, 10) || "0")
|
||||||
const minutes = Number(digitsOnly.slice(10, 12) || "0")
|
const mi = Number(digitsOnly.slice(10, 12) || "0")
|
||||||
const seconds = Number(digitsOnly.slice(12, 14) || "0")
|
const ss = Number(digitsOnly.slice(12, 14) || "0")
|
||||||
const parsed = new Date(Date.UTC(year, month, day, hours, minutes, seconds))
|
if (yyyy > 1900 && mm >= 1 && mm <= 12 && dd >= 1 && dd <= 31) {
|
||||||
if (!Number.isNaN(parsed.getTime())) {
|
const parsed = new Date(Date.UTC(yyyy, mm - 1, dd, hh, mi, ss))
|
||||||
return parsed
|
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 = {
|
type WindowsOsInfo = {
|
||||||
|
|
@ -251,30 +276,51 @@ type WindowsOsInfo = {
|
||||||
function parseWindowsOsInfo(raw: unknown): WindowsOsInfo | null {
|
function parseWindowsOsInfo(raw: unknown): WindowsOsInfo | null {
|
||||||
if (!raw) return null
|
if (!raw) return null
|
||||||
const parseRecord = (value: Record<string, unknown>) => {
|
const parseRecord = (value: Record<string, unknown>) => {
|
||||||
const productName = readString(value, "ProductName", "productName")
|
const read = (k: string, ...alts: string[]) => readString(value, k, ...alts)
|
||||||
const editionId = readString(value, "EditionID", "editionId")
|
const readNum = (...keys: string[]) => readNumber(value, ...keys)
|
||||||
const displayVersion = readString(value, "DisplayVersion", "displayVersion")
|
|
||||||
const releaseId = readString(value, "ReleaseId", "releaseId")
|
const productName =
|
||||||
const currentBuild = readString(value, "CurrentBuild", "currentBuild")
|
read("ProductName", "productName", "Name", "name") ??
|
||||||
const currentBuildNumber = readString(value, "CurrentBuildNumber", "currentBuildNumber")
|
(read("Family") && read("Edition") ? `${read("Family")} ${read("Edition")}` : undefined)
|
||||||
const licenseStatus = readNumber(value, "LicenseStatus", "licenseStatus")
|
|
||||||
const isActivatedRaw = value["IsActivated"]
|
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 =
|
const isActivated =
|
||||||
typeof isActivatedRaw === "boolean"
|
typeof isActivatedRaw === "boolean"
|
||||||
? isActivatedRaw
|
? isActivatedRaw
|
||||||
: typeof isActivatedRaw === "string"
|
: typeof isActivatedRaw === "string"
|
||||||
? isActivatedRaw.toLowerCase() === "true"
|
? isActivatedRaw.toLowerCase() === "true"
|
||||||
: undefined
|
: licenseStatus === 1
|
||||||
|
|
||||||
const installDate =
|
const installDate =
|
||||||
parseWindowsInstallDate(value["InstallDate"]) ??
|
parseWindowsInstallDate(value["InstallDate"]) ??
|
||||||
parseWindowsInstallDate(value["InstallationDate"]) ??
|
parseWindowsInstallDate(value["InstallationDate"]) ??
|
||||||
parseWindowsInstallDate(value["InstallDateTime"])
|
parseWindowsInstallDate(value["InstallDateTime"]) ??
|
||||||
const experience = readString(value, "Experience", "experience", "UBR")
|
parseWindowsInstallDate(value["InstalledOn"])
|
||||||
|
|
||||||
|
const experience =
|
||||||
|
read("Experience", "experience", "FeatureExperiencePack", "featureExperiencePack") ??
|
||||||
|
(currentBuildNumber ? `OS Build ${currentBuildNumber}` : undefined)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
productName,
|
productName,
|
||||||
editionId,
|
editionId,
|
||||||
displayVersion,
|
displayVersion,
|
||||||
releaseId,
|
releaseId: read("ReleaseId", "releaseId"),
|
||||||
currentBuild,
|
currentBuild,
|
||||||
currentBuildNumber,
|
currentBuildNumber,
|
||||||
licenseStatus,
|
licenseStatus,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue