Trong Posted August 30 Posted August 30 (edited) UDF: expandcollapse popup#include-once ; #INDEX# ======================================================================================================================= ; Title ..........: Windows Version Detector UDF v5 ; AutoIt Version .: 3.3.16.1+ ; Language .......: English ; Description ...: This User Defined Function (UDF) detects Windows versions for both live (running) and offline (mounted or extracted) Windows installations. ; It uses a dual-database approach: an exact build database for precise matches and a range-based inference database for broader version identification. ; The UDF supports Windows from version 1.0 up to Windows Server 2025, including client and server editions, Insider previews, and various builds. ; Key features include registry reading for live systems, offline hive loading for mounted images, and file-based fallback detection. ; Author(s) ......: Dao Van Trong - TRONG.PRO ; Version ........: 3.8.1 (Updated for consistent official version names like 2004; Enhanced with full UDF headers and inline comments) ; Dll(s) .........: kernel32.dll, advapi32.dll, ole32.dll ; =============================================================================================================================== ; #INCLUDES# ==================================================================================================================== #include <FileConstants.au3> ; For file operations like $OPEN_EXISTING, $FILE_SHARE_READ, $GENERIC_READ #include <APIRegConstants.au3> ; For registry constants like $HKEY_LOCAL_MACHINE #include <APIErrorsConstants.au3> ; For error codes like $ERROR_SUCCESS #include <StringConstants.au3> ; For string manipulation constants like $STR_STRIPLEADING, $STR_STRIPTRAILING, $STR_NOCOUNT #include <Array.au3> ; For array functions like _ArrayToString (though custom implementation used here for compatibility) ; =============================================================================================================================== ; #CONSTANTS# ==================================================================================================================== ; Registry paths and system constants Global Const $REG_KEY_VERSION = "SOFTWARE\Microsoft\Windows NT\CurrentVersion" ; Main registry key for Windows version info Global Const $REG_KEY_INSIDER = "SOFTWARE\Microsoft\WindowsSelfHost\Applicability" ; Registry key for Insider preview detection Global Const $HIVE_SOFTWARE = "\System32\Config\SOFTWARE" ; Path to SOFTWARE hive file for offline detection Global Const $MAX_PATH = 32767 ; Maximum path length for Windows API calls Global Const $SE_BACKUP_PRIVILEGE = "SeBackupPrivilege" ; Privilege required to load/unload registry hives ; Static version databases (initialized at compile time) ; Range DB structure: [MinBuild, MaxBuild, ProductName] - Used for inferring versions when exact match fails Global Const $_g_aWinVerRangeDB = __WinVerDetect_InitWindowsVersionDB() ; Exact DB structure: [ProductName, Codename, ReleaseDate, DisplayVersion, Build, UBR] - For precise version matching Global Const $_g_aWinVerExactDB = __WinVerDetect_InitExactWindowsVersionDB() ; Edition mappings array Global Const $g_aEditionMap = __WinVerDetect_InitEditionMap() ; =============================================================================================================================== ; #ENUMS# ======================================================================================================================= ; Enum for return array indices from _WinVerDetect_GetVersion (when $iReturn = -1) Global Enum $WINVER_STATE, _ ; 0: "Live" or "Offline" indicating if the system is running or not $WINVER_SHORTNAME, _ ; 1: Short OS identifier (e.g., "WIN_10", "WIN_11", "WIN_SRV") $WINVER_PRODUCTNAME, _ ; 2: Full product name (e.g., "Windows 10", "Windows Server 2022") $WINVER_FULLNAME, _ ; 3: Full version name (e.g., "Windows 10 Version 22H2 (Build 19045)") $WINVER_BUILD, _ ; 4: Major build number (e.g., "19045") $WINVER_UBR, _ ; 5: Update Build Revision (e.g., "4567") $WINVER_DISPLAYVERSION, _ ; 6: Display version string (e.g., "22H2", "2004") $WINVER_EDITIONID, _ ; 7: Edition ID (e.g., "Professional", "Enterprise", "Server") $WINVER_EDITIONTYPE, _ ; 8: Inferred edition type (e.g., "Professional") $WINVER_ISINSIDER ; 9: Boolean (True if Insider Preview) ; Enum for error codes returned by @error in _WinVerDetect_GetVersion Global Enum $WINVER_ERROR_SUCCESS, _ ; 0: No error $WINVER_ERROR_INVALID_PATH, _ ; 1: Invalid or non-existent Windows path $WINVER_ERROR_REGISTRY_FAILED, _ ; 2: Failed to read registry (live or offline) $WINVER_ERROR_FILE_ACCESS, _ ; 3: File access denied or files not found $WINVER_ERROR_NO_ADMIN, _ ; 4: Admin privileges required for live/offline operations $WINVER_ERROR_INVALID_BUILD ; 5: Invalid or unrecognized build number ; =============================================================================================================================== ; #VARIABLES# ==================================================================================================================== ; No global variables beyond constants; all data is in static arrays for efficiency ; =============================================================================================================================== ; #FUNCTIONS# ==================================================================================================================== ; Public Functions ; _WinVerDetect_GetVersion ; _RegReadMulti ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name ..........: _WinVerDetect_GetVersion ; Description ...: Detects detailed Windows version information from a live or offline Windows installation path. ; Supports both running systems (live) and mounted/extracted images (offline). For live systems, requires admin privileges. ; Returns an array with version details or a specific index if requested. Uses registry for precise info, falls back to file versions. ; Syntax ........: _WinVerDetect_GetVersion([$sWindowsPath = @WindowsDir[, $iReturn = -1]]) ; Parameters ....: $sWindowsPath - String: Path to Windows directory (default: @WindowsDir for live system) ; $iReturn - Integer: Index of array element to return (default: -1 for full array) ; Return values .: Success - If $iReturn = -1: Array[10] with version info as per $WINVER_* enums ; | If $iReturn >= 0: String value from the specified array index ; Failure - Sets @error to one of $WINVER_ERROR_* codes, returns empty array/string ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Enhanced documentation and error handling ; Remarks .......: - For offline detection without admin: Falls back to file-based inference (less accurate). ; | - Builds and UBR are integers as strings for consistency. ; | - IsInsider detection checks for Insider Preview rings. ; Related .......: _RegReadMulti, __WinVerDetect_LiveVersion, __WinVerDetect_OfflineVersion, __WinVerDetect_FromFiles ; Example .......: #include "Windows Version Detector v5.au3" ; Local $aInfo = _WinVerDetect_GetVersion() ; If Not @error Then ConsoleWrite("OS: " & $aInfo[$WINVER_PRODUCTNAME] & @CRLF) ; =============================================================================================================================== Func _WinVerDetect_GetVersion($sWindowsPath = @WindowsDir, $iReturn = -1) ; Initialize result array with defaults (empty strings and False for boolean) Local $aResult[10] = ["", "", "", "", "", "", "", "", "", False] ; Normalize the input path to handle long paths and ensure consistency Local $sPath = __WinVerDetect_NormalizePath($sWindowsPath) ; Validate if the path points to a valid Windows installation If Not __WinVerDetect_IsValidWindowsPath($sPath) Then Return SetError($WINVER_ERROR_INVALID_PATH, 0, ($iReturn = -1) ? $aResult : $aResult[$iReturn]) EndIf ; Determine if this is a live (running) system or offline installation $aResult[$WINVER_STATE] = __WinVerDetect_IsSystemLive($sPath) ? "Live" : "Offline" ; Process based on live/offline status If $aResult[$WINVER_STATE] = "Live" Then ; For live systems, require admin privileges If Not IsAdmin() Then Return SetError($WINVER_ERROR_NO_ADMIN, 0, ($iReturn = -1) ? $aResult : $aResult[$iReturn]) EndIf ; Read from live registry $aResult = __WinVerDetect_LiveVersion($sPath) Else ; For offline, attempt registry hive load if admin, else fallback to files If IsAdmin() Then $aResult = __WinVerDetect_OfflineVersion($sPath) Else $aResult = __WinVerDetect_FromFiles($sPath) EndIf EndIf ; Propagate errors from internal functions If @error Then Return SetError(@error, @extended, ($iReturn = -1) ? $aResult : $aResult[$iReturn]) EndIf ; Fill in any missing information using the version databases $aResult = __WinVerDetect_FillMissingInfo($aResult) ; Return full array or specific index Return ($iReturn = -1) ? $aResult : $aResult[$iReturn] EndFunc ;==>_WinVerDetect_GetVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: _RegReadMulti ; Description ...: Reads multiple registry values from a single key, supporting array input, delimited strings, or single values. ; Handles errors gracefully, returning defaults for missing values. Useful for batch registry reads in version detection. ; Syntax ........: _RegReadMulti($sKey, $vFields[, $sDefault = ""[, $sSplitChar = "|"[, $sJoinChar = "|"[, $bReturnArray = False]]]]) ; Parameters ....: $sKey - String: Registry key path (e.g., "HKLM\SOFTWARE\...") ; $vFields - Variant: Array of value names, delimited string (e.g., "Value1|Value2"), or single string ; $sDefault - String: Default value if read fails (default: "") ; $sSplitChar - String: Delimiter for splitting $vFields if string (default: "|") ; $sJoinChar - String: Delimiter for joining results if not returning array (default: "|") ; $bReturnArray- Boolean: True to return array, False to return joined string (default: True) ; Return values .: Success - Array if $bReturnArray=True, joined string otherwise ; Failure - Sets @error: 1=Invalid key, 2=Empty fields, 3=Parse error; @extended=Number of values processed ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added comprehensive error handling and documentation ; Remarks .......: - Strips whitespace from field names. ; | - Tracks the highest error code for partial failures. ; Related .......: RegRead (built-in) ; Example .......: Local $aValues = _RegReadMulti("HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion", ["ProductName", "BuildLab"], "", "|", True) ; =============================================================================================================================== Func _RegReadMulti($sKey, $vFields, $sDefault = "", $sSplitChar = "|", $sJoinChar = "|", $bReturnArray = True) Local $aNames, $iErrorCode = 0, $iExtended = 0 ; Track errors Local $aDefaultResult[1] = [$sDefault] ; Fallback for empty fields ; Parse $vFields: Handle array, delimited string, or single value If IsArray($vFields) Then If UBound($vFields) > 0 Then $aNames = $vFields ; Direct array Else $aNames = $aDefaultResult $iErrorCode = 3 ; Empty array $iExtended = 1 EndIf Else If $vFields = "" Then $aNames = $aDefaultResult $iErrorCode = 2 ; Empty string $iExtended = 1 ElseIf $sSplitChar <> "" And StringInStr($vFields, $sSplitChar) Then ; Split delimited string $aNames = StringSplit($vFields, $sSplitChar, $STR_NOCOUNT) If UBound($aNames) > 0 Then ; Strip whitespace from each name For $i = 0 To UBound($aNames) - 1 $aNames[$i] = StringStripWS($aNames[$i], $STR_STRIPLEADING + $STR_STRIPTRAILING) Next Else $aNames = $aDefaultResult $iErrorCode = 3 $iExtended = 1 EndIf Else ; Single value as array Local $aTmp[1] = [StringStripWS($vFields, $STR_STRIPLEADING + $STR_STRIPTRAILING)] $aNames = $aTmp EndIf EndIf ; Initialize result array Local $aResult[UBound($aNames)] If $sKey = "" Then ; No key: Fill with defaults For $i = 0 To UBound($aResult) - 1 $aResult[$i] = $sDefault Next If $iErrorCode = 0 Then $iErrorCode = 1 ; Invalid key $iExtended = UBound($aResult) Else ; Read each value from registry For $i = 0 To UBound($aNames) - 1 Local $sValue = RegRead($sKey, $aNames[$i]) If @error Then $sValue = $sDefault ; Track highest error $iErrorCode = (@error > $iErrorCode) ? @error : $iErrorCode $iExtended = (@extended > $iExtended) ? @extended : $iExtended EndIf $aResult[$i] = $sValue Next EndIf ; Return array or joined string Return SetError($iErrorCode, $iExtended, $bReturnArray ? $aResult : __WinVerDetect_ArrayToString($aResult, $sJoinChar)) EndFunc ;==>_RegReadMulti ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name...........: Internal Functions ; Description ...: These functions are for internal use by the UDF and should not be called directly. ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_GetShortName ; Description ...: Infers a short OS identifier (e.g., "WIN_10") from the full product name. Used for standardized OS classification. ; Syntax ........: __WinVerDetect_GetShortName($sProductName) ; Parameters ....: $sProductName - String: Full product name (e.g., "Windows 10", "Windows Server 2022") ; Return values .: Success - String: Short identifier (e.g., "WIN_10", "WIN_SRV") ; Failure - "UNKNOWN" if no match ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added inline comments for priority matching ; Remarks .......: - Prioritizes server versions first, then client. ; | - Case-insensitive matching using StringLower. ; Related .......: _WinVerDetect_GetVersion ; =============================================================================================================================== Func __WinVerDetect_GetShortName($sProductName) Local $sLower = StringLower($sProductName) ; Convert to lowercase for case-insensitive matching ; Prioritize server versions (check for "server" keyword first) If StringInStr($sLower, "server") Then If StringInStr($sLower, "2025") Then Return "WIN_2025" ; Windows Server 2025 If StringInStr($sLower, "2022") Then Return "WIN_2022" ; Windows Server 2022 If StringInStr($sLower, "2019") Then Return "WIN_2019" ; Windows Server 2019 If StringInStr($sLower, "2016") Then Return "WIN_2016" ; Windows Server 2016 If StringInStr($sLower, "2012 r2") Then Return "WIN_2012R2" ; Windows Server 2012 R2 If StringInStr($sLower, "2012") Then Return "WIN_2012" ; Windows Server 2012 If StringInStr($sLower, "2008 r2") Then Return "WIN_2008R2" ; Windows Server 2008 R2 If StringInStr($sLower, "2008") Then Return "WIN_2008" ; Windows Server 2008 If StringInStr($sLower, "2003 r2") Then Return "WIN_2003R2" ; Windows Server 2003 R2 If StringInStr($sLower, "2003") Then Return "WIN_2003" ; Windows Server 2003 Return "WIN_SRV" ; Generic server fallback EndIf ; Client versions (check in descending order for accuracy) If StringInStr($sLower, "windows 11") Then Return "WIN_11" If StringInStr($sLower, "windows 10") Then Return "WIN_10" If StringInStr($sLower, "windows 8.1") Then Return "WIN_81" If StringInStr($sLower, "windows 8") Then Return "WIN_8" If StringInStr($sLower, "windows 7") Then Return "WIN_7" If StringInStr($sLower, "vista") Then Return "WIN_VISTA" If StringInStr($sLower, "xp") Then Return "WIN_XP" If StringInStr($sLower, "2000") Then Return "WIN_2000" If StringInStr($sLower, "nt 4.0") Then Return "WIN_NT4" If StringInStr($sLower, "nt 3.51") Then Return "WIN_NT351" If StringInStr($sLower, "nt 3.5") Then Return "WIN_NT35" If StringInStr($sLower, "nt 3.1") Then Return "WIN_NT31" Return "UNKNOWN" ; No match found EndFunc ;==>__WinVerDetect_GetShortName ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_LiveVersion ; Description ...: Retrieves version info from the live system's registry. Requires admin privileges. ; Syntax ........: __WinVerDetect_LiveVersion($sPath) ; Parameters ....: $sPath - String: Path to Windows directory (must be live system) ; Return values .: Success - Array[10] with populated version fields ; Failure - Calls __WinVerDetect_FromFiles as fallback; logs error ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Integrated error logging and fallback ; Remarks .......: - Uses _RegReadMulti for efficient batch reading. ; | - Sets EditionType via inference if needed. ; Related .......: _RegReadMulti, __WinVerDetect_IsInsiderPreview, __WinVerDetect_FromFiles ; =============================================================================================================================== Func __WinVerDetect_LiveVersion($sPath) ; Initialize result array for live system Local $aResult[10] = ["Live", "", "", "", "", "", "", "", "", False] ; Registry key for version info Local $sKey = "HKLM\" & $REG_KEY_VERSION ; Read multiple values: ProductName, CurrentBuildNumber, DisplayVersion, UBR, EditionID Local $aRegValues = _RegReadMulti($sKey, "ProductName|CurrentBuildNumber|DisplayVersion|UBR|EditionID", "", "|", "|", True) ; Check if read succeeded (array of 5 elements) If Not @error And IsArray($aRegValues) And UBound($aRegValues) = 5 Then ; Populate result from registry values $aResult[$WINVER_PRODUCTNAME] = $aRegValues[0] ; ProductName $aResult[$WINVER_BUILD] = $aRegValues[1] ; Build $aResult[$WINVER_DISPLAYVERSION] = $aRegValues[2] ; DisplayVersion $aResult[$WINVER_UBR] = $aRegValues[3] ; UBR $aResult[$WINVER_EDITIONID] = $aRegValues[4] ; EditionID ; Infer EditionType from ProductName or EditionID $aResult[$WINVER_EDITIONTYPE] = __WinVerDetect_InferEditionType($aRegValues[0], $aRegValues[4]) ; Check for Insider Preview $aResult[$WINVER_ISINSIDER] = __WinVerDetect_IsInsiderPreview() Return $aResult Else ; Log error details for debugging __WinVerDetect_LogError("Registry read failed in __WinVerDetect_LiveVersion: Error=" & @error & ", Extended=" & @extended & ", aRegValues=" & (IsArray($aRegValues) ? __WinVerDetect_ArrayToString($aRegValues) : $aRegValues)) ; Fallback to file-based detection Return __WinVerDetect_FromFiles($sPath) EndIf EndFunc ;==>__WinVerDetect_LiveVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_OfflineVersion ; Description ...: Loads offline registry hive and reads version info. Requires admin privileges and SeBackupPrivilege. ; Syntax ........: __WinVerDetect_OfflineVersion($sPath) ; Parameters ....: $sPath - String: Path to offline Windows directory ; Return values .: Success - Array[10] with populated version fields ; Failure - Falls back to __WinVerDetect_FromFiles; unloads hive on exit ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added hive unloading and Insider check for offline ; Remarks .......: - Uses temporary key for hive loading to avoid conflicts. ; | - Ensures hive is unloaded after reading to free resources. ; Related .......: __WinVerDetect_LoadOfflineHive, __WinVerDetect_UnloadOfflineHive, __WinVerDetect_IsOfflineInsiderPreview ; =============================================================================================================================== Func __WinVerDetect_OfflineVersion($sPath) ; Initialize result array for offline system Local $aResult[10] = ["Offline", "", "", "", "", "", "", "", "", False] ; Path to SOFTWARE hive Local $sHiveFile = $sPath & $HIVE_SOFTWARE ; Check if hive file exists If Not FileExists($sHiveFile) Then Return __WinVerDetect_FromFiles($sPath) EndIf ; Generate unique temporary key for hive loading Local $sTempKey = __WinVerDetect_GenerateUniqueKey() ; Load the hive (requires backup privilege) If Not __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey) Then Return __WinVerDetect_FromFiles($sPath) EndIf ; Read from loaded hive Local $sKey = "HKLM\" & $sTempKey & "\" & $REG_KEY_VERSION Local $aRegValues = _RegReadMulti($sKey, "ProductName|CurrentBuildNumber|DisplayVersion|UBR|EditionID", "", "|", "|", True) ; Populate result (assume success; errors handled in _RegReadMulti) $aResult[$WINVER_PRODUCTNAME] = $aRegValues[0] ; ProductName $aResult[$WINVER_BUILD] = $aRegValues[1] ; Build $aResult[$WINVER_DISPLAYVERSION] = $aRegValues[2] ; DisplayVersion $aResult[$WINVER_UBR] = $aRegValues[3] ; UBR $aResult[$WINVER_EDITIONID] = $aRegValues[4] ; EditionID ; Infer EditionType $aResult[$WINVER_EDITIONTYPE] = __WinVerDetect_InferEditionType($aRegValues[0], $aRegValues[4]) ; Check for offline Insider $aResult[$WINVER_ISINSIDER] = __WinVerDetect_IsOfflineInsiderPreview($sPath) ; Unload the hive to clean up __WinVerDetect_UnloadOfflineHive($sTempKey) Return $aResult EndFunc ;==>__WinVerDetect_OfflineVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_FromFiles ; Description ...: Fallback detection using file versions (kernel32.dll or ntdll.dll) and edition-specific files. No admin required. ; Syntax ........: __WinVerDetect_FromFiles($sPath) ; Parameters ....: $sPath - String: Path to Windows directory ; Return values .: Success - Array[10] with build, UBR, and inferred product/edition ; Failure - Sets @error=3 if no build found ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Enhanced edition detection logic ; Remarks .......: - Extracts build and UBR from file version info (format: Major.Minor.Build.UBR). ; | - Infers edition by presence of specific files (e.g., ServerManager.exe for Server). ; Related .......: FileGetVersion (built-in) ; =============================================================================================================================== Func __WinVerDetect_FromFiles($sPath) ; Initialize result array for offline/file-based detection Local $aResult[10] = ["Offline", "", "", "", "", "", "", "", "", False] ; Key system files for build detection Local $aSystemFiles[2] = [$sPath & "\System32\kernel32.dll", $sPath & "\System32\ntdll.dll"] ; Try each file for version info For $sFile In $aSystemFiles If FileExists($sFile) Then Local $sFileVersion = FileGetVersion($sFile) If $sFileVersion <> "" Then Local $aVersionParts = StringSplit($sFileVersion, ".") If $aVersionParts[0] >= 4 Then ; File version format: Major.Minor.Build.UBR (e.g., 10.0.19045.4567) $aResult[$WINVER_BUILD] = $aVersionParts[3] ; Build (last but one) $aResult[$WINVER_UBR] = $aVersionParts[4] ; UBR (private build) $aResult[$WINVER_DISPLAYVERSION] = "" ; To be inferred later ExitLoop ; Success, stop checking EndIf EndIf EndIf Next ; Error if no build found If $aResult[$WINVER_BUILD] = "" Then Return SetError($WINVER_ERROR_FILE_ACCESS, 0, $aResult) EndIf ; Infer product and edition based on edition-specific files If FileExists($sPath & "\System32\ServerManager.exe") Then ; Server edition $aResult[$WINVER_PRODUCTNAME] = "Windows Server" $aResult[$WINVER_EDITIONID] = "Server" $aResult[$WINVER_EDITIONTYPE] = "Server" ElseIf FileExists($sPath & "\System32\ProfSvc.dll") Then ; Professional edition $aResult[$WINVER_PRODUCTNAME] = "Windows Professional" $aResult[$WINVER_EDITIONID] = "Professional" $aResult[$WINVER_EDITIONTYPE] = "Professional" Else ; Default to Home $aResult[$WINVER_PRODUCTNAME] = "Windows Home" $aResult[$WINVER_EDITIONID] = "Home" $aResult[$WINVER_EDITIONTYPE] = "Home" EndIf Return $aResult EndFunc ;==>__WinVerDetect_FromFiles ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_FillMissingInfo ; Description ...: Populates missing fields in the result array using the static version databases or inference functions. ; Syntax ........: __WinVerDetect_FillMissingInfo(ByRef $aResult) ; Parameters ....: $aResult - Array: Reference to the result array[10] to fill ; Return values .: Modified $aResult with filled fields; Sets @error=5 if invalid build ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Prioritized DB lookup before inference ; Remarks .......: - Uses exact DB first, then range DB. ; | - Only overrides empty fields to preserve registry data. ; Related .......: __WinVerDetect_GetVersionFromDB, __WinVerDetect_InferDisplayVersion ; =============================================================================================================================== Func __WinVerDetect_FillMissingInfo(ByRef $aResult) ; Parse build and UBR as integers for comparison Local $iBuild = Int($aResult[$WINVER_BUILD]) Local $iUBR = Int($aResult[$WINVER_UBR]) If $iBuild < 1 Then Return SetError($WINVER_ERROR_INVALID_BUILD, 0, $aResult) EndIf ; Attempt to get full info from databases Local $aVersionInfo = __WinVerDetect_GetVersionFromDB($iBuild, $iUBR) If IsArray($aVersionInfo) Then ; Use DB info if available, but only fill empty fields If $aResult[$WINVER_SHORTNAME] = "" Then $aResult[$WINVER_SHORTNAME] = $aVersionInfo[1] ; ShortOS If $aResult[$WINVER_PRODUCTNAME] = "" Then $aResult[$WINVER_PRODUCTNAME] = $aVersionInfo[2] ; ProductName If $aResult[$WINVER_FULLNAME] = "" Then $aResult[$WINVER_FULLNAME] = $aVersionInfo[3] ; VersionFullName If $aResult[$WINVER_DISPLAYVERSION] = "" Then $aResult[$WINVER_DISPLAYVERSION] = $aVersionInfo[6] ; DisplayVersion ; Only set edition if not already from registry If $aResult[$WINVER_EDITIONID] = "" Then $aResult[$WINVER_EDITIONID] = $aVersionInfo[7] If $aResult[$WINVER_EDITIONTYPE] = "" Then $aResult[$WINVER_EDITIONTYPE] = $aVersionInfo[8] Else ; Fallback to inference functions for missing fields If $aResult[$WINVER_SHORTNAME] = "" Then $aResult[$WINVER_SHORTNAME] = __WinVerDetect_GetShortName($aResult[$WINVER_PRODUCTNAME]) If $aResult[$WINVER_PRODUCTNAME] = "" Then $aResult[$WINVER_PRODUCTNAME] = "Windows" ; Default If $aResult[$WINVER_FULLNAME] = "" Then $aResult[$WINVER_FULLNAME] = __WinVerDetect_GetVersionNameByBuild($iBuild, $aResult[$WINVER_DISPLAYVERSION], $aResult[$WINVER_PRODUCTNAME], $iUBR) If $aResult[$WINVER_DISPLAYVERSION] = "" Then $aResult[$WINVER_DISPLAYVERSION] = __WinVerDetect_InferDisplayVersion($iBuild) If $aResult[$WINVER_EDITIONID] = "" Then $aResult[$WINVER_EDITIONID] = __WinVerDetect_InferEditionType($aResult[$WINVER_PRODUCTNAME], "") If $aResult[$WINVER_EDITIONTYPE] = "" Then $aResult[$WINVER_EDITIONTYPE] = __WinVerDetect_InferEditionType($aResult[$WINVER_PRODUCTNAME], $aResult[$WINVER_EDITIONID]) EndIf Return $aResult EndFunc ;==>__WinVerDetect_FillMissingInfo ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_GetVersionFromDB ; Description ...: Looks up version info in exact and range databases based on build and UBR. ; Syntax ........: __WinVerDetect_GetVersionFromDB($iBuild[, $iUBR = 0]) ; Parameters ....: $iBuild - Integer: Major build number ; $iUBR - Integer: Update Build Revision (optional) ; Return values .: Success - Array[10] with version details ; Failure - 0 (no match) ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Structured array return for consistency ; Remarks .......: - Exact DB checked first for precise matches (including UBR). ; | - Range DB for broader inference (ignores UBR). ; Related .......: __WinVerDetect_InitExactWindowsVersionDB, __WinVerDetect_InitWindowsVersionDB ; =============================================================================================================================== Func __WinVerDetect_GetVersionFromDB($iBuild, $iUBR = 0) ; Check exact build database first (precise matches) For $i = 0 To UBound($_g_aWinVerExactDB) - 1 ; Match build and UBR (UBR=-1 means any) If $iBuild = $_g_aWinVerExactDB[$i][4] And ($iUBR = $_g_aWinVerExactDB[$i][5] Or $_g_aWinVerExactDB[$i][5] = -1) Then ; Construct result array Local $aResult[10] $aResult[0] = "" ; State (not used here) $aResult[1] = __WinVerDetect_GetShortName($_g_aWinVerExactDB[$i][0]) ; ShortOS $aResult[2] = $_g_aWinVerExactDB[$i][0] ; ProductName ; Full name with version, build, and codename if available $aResult[3] = $_g_aWinVerExactDB[$i][0] & " Version " & $_g_aWinVerExactDB[$i][3] & " (Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")" & ($_g_aWinVerExactDB[$i][2] <> "" ? " (" & $_g_aWinVerExactDB[$i][2] & ")" : "") $aResult[4] = String($iBuild) ; Build as string $aResult[5] = String($iUBR) ; UBR as string $aResult[6] = $_g_aWinVerExactDB[$i][3] ; DisplayVersion $aResult[7] = $_g_aWinVerExactDB[$i][0] ; EditionID fallback to product $aResult[8] = $_g_aWinVerExactDB[$i][0] ; EditionType fallback $aResult[9] = False ; Not Insider (DB is for stable releases) Return $aResult EndIf Next ; Fallback to range database (build range match) For $i = 0 To UBound($_g_aWinVerRangeDB) - 1 ; Check if build falls in range (MaxBuild=-1 means up to current) If $iBuild >= $_g_aWinVerRangeDB[$i][0] And ($iBuild <= $_g_aWinVerRangeDB[$i][1] Or $_g_aWinVerRangeDB[$i][1] = -1) Then Local $aResult[10] $aResult[0] = "" ; State $aResult[1] = __WinVerDetect_GetShortName($_g_aWinVerRangeDB[$i][2]) ; ShortOS $aResult[2] = $_g_aWinVerRangeDB[$i][2] ; ProductName ; Full name with inferred display version $aResult[3] = $_g_aWinVerRangeDB[$i][2] & " Version " & __WinVerDetect_InferDisplayVersion($iBuild) & " (Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")" $aResult[4] = String($iBuild) $aResult[5] = String($iUBR) $aResult[6] = __WinVerDetect_InferDisplayVersion($iBuild) ; DisplayVersion $aResult[7] = $_g_aWinVerRangeDB[$i][2] ; EditionID fallback $aResult[8] = $_g_aWinVerRangeDB[$i][2] ; EditionType fallback $aResult[9] = False Return $aResult EndIf Next Return 0 ; No match EndFunc ;==>__WinVerDetect_GetVersionFromDB ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_InitExactWindowsVersionDB ; Description ...: Initializes the exact version database with historical and current Windows builds. Called at compile time. ; Syntax ........: __WinVerDetect_InitExactWindowsVersionDB() ; Parameters ....: None ; Return values .: 2D Array: [57][6] with [ProductName, Codename, ReleaseDate, DisplayVersion, Build, UBR] ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Updated entries for Windows 11 24H2 and Server 2025; added comments ; Remarks .......: - UBR = -1 means any UBR for that build. ; | - Covers Windows 1.0 to Windows Server 2025. ; | - Duplicate entries for SP/service packs where applicable. ; Related .......: __WinVerDetect_GetVersionFromDB ; =============================================================================================================================== Func __WinVerDetect_InitExactWindowsVersionDB() ; Define 2D array structure: [ProductName, Codename, ReleaseDate, Version, DisplayVersion, Build, UBR] Local $aDB[53][7] ; Source data entries (historical to modern) Local $aEntries[53][7] = [ _ ["Windows 95", "Chicago", "August 1995", "4.0", "4.0", 950, -1], _ ["Windows 98", "Memphis", "June 1998", "4.1", "4.1", 1998, -1], _ ["Windows 98", "Memphis", "May 1999", "4.1", "SE", 2222, -1], _ ["Windows Me", "Millennium", "September 2000", "4.9", "4.9", 3000, -1], _ ["Windows NT 3.1", "Razzle", "July 1993", "3.1", "3.1", 528, -1], _ ["Windows NT 3.5", "Daytona", "September 1994", "3.5", "3.5", 807, -1], _ ["Windows NT 3.51", "Daytona", "May 1995", "3.51", "3.51", 1057, -1], _ ["Windows NT 4.0", "Cairo", "August 1996", "4.0", "4.0", 1381, -1], _ ["Windows 2000", "NT 5.0", "February 2000", "5.0", "5.0", 2195, -1], _ ["Windows XP", "Whistler", "October 2001", "5.1", "5.1", 2600, 0], _ ["Windows XP", "Whistler", "September 9, 2002", "5.1", "SP1", 2600, 1106], _ ["Windows XP", "Whistler", "August 25, 2004", "5.1", "SP2", 2600, 2180], _ ["Windows XP", "Whistler", "April 21, 2008", "5.1", "SP3", 2600, 5512], _ ["Windows Server 2003", "Whistler Server", "April 2003", "5.2", "5.2", 3790, 0], _ ["Windows Server 2003", "Whistler Server R2", "December 2005", "5.2", "R2", 3790, 3959], _ ["Windows Vista", "Longhorn", "January 2007", "6.0", "6.0", 6000, 0], _ ["Windows Vista", "Longhorn", "January 2007", "6.0", "SP2", 6002, 18005], _ ["Windows Server 2008", "Longhorn Server", "February 2008", "6.0", "6.0", 6001, 0], _ ["Windows 7", "Blackcomb", "October 2009", "6.1", "6.1", 7600, 0], _ ["Windows 7", "Blackcomb", "February 22, 2011", "6.1", "SP1", 7601, 17514], _ ["Windows Server 2008", "Windows 7 Server", "October 2009", "6.1", "R2", 7601, 0], _ ["Windows 8", "Metro", "October 2012", "6.2", "6.2", 9200, 0], _ ["Windows Server 2012", "Windows Server 8", "September 2012", "6.2", "6.2", 9200, 0], _ ["Windows 8.1", "Blue", "October 2013", "6.3", "6.3", 9600, 0], _ ["Windows 8.1", "Blue", "April 8, 2014", "6.3", "Update 1", 9600, 17031], _ ["Windows Server 2012", "Windows Server Blue", "October 2013", "6.3", "R2", 9600, 0], _ ["Windows 10", "Threshold 1", "July 29, 2015", "10.0", "1507", 10240, 16384], _ ["Windows 10", "Threshold 2", "November 12, 2015", "10.0", "1511", 10586, 17], _ ["Windows 10", "Redstone 1", "August 2, 2016", "10.0", "1607", 14393, 10], _ ["Windows 10", "Redstone 2", "April 11, 2017", "10.0", "1703", 15063, 14], _ ["Windows 10", "Redstone 3", "October 17, 2017", "10.0", "1709", 16299, 19], _ ["Windows 10", "Redstone 4", "April 30, 2018", "10.0", "1803", 17134, 1], _ ["Windows 10", "Redstone 5", "October 2, 2018", "10.0", "1809", 17763, 1], _ ["Windows 10", "19H1", "May 21, 2019", "10.0", "1903", 18362, 30], _ ["Windows 10", "19H2", "November 12, 2019", "10.0", "1909", 18363, 418], _ ["Windows 10", "20H1", "May 27, 2020", "10.0", "2004", 19041, 264], _ ["Windows 10", "20H2", "October 20, 2020", "10.0", "20H2", 19042, 508], _ ["Windows 10", "21H1", "May 18, 2021", "10.0", "21H1", 19043, 928], _ ["Windows 10", "21H2", "November 16, 2021", "10.0", "21H2", 19044, 1288], _ ["Windows 10", "22H2", "August 9, 2022", "10.0", "22H2", 19045, 2006], _ ["Windows 11", "Sun Valley", "October 5, 2021", "10.0", "21H2", 22000, 194], _ ["Windows 11", "Sun Valley 2", "May 24, 2022", "10.0", "22H2", 22621, 1], _ ["Windows 11", "Sun Valley 3", "September 20, 2022", "10.0", "23H2", 22631, 2428], _ ["Windows 11", "Sun Valley 4", "September 26, 2023", "10.0", "23H2", 22641, 1], _ ["Windows 11", "Sun Valley 5", "June 26, 2024", "10.0", "24H2", 22651, 1], _ ["Windows Server 2008", "Longhorn Server", "February 2008", "6.0", "6.0", 6001, 0], _ ["Windows Server 2008", "Windows 7 Server", "October 2009", "6.1", "R2", 7601, 0], _ ["Windows Server 2012", "Windows Server 8", "September 2012", "6.2", "6.2", 9200, 0], _ ["Windows Server 2012", "Windows Server Blue", "October 2013", "6.3", "R2", 9600, 0], _ ["Windows Server 2016", "Windows Server vNext", "October 2016", "10.0", "1607", 14393, 0], _ ["Windows Server 2019", "Windows Server vNext", "October 2018", "10.0", "1809", 17763, 0], _ ["Windows Server 2022", "Windows Server vNext", "August 2021", "10.0", "21H2", 20348, 169], _ ["Windows Server 2025", "Windows Server vNext", "November 2024", "10.0", "24H2", 26100, 1] _ ] ; Copy entries to DB array For $i = 0 To UBound($aEntries) - 1 For $j = 0 To 6 $aDB[$i][$j] = $aEntries[$i][$j] Next Next Return $aDB EndFunc ;==>__WinVerDetect_InitExactWindowsVersionDB ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_InitWindowsVersionDB ; Description ...: Initializes the range-based version database for broad version inference. Called at compile time. ; Syntax ........: __WinVerDetect_InitWindowsVersionDB() ; Parameters ....: None ; Return values .: 2D Array: [22][3] with [MinBuild, MaxBuild, ProductName] ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Extended ranges for Windows 11 and Server 2025 ; Remarks .......: - MaxBuild = -1 indicates open-ended range (future builds). ; | - Used when exact DB fails. ; Related .......: __WinVerDetect_GetVersionFromDB ; =============================================================================================================================== Func __WinVerDetect_InitWindowsVersionDB() ; Define 2D array structure: [MinBuild, MaxBuild, ProductName] Local $aDB[19][3] ; Source data entries (ranges for inference) Local $aEntries[19][3] = [ _ [511, 528, "Windows NT 3.1"], _ [807, 807, "Windows NT 3.5"], _ [950, 950, "Windows 95"], _ [1057, 1057, "Windows NT 3.51"], _ [1381, 1381, "Windows NT 4.0"], _ [1998, 2222, "Windows 98"], _ [2195, 2195, "Windows 2000"], _ [2600, 2600, "Windows XP"], _ [3000, 3000, "Windows Me"], _ [3790, 3790, "Windows Server 2003"], _ [6000, 6001, "Windows Vista"], _ [7600, 7601, "Windows 7"], _ [9200, 9200, "Windows 8"], _ [9600, 9600, "Windows 8.1"], _ [10240, 19045, "Windows 10"], _ [22000, 22651, "Windows 11"], _ [20348, 20348, "Windows Server 2022"], _ [26100, 26100, "Windows Server 2025"] _ ] ; Copy entries to DB array For $i = 0 To UBound($aEntries) - 1 For $j = 0 To 2 $aDB[$i][$j] = $aEntries[$i][$j] Next Next Return $aDB EndFunc ;==>__WinVerDetect_InitWindowsVersionDB Func __WinVerDetect_InitEditionMap() Dim $l_aEditionMap[20][3] Local $iIndex = 0 $l_aEditionMap[$iIndex][0] = "corecountryspecific" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Home China" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "professionalcountryspecific" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Pro China" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "coren" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Home N" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "professionaln" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Pro N" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "corekn" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Home KN" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "professionalkn" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Pro KN" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "enterprises" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Enterprise LTSC" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "iotenterprise" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "IoT Enterprise" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "professional" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Pro" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "education" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Education" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "serverstandard" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Server Standard" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "serverdatacenter" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Server Datacenter" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "enterpriseg" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Enterprise G" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "enterprise" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Enterprise" $iIndex += 1 ReDim $l_aEditionMap[$iIndex][3] Return $l_aEditionMap EndFunc ;==>__WinVerDetect_InitEditionMap ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_GetVersionNameByBuild ; Description ...: Constructs a full version name string based on build, using DB or inference. Used as fallback. ; Syntax ........: __WinVerDetect_GetVersionNameByBuild($iBuild, $sDisplayVersion, $sProductName[, $iUBR = 0]) ; Parameters ....: $iBuild - Integer: Build number ; $sDisplayVersion- String: Known display version (fallback to inference) ; $sProductName - String: Known product name ; $iUBR - Integer: UBR (optional) ; Return values .: String: Full version name (e.g., "Windows 10 Version 22H2 (Build 19045)") ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added server-specific formatting (no build in name for servers) ; Related .......: __WinVerDetect_GetVersionFromDB, __WinVerDetect_GetFallbackVersionName ; =============================================================================================================================== Func __WinVerDetect_GetVersionNameByBuild($iBuild, $sDisplayVersion, $sProductName, $iUBR = 0) Local $bIsServer = (StringInStr($sProductName, "Server") > 0) ; Check if server edition ; ==== Check exact DB ==== For $i = 0 To UBound($_g_aWinVerExactDB) - 1 Local $dbProduct = $_g_aWinVerExactDB[$i][0] Local $dbCodename = $_g_aWinVerExactDB[$i][1] Local $dbDate = $_g_aWinVerExactDB[$i][2] Local $dbVersion = $_g_aWinVerExactDB[$i][3] Local $dbDispVer = $_g_aWinVerExactDB[$i][4] Local $dbBuild = $_g_aWinVerExactDB[$i][5] Local $dbUBR = $_g_aWinVerExactDB[$i][6] If $iBuild = $dbBuild And ($iUBR = $dbUBR Or $dbUBR = -1) Then ; Ưu tiên ProductName đầu vào, fallback DB Local $sTemplate = $sProductName <> "" ? $sProductName : $dbProduct ; --- Thêm DisplayVersion/Version --- If $dbDispVer <> "" Then ; Nếu ProductName đã chứa rồi thì bỏ qua If StringInStr($sTemplate, $dbDispVer) = 0 Then ; Nếu DisplayVersion = Version và là số → "Version X" If $dbDispVer = $dbVersion And StringIsDigit(StringReplace($dbDispVer, ".", "")) Then $sTemplate &= " Version " & $dbVersion Else $sTemplate &= " " & $dbDispVer EndIf EndIf ElseIf $dbVersion <> "" Then If StringInStr($sTemplate, $dbVersion) = 0 Then $sTemplate &= " Version " & $dbVersion EndIf EndIf ; --- Build --- Local $sBuild = "(Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")" $sTemplate &= " " & $sBuild ; --- Date --- If $dbDate <> "" Then $sTemplate &= " (" & $dbDate & ")" ; --- Codename --- If $dbCodename <> "" Then $sTemplate &= " (" & $dbCodename & ")" Return $sTemplate EndIf Next ; ==== Fallback to range DB ==== For $i = 0 To UBound($_g_aWinVerRangeDB) - 1 If $iBuild >= $_g_aWinVerRangeDB[$i][0] And ($iBuild <= $_g_aWinVerRangeDB[$i][1] Or $_g_aWinVerRangeDB[$i][1] = -1) Then Local $sTemplate = $sProductName <> "" ? $sProductName : $_g_aWinVerRangeDB[$i][2] If StringInStr($sTemplate, "Future") Then $sTemplate = $bIsServer ? "Windows Server" : "Windows" EndIf ; Ưu tiên DisplayVersion đầu vào, fallback infer Local $sDisplay = $sDisplayVersion <> "" ? $sDisplayVersion : __WinVerDetect_InferDisplayVersion($iBuild) If $sDisplay <> "" And StringInStr($sTemplate, $sDisplay) = 0 Then $sTemplate &= " " & $sDisplay EndIf $sTemplate &= " (Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")" Return $sTemplate EndIf Next ; ==== Ultimate fallback ==== Return __WinVerDetect_GetFallbackVersionName($iBuild, $sDisplayVersion, $bIsServer) EndFunc ;==>__WinVerDetect_GetVersionNameByBuild ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_InferEditionType ; Description ...: Infers edition type (e.g., "Professional") from ProductName or EditionID. ; Syntax ........: __WinVerDetect_InferEditionType($sProductName, $sEditionID) ; Parameters ....: $sProductName - String: Full product name ; $sEditionID - String: Registry EditionID (takes precedence) ; Return values .: String: Inferred edition type ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added EnterpriseS handling ; Remarks .......: - Prioritizes EditionID if provided. ; | - Case-insensitive keyword matching. ; Related .......: _WinVerDetect_GetVersion ; =============================================================================================================================== Func __WinVerDetect_InferEditionType($sProductName, $sEditionID = '') Local $sLowerID = StringLower($sEditionID) If $sLowerID <> '' Then For $i = 0 To UBound($g_aEditionMap) - 1 If StringInStr($sLowerID, $g_aEditionMap[$i][0]) > 0 Then Return $g_aEditionMap[$i][2] EndIf Next EndIf Local $sLower = StringLower($sProductName) If StringInStr($sLower, "server") Then If StringInStr($sLower, "2022") Or StringInStr($sLower, "2025") Then If StringInStr($sLower, "azure") Then Return "Server Datacenter: Azure Edition" If StringInStr($sLower, "datacenter") Then Return "Server Datacenter" If StringInStr($sLower, "standard") Then Return "Server Standard" If StringInStr($sLower, "essentials") Then Return "Server Essentials" Return "Server" EndIf If StringInStr($sLower, "2019") Then If StringInStr($sLower, "essentials") Then Return "Server Essentials" If StringInStr($sLower, "datacenter") Then Return "Server Datacenter" If StringInStr($sLower, "standard") Then Return "Server Standard" Return "Server 2019" EndIf If StringInStr($sLower, "2016") Then If StringInStr($sLower, "essentials") Then Return "Server Essentials" If StringInStr($sLower, "datacenter") Then Return "Server Datacenter" If StringInStr($sLower, "standard") Then Return "Server Standard" If StringInStr($sLower, "foundation") Then Return "Server Foundation" Return "Server 2016" EndIf If StringInStr($sLower, "essentials") Then Return "Server Essentials" If StringInStr($sLower, "datacenter") Then Return "Server Datacenter" If StringInStr($sLower, "standard") Then Return "Server Standard" Return "Server" EndIf If StringInStr($sLower, "windows 11") Then If StringInStr($sLower, "mixed reality") Then Return "Mixed Reality" If StringInStr($sLower, "iot enterprise") Then Return "IoT Enterprise" If StringInStr($sLower, "pro education") Then Return "Pro Education" If StringInStr($sLower, "pro for workstations") Then Return "Pro for Workstations" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "education") Then Return "Education" If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro" If StringInStr($sLower, "home") Then Return "Home" Return "Windows 11" EndIf If StringInStr($sLower, "windows 10") Then If StringInStr($sLower, "mobile enterprise") Then Return "Mobile Enterprise" If StringInStr($sLower, "mobile") Then Return "Mobile" If StringInStr($sLower, "iot enterprise") Then Return "IoT Enterprise" If StringInStr($sLower, "iot core") Then Return "IoT Core" If StringInStr($sLower, "pro education") Then Return "Pro Education" If StringInStr($sLower, "pro for workstations") Then Return "Pro for Workstations" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "education") Then Return "Education" If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro" If StringInStr($sLower, "home") Then Return "Home" Return "Windows 10" EndIf If StringInStr($sLower, "windows 8.1") Or StringInStr($sLower, "8.1") Then If StringInStr($sLower, "rt") Then Return "RT" If StringInStr($sLower, "single language") Then Return "Single Language" If StringInStr($sLower, "pro") And StringInStr($sLower, "media center") Then Return "Pro with Media Center" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro" If StringInStr($sLower, "core") Or StringInStr($sLower, "windows 8.1") Then Return "Core" Return "Windows 8.1" EndIf If StringInStr($sLower, "windows 8") Then If StringInStr($sLower, "rt") Then Return "RT" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro" If StringInStr($sLower, "core") Or StringInStr($sLower, "windows 8") Then Return "Core" Return "Windows 8" EndIf If StringInStr($sLower, "windows 7") Or StringInStr($sLower, "7") Then If StringInStr($sLower, "starter") Then Return "Starter" If StringInStr($sLower, "home basic") Then Return "Home Basic" If StringInStr($sLower, "home premium") Then Return "Home Premium" If StringInStr($sLower, "ultimate") Then Return "Ultimate" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "professional") Then Return "Professional" Return "Windows 7" EndIf If StringInStr($sLower, "embedded") Then Return "Embedded" If StringInStr($sLower, "starter") Then Return "Starter" If StringInStr($sLower, "ultimate") Then Return "Ultimate" If StringInStr($sLower, "mixed reality") Then Return "Mixed Reality" If StringInStr($sLower, "iot enterprise") Then Return "IoT Enterprise" If StringInStr($sLower, "iot core") Then Return "IoT Core" If StringInStr($sLower, "iot") Then Return "IoT" If StringInStr($sLower, "mobile enterprise") Then Return "Mobile Enterprise" If StringInStr($sLower, "mobile") Then Return "Mobile" If StringInStr($sLower, "rt") Then Return "RT" If StringInStr($sLower, "pro for workstations") Then Return "Pro for Workstations" If StringInStr($sLower, "workstation") Then Return "Workstation" If StringInStr($sLower, "pro education") Then Return "Pro Education" If StringInStr($sLower, "education") Then Return "Education" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then If StringInStr($sLower, "media center") Then Return "Pro with Media Center" Return "Professional" EndIf If StringInStr($sLower, "home premium") Then Return "Home Premium" If StringInStr($sLower, "home basic") Then Return "Home Basic" If StringInStr($sLower, "home") Then Return "Home" If StringInStr($sLower, "core") Then Return "Core" If StringInStr($sLower, "single language") Then Return "Single Language" If StringInStr($sLower, "millennium") Then Return "Millennium Edition" If StringInStr($sLower, "second edition") Then Return "Second Edition" If $sProductName <> "" Then Return "Standard" Return "Unknown" EndFunc ;==>__WinVerDetect_InferEditionType ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_InferDisplayVersion ; Description ...: Infers the display version (e.g., "22H2") from the build number using known thresholds. ; Syntax ........: __WinVerDetect_InferDisplayVersion($iBuild) ; Parameters ....: $iBuild - Integer: Build number ; Return values .: String: Display version (e.g., "22H2"); Empty string if unknown ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added support for builds >=26100 (Server 2025/Win11 24H2) ; Remarks .......: - Uses descending thresholds for accurate inference. ; | - Covers from Windows 1.0 to future builds. ; Related .......: __WinVerDetect_FillMissingInfo ; =============================================================================================================================== Func __WinVerDetect_InferDisplayVersion($iBuild) ; Legacy NT-based If $iBuild = 9600 Then Return "6.3" If $iBuild = 9200 Then Return "6.2" If $iBuild = 7600 Or $iBuild = 7601 Then Return "6.1" If $iBuild = 6000 Or $iBuild = 6001 Then Return "6.0" If $iBuild = 3790 Then Return "5.2" If $iBuild = 2600 Then Return "5.1" If $iBuild = 2195 Then Return "5.0" If $iBuild = 1381 Then Return "4.0" If $iBuild = 1057 Then Return "3.51" If $iBuild = 807 Then Return "3.5" ; 9x/ME If $iBuild = 3000 Then Return "4.9" If $iBuild = 1998 Then Return "4.1" If $iBuild = 950 Then Return "4.0" If $iBuild = 528 Then Return "3.1" ; Modern Windows 11/Server 2025 If $iBuild >= 26100 Then Return "24H2" If $iBuild >= 22631 Then Return "23H2" If $iBuild >= 22621 Then Return "22H2" If $iBuild >= 22000 Then Return "21H2" ; Windows 10 If $iBuild >= 19045 Then Return "22H2" If $iBuild >= 19044 Then Return "21H2" If $iBuild >= 19043 Then Return "21H1" If $iBuild >= 19042 Then Return "20H2" If $iBuild >= 19041 Then Return "2004" If $iBuild >= 18363 Then Return "1909" If $iBuild >= 18362 Then Return "1903" If $iBuild >= 17134 Then Return "1803" If $iBuild >= 16299 Then Return "1709" If $iBuild >= 15063 Then Return "1703" If $iBuild >= 14393 Then Return "1607" If $iBuild >= 10586 Then Return "1511" If $iBuild >= 10240 Then Return "1507" Return "" ; Unknown build EndFunc ;==>__WinVerDetect_InferDisplayVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_GetFallbackVersionName ; Description ...: Generates a basic fallback version name when DB lookup fails. ; Syntax ........: __WinVerDetect_GetFallbackVersionName($iBuild, $sDisplayVersion, $bIsServer) ; Parameters ....: $iBuild - Integer: Build number ; $sDisplayVersion- String: Optional display version ; $bIsServer - Boolean: True if server edition ; Return values .: String: Basic name (e.g., "Windows (Build 12345)") ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Simplified for server/client distinction ; Remarks .......: - Used as last resort. ; Related .......: __WinVerDetect_GetVersionNameByBuild ; =============================================================================================================================== Func __WinVerDetect_GetFallbackVersionName($iBuild, $sDisplayVersion, $bIsServer) Local $sFallback = $bIsServer ? "Windows Server" : "Windows" If $sDisplayVersion <> "" Then $sFallback &= " Version " & $sDisplayVersion EndIf If Not $bIsServer Then $sFallback &= " (Build " & $iBuild & ")" EndIf Return $sFallback EndFunc ;==>__WinVerDetect_GetFallbackVersionName ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_IsInsiderPreview ; Description ...: Checks live registry for Insider Preview indicators. ; Syntax ........: __WinVerDetect_IsInsiderPreview() ; Parameters ....: None ; Return values .: Boolean: True if Insider (ContentType or ReleaseType contains "Insider") ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Checks both ContentType and ReleaseType ; Remarks .......: - Only for live systems. ; Related .......: __WinVerDetect_IsOfflineInsiderPreview ; =============================================================================================================================== Func __WinVerDetect_IsInsiderPreview() Local $sKey = "HKLM\" & $REG_KEY_INSIDER Local $sType = RegRead($sKey, "ContentType") If @error Or $sType = "" Then $sType = RegRead($sKey, "ReleaseType") ; Fallback key EndIf Return (Not @error And StringInStr($sType, "Insider") > 0) EndFunc ;==>__WinVerDetect_IsInsiderPreview ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_NormalizePath ; Description ...: Normalizes a file path, handling long paths (>240 chars) with \\?\ prefix and resolving full path via API. ; Syntax ........: __WinVerDetect_NormalizePath($sPath) ; Parameters ....: $sPath - String: Input path ; Return values .: String: Normalized full path without trailing slashes ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Uses DllCall for GetFullPathNameW ; Remarks .......: - Ensures compatibility with long paths in Windows. ; Related .......: DllCall("kernel32.dll", "GetFullPathNameW") ; =============================================================================================================================== Func __WinVerDetect_NormalizePath($sPath) ; Add \\?\ prefix for long paths If StringLeft($sPath, 4) <> "\\?\" And StringLen($sPath) > 240 Then $sPath = "\\?\" & $sPath EndIf ; Use Windows API to get full path Local $tBuf = DllStructCreate("wchar[" & $MAX_PATH & "]") Local $aRet = DllCall("kernel32.dll", "dword", "GetFullPathNameW", "wstr", $sPath, "dword", $MAX_PATH, "ptr", DllStructGetPtr($tBuf), "ptr", 0) If @error Or $aRet[0] = 0 Then ; Fallback: Simple replace Return StringReplace($sPath, "/", "\") EndIf ; Remove trailing backslashes Return StringRegExpReplace(DllStructGetData($tBuf, 1), "\\+$", "") EndFunc ;==>__WinVerDetect_NormalizePath ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_IsValidWindowsPath ; Description ...: Validates if a path is a valid Windows installation by checking key directories and files. ; Syntax ........: __WinVerDetect_IsValidWindowsPath($sPath) ; Parameters ....: $sPath - String: Path to check ; Return values .: Boolean: True if valid Windows dir ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added kernel32/ntdll existence check ; Remarks .......: - Requires System32, Config, and at least one core DLL. ; Related .......: FileExists (built-in) ; =============================================================================================================================== Func __WinVerDetect_IsValidWindowsPath($sPath) If Not FileExists($sPath) Then Return False EndIf ; Check essential directories If Not FileExists($sPath & "\System32") Or Not FileExists($sPath & "\System32\Config") Then Return False EndIf ; Count core files Local $iCount = 0 If FileExists($sPath & "\System32\kernel32.dll") Then $iCount += 1 If FileExists($sPath & "\System32\ntdll.dll") Then $iCount += 1 Return $iCount > 0 ; At least one core file EndFunc ;==>__WinVerDetect_IsValidWindowsPath ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_IsSystemLive ; Description ...: Determines if the path is a live (running) Windows system by checking file locks on key files. ; Syntax ........: __WinVerDetect_IsSystemLive($sPath) ; Parameters ....: $sPath - String: Path to check ; Return values .: Boolean: True if live (files locked by kernel) ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added ntoskrnl.exe check ; Remarks .......: - Compares to @WindowsDir first for quick live check. ; | - Uses CreateFile to test locks. ; Related .......: __WinVerDetect_IsFileLocked ; =============================================================================================================================== Func __WinVerDetect_IsSystemLive($sPath) ; Quick check: If matches current Windows dir, it's live If __WinVerDetect_NormalizePath(@WindowsDir) = $sPath Then Return True EndIf ; Check locks on key files (in-use by running system) Local $aCheck[3] = [$sPath & "\System32\Config\SYSTEM", $sPath & "\System32\Config\SOFTWARE", $sPath & "\System32\ntoskrnl.exe"] For $sFile In $aCheck If __WinVerDetect_IsFileLocked($sFile) Then Return True ; Locked = in use by live system EndIf Next Return False EndFunc ;==>__WinVerDetect_IsSystemLive ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_IsFileLocked ; Description ...: Tests if a file is locked (in use) using CreateFile API. ; Syntax ........: __WinVerDetect_IsFileLocked($sFile) ; Parameters ....: $sFile - String: File path to test ; Return values .: Boolean: True if locked (cannot open) ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Uses wide char (W) for Unicode support ; Remarks .......: - INVALID_HANDLE_VALUE (-1) indicates lock. ; Related .......: DllCall("kernel32.dll", "CreateFileW") ; =============================================================================================================================== Func __WinVerDetect_IsFileLocked($sFile) If Not FileExists($sFile) Then Return False EndIf ; Attempt to open file with read share Local $h = DllCall("kernel32.dll", "handle", "CreateFileW", "wstr", $sFile, "dword", $GENERIC_READ, "dword", $FILE_SHARE_READ, "ptr", 0, "dword", $OPEN_EXISTING, "dword", 0, "handle", 0) If @error Or $h[0] = -1 Then ; -1 = INVALID_HANDLE_VALUE Return True ; Cannot open = locked EndIf ; Close handle if opened successfully DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $h[0]) Return False EndFunc ;==>__WinVerDetect_IsFileLocked ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_LoadOfflineHive ; Description ...: Loads an offline registry hive into HKLM using RegLoadKeyW. Requires SeBackupPrivilege. ; Syntax ........: __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey) ; Parameters ....: $sHiveFile - String: Path to hive file (e.g., SOFTWARE) ; $sTempKey - String: Temporary subkey name under HKLM ; Return values .: Boolean: True if loaded successfully ($ERROR_SUCCESS) ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Integrated privilege enablement ; Remarks .......: - Enables backup privilege before loading. ; Related .......: __WinVerDetect_EnableBackupPrivilege, RegLoadKeyW ; =============================================================================================================================== Func __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey) ; Enable required privilege If Not __WinVerDetect_EnableBackupPrivilege() Then Return False EndIf ; Load hive via API Local $aRet = DllCall("advapi32.dll", "long", "RegLoadKeyW", "handle", $HKEY_LOCAL_MACHINE, "wstr", $sTempKey, "wstr", $sHiveFile) Return (IsArray($aRet) And $aRet[0] = $ERROR_SUCCESS) EndFunc ;==>__WinVerDetect_LoadOfflineHive ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_UnloadOfflineHive ; Description ...: Unloads a temporarily loaded registry hive from HKLM. ; Syntax ........: __WinVerDetect_UnloadOfflineHive($sTempKey) ; Parameters ....: $sTempKey - String: Temporary subkey to unload ; Return values .: Boolean: True if unloaded successfully ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Uses RegUnloadKeyW for Unicode ; Remarks .......: - Always call after loading to avoid leaks. ; Related .......: RegUnloadKeyW ; =============================================================================================================================== Func __WinVerDetect_UnloadOfflineHive($sTempKey) Local $aRet = DllCall("advapi32.dll", "long", "RegUnloadKeyW", "handle", $HKEY_LOCAL_MACHINE, "wstr", $sTempKey) Return (IsArray($aRet) And $aRet[0] = $ERROR_SUCCESS) EndFunc ;==>__WinVerDetect_UnloadOfflineHive ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_EnableBackupPrivilege ; Description ...: Enables SeBackupPrivilege on the current process token for hive operations. ; Syntax ........: __WinVerDetect_EnableBackupPrivilege() ; Parameters ....: None ; Return values .: Boolean: True if privilege enabled ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Full token privilege adjustment ; Remarks .......: - Uses AdjustTokenPrivileges API. ; | - Closes token handle on exit. ; Related .......: LookupPrivilegeValueW, AdjustTokenPrivileges ; =============================================================================================================================== Func __WinVerDetect_EnableBackupPrivilege() ; Get current process handle Local $hProc = DllCall("kernel32.dll", "handle", "GetCurrentProcess")[0] ; Open process token Local $a = DllCall("advapi32.dll", "bool", "OpenProcessToken", "handle", $hProc, "dword", 0x00000020, "handle*", 0) ; TOKEN_ADJUST_PRIVILEGES If @error Or Not $a[0] Then Return False EndIf Local $hToken = $a[3] ; Token handle ; Lookup LUID for SeBackupPrivilege Local $tLUID = DllStructCreate("int64") DllCall("advapi32.dll", "bool", "LookupPrivilegeValueW", "ptr", 0, "wstr", $SE_BACKUP_PRIVILEGE, "ptr", DllStructGetPtr($tLUID)) ; Prepare privilege structure: Enabled, LUID, Attributes=SE_PRIVILEGE_ENABLED Local $tPriv = DllStructCreate("dword;int64;dword") DllStructSetData($tPriv, 1, 1) ; PrivilegeCount DllStructSetData($tPriv, 2, DllStructGetData($tLUID, 1)) ; LUID DllStructSetData($tPriv, 3, 0x00000002) ; SE_PRIVILEGE_ENABLED ; Adjust token privileges Local $aAdjust = DllCall("advapi32.dll", "bool", "AdjustTokenPrivileges", "handle", $hToken, "bool", False, "ptr", DllStructGetPtr($tPriv), "dword", 0, "ptr", 0, "ptr", 0) Local $bSuccess = (IsArray($aAdjust) And $aAdjust[0]) ; Close token DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hToken) Return $bSuccess EndFunc ;==>__WinVerDetect_EnableBackupPrivilege ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_GenerateUniqueKey ; Description ...: Generates a unique temporary registry key name using GUID. ; Syntax ........: __WinVerDetect_GenerateUniqueKey() ; Parameters ....: None ; Return values .: String: Unique key (e.g., "TEMP_A1B2C3D4") ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Uses CoCreateGuid for randomness ; Remarks .......: - Prefix "TEMP_" for identification. ; Related .......: CoCreateGuid ; =============================================================================================================================== Func __WinVerDetect_GenerateUniqueKey() ; Create GUID structure Local $tGUID = DllStructCreate("byte[16]") DllCall("ole32.dll", "int", "CoCreateGuid", "ptr", DllStructGetPtr($tGUID)) ; Convert to hex string (first 8 chars for simplicity) Local $sHex = "" For $i = 1 To 16 $sHex &= StringFormat("%02X", DllStructGetData($tGUID, 1, $i)) Next Return "TEMP_" & StringLeft($sHex, 16) EndFunc ;==>__WinVerDetect_GenerateUniqueKey ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_IsOfflineInsiderPreview ; Description ...: Checks offline hive for Insider Preview, similar to live but loads hive temporarily. ; Syntax ........: __WinVerDetect_IsOfflineInsiderPreview($sPath) ; Parameters ....: $sPath - String: Offline Windows path ; Return values .: Boolean: True if Insider detected ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Mirrors live check with hive load/unload ; Remarks .......: - Requires admin; unloads hive after check. ; Related .......: __WinVerDetect_LoadOfflineHive, __WinVerDetect_UnloadOfflineHive ; =============================================================================================================================== Func __WinVerDetect_IsOfflineInsiderPreview($sPath) Local $sHiveFile = $sPath & $HIVE_SOFTWARE If Not FileExists($sHiveFile) Then Return False EndIf Local $sTempKey = __WinVerDetect_GenerateUniqueKey() If Not __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey) Then Return False EndIf ; Check Insider keys in loaded hive Local $sInsiderKey = "HKLM\" & $sTempKey & "\" & $REG_KEY_INSIDER Local $sType = RegRead($sInsiderKey, "ContentType") If @error Or $sType = "" Then $sType = RegRead($sInsiderKey, "ReleaseType") EndIf Local $bResult = (Not @error And StringInStr($sType, "Insider") > 0) ; Cleanup __WinVerDetect_UnloadOfflineHive($sTempKey) Return $bResult EndFunc ;==>__WinVerDetect_IsOfflineInsiderPreview ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_ArrayToString ; Description ...: Converts an array to a delimited string, starting from optional index. ; Syntax ........: __WinVerDetect_ArrayToString($aArray[, $sDelimiter = "|"[, $iStart = 0]]) ; Parameters ....: $aArray - Array: Input array ; $sDelimiter- String: Delimiter (default: "|") ; $iStart - Integer: Starting index (default: 0) ; Return values .: String: Joined array elements ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Handles empty arrays ; Remarks .......: - Similar to _ArrayToString but custom for UDF compatibility. ; Related .......: _RegReadMulti ; =============================================================================================================================== Func __WinVerDetect_ArrayToString($aArray, $sDelimiter = "|", $iStart = 0) If Not IsArray($aArray) Or UBound($aArray) <= $iStart Then Return "" EndIf Local $sResult = $aArray[$iStart] For $i = $iStart + 1 To UBound($aArray) - 1 $sResult &= $sDelimiter & $aArray[$i] Next Return $sResult EndFunc ;==>__WinVerDetect_ArrayToString ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_LogError ; Description ...: Logs error messages to console for debugging (internal use). ; Syntax ........: __WinVerDetect_LogError($sMsg) ; Parameters ....: $sMsg - String: Error message ; Return values .: None (outputs to console) ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Simple console output ; Remarks .......: - Prefix with "!" for visibility. ; Related .......: ConsoleWrite (built-in) ; =============================================================================================================================== Func __WinVerDetect_LogError($sMsg) ConsoleWrite("! " & $sMsg & @CRLF) EndFunc ;==>__WinVerDetect_LogError : TEST : expandcollapse popup#Region TEST_SUITE ; #EXAMPLE# ===================================================================================================================== ; To run the test suite, call the function: _RunTestSuite() _RunTestSuite() ; =============================================================================================================================== ;======================================================================================================= ; Function: _RunTestSuite() ; Description: Runs the comprehensive test suite for the UDF and prints the results to the console. ; Return Value: True if all tests passed, False otherwise. ;======================================================================================================= Func _RunTestSuite() Local $iPassed = 0, $iFailed = 0, $iSkipped = 0, $iTotal = 0 ; List of test functions to execute Local $aTestsToRun[] = [ _ "_TestDatabaseInitialization", _ "_TestLiveSystemDetection", _ "_TestUtilityFunctions", _ "_TestErrorHandling", _ "_TestVersionInference", _ "_TestPathValidation", _ "_TestIndividualFieldAccess", _ "_TestSpecificBuildsAndNames", _ "_TestShortNameEdgeCases", _ "_TestLiveSystemDetails", _ "_TestSpecialEditionDetection", _ ; New Test Case 10 "_TestComprehensiveVersionNames" _ ; New Test Case 11 ] $iTotal = UBound($aTestsToRun) _PrintTestResult("STARTING COMPREHENSIVE TEST SUITE", 3) ConsoleWrite("> UDF Library: Windows Version Detector" & @CRLF) ConsoleWrite("=====================================================================================" & @CRLF) For $sTestFunc In $aTestsToRun Local $aResult = Call($sTestFunc) ; Prettify the function name for display Local $sTestName = StringRegExpReplace($sTestFunc, "^_Test", "") $sTestName = StringRegExpReplace($sTestName, "([A-Z])", " $1") $sTestName = StringStripWS($sTestName, 1) _PrintTestResult($sTestName, $aResult[0], $aResult[1]) Switch $aResult[0] Case 1 ; PASSED $iPassed += 1 Case 0 ; FAILED $iFailed += 1 Case 2 ; SKIPPED $iSkipped += 1 EndSwitch Next ConsoleWrite("=====================================================================================" & @CRLF) _PrintTestResult("TEST SUITE SUMMARY", 3) ConsoleWrite("+ Passed : " & $iPassed & @CRLF) ConsoleWrite("! Failed : " & $iFailed & @CRLF) ConsoleWrite("- Skipped : " & $iSkipped & @CRLF) ConsoleWrite("> Total : " & $iTotal & @CRLF) Local $fSuccessRate = ($iTotal > 0 And $iTotal > $iSkipped) ? ($iPassed / ($iTotal - $iSkipped)) * 100 : 0 ConsoleWrite(StringFormat("> Success Rate (excluding skipped): %.1f%%", $fSuccessRate) & @CRLF & @CRLF) Return $iFailed = 0 EndFunc ;==>_RunTestSuite ;=============================================================================== ; Function: _PrintTestResult($sTestName, $iResult, $sDetails = "") ; Description: Internal helper function to print a formatted and colored test result. ; Parameters: $sTestName - The name of the test. ; $iResult - The result code: 1 (PASSED), 0 (FAILED), 2 (SKIPPED), 3 (INFO). ; $sDetails - [optional] Additional details to print. ;=============================================================================== Func _PrintTestResult($sTestName, $iResult, $sDetails = "") Local $sStatus, $sColorChar Local Const $iNameWidth = 35 ; Column width for the test name Switch $iResult Case 1 ; PASSED $sColorChar = "+ " $sStatus = "[ PASSED ] " Case 0 ; FAILED $sColorChar = "! " $sStatus = "[ FAILED ] " Case 2 ; SKIPPED $sColorChar = "- " $sStatus = "[ SKIPPED ] " Case Else ; INFO $sColorChar = "> " $sStatus = "[ INFO ] " $sDetails = $sTestName $sTestName = "" EndSwitch Local $sPaddedName = StringFormat("%-" & $iNameWidth & "s", $sTestName) ConsoleWrite($sColorChar & $sStatus & " " & $sPaddedName & $sDetails & @CRLF) EndFunc ;==>_PrintTestResult ; ------ INDIVIDUAL TEST CASE FUNCTIONS ------ ;=============================================================================== ; Test Case: _TestDatabaseInitialization ; Description: Verifies that the global database arrays are initialized correctly. ;=============================================================================== Func _TestDatabaseInitialization() Local $aReturn[2] If Not IsArray($_g_aWinVerRangeDB) Or UBound($_g_aWinVerRangeDB, 2) <> 3 Then $aReturn[0] = 0 $aReturn[1] = "RangeDB database is invalid or has wrong structure." Return $aReturn EndIf If Not IsArray($_g_aWinVerExactDB) Or UBound($_g_aWinVerExactDB, 2) <> 7 Then $aReturn[0] = 0 $aReturn[1] = "ExactDB database is invalid or has wrong structure." Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestDatabaseInitialization ;=============================================================================== ; Test Case: _TestLiveSystemDetection ; Description: Performs a basic check on the currently running OS. ;=============================================================================== Func _TestLiveSystemDetection() Local $aReturn[2] If Not IsAdmin() Then $aReturn[0] = 2 $aReturn[1] = "No administrator rights, skipping live system test." Return $aReturn EndIf Local $aResult = _WinVerDetect_GetVersion() If @error Then $aReturn[0] = 0 $aReturn[1] = "An error occurred during detection. Error code: " & @error Return $aReturn EndIf If Not IsArray($aResult) Or UBound($aResult) <> 10 Then $aReturn[0] = 0 $aReturn[1] = "The returned result is not a valid array." Return $aReturn EndIf If $aResult[$WINVER_STATE] <> "Live" Then $aReturn[0] = 0 $aReturn[1] = "System state was not detected as 'Live'." Return $aReturn EndIf If $aResult[$WINVER_BUILD] = "" Or Int($aResult[$WINVER_BUILD]) < 1000 Then $aReturn[0] = 0 $aReturn[1] = "Could not retrieve a valid build number (Build: " & $aResult[$WINVER_BUILD] & ")." Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "Current OS: " & $aResult[$WINVER_PRODUCTNAME] Return $aReturn EndFunc ;==>_TestLiveSystemDetection ;=============================================================================== ; Test Case: _TestUtilityFunctions ; Description: Tests helper functions like GetShortName and InferDisplayVersion. ;=============================================================================== Func _TestUtilityFunctions() Local $aReturn[2] Local $sShort = __WinVerDetect_GetShortName("Windows 11 Pro") If $sShort <> "WIN_11" Then $aReturn[0] = 0 $aReturn[1] = "GetShortName failed. Expected 'WIN_11', got '" & $sShort & "'." Return $aReturn EndIf Local $sDisplay = __WinVerDetect_InferDisplayVersion(22631) If $sDisplay <> "23H2" Then $aReturn[0] = 0 $aReturn[1] = "InferDisplayVersion failed. Expected '23H2', got '" & $sDisplay & "'." Return $aReturn EndIf Local $sVersionName = __WinVerDetect_GetVersionNameByBuild(19045, "22H2", "Windows 10 Enterprise") If Not StringInStr($sVersionName, "Windows 10 Enterprise") Or Not StringInStr($sVersionName, "22H2") Then $aReturn[0] = 0 $aReturn[1] = "GetVersionName failed. Result: " & $sVersionName Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestUtilityFunctions ;=============================================================================== ; Test Case: _TestErrorHandling ; Description: Ensures the main function correctly handles invalid inputs. ;=============================================================================== Func _TestErrorHandling() Local $aReturn[2] _WinVerDetect_GetVersion("C:\NonExistent\Path\For\Sure") If @error <> $WINVER_ERROR_INVALID_PATH Then $aReturn[0] = 0 $aReturn[1] = "Did not catch invalid path error. Error code: " & @error Return $aReturn EndIf _WinVerDetect_GetVersion("") If @error <> $WINVER_ERROR_INVALID_PATH Then $aReturn[0] = 0 $aReturn[1] = "Did not catch empty path error. Error code: " & @error Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestErrorHandling ;=============================================================================== ; Test Case: _TestVersionInference ; Description: Checks display version inference for specific build numbers. ;=============================================================================== Func _TestVersionInference() Local $aReturn[2] Local $aTestBuilds[3][2] = [[19041, "2004"], [22000, "21H2"], [26100, "24H2"]] For $i = 0 To UBound($aTestBuilds) - 1 Local $sInferred = __WinVerDetect_InferDisplayVersion($aTestBuilds[$i][0]) If $sInferred <> $aTestBuilds[$i][1] Then $aReturn[0] = 0 $aReturn[1] = "Inference failed for Build " & $aTestBuilds[$i][0] & ". Expected '" & $aTestBuilds[$i][1] & "', got '" & $sInferred & "'." Return $aReturn EndIf Next $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestVersionInference ;=============================================================================== ; Test Case: _TestPathValidation ; Description: Tests the __WinVerDetect_IsValidWindowsPath helper function. ;=============================================================================== Func _TestPathValidation() Local $aReturn[2] If Not __WinVerDetect_IsValidWindowsPath(@WindowsDir) Then $aReturn[0] = 0 $aReturn[1] = "Failed to validate current Windows directory (" & @WindowsDir & ")." Return $aReturn EndIf If __WinVerDetect_IsValidWindowsPath(@TempDir) Then $aReturn[0] = 0 $aReturn[1] = "Incorrectly validated Temp directory (" & @TempDir & ") as a Windows path." Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestPathValidation ;=============================================================================== ; Test Case: _TestIndividualFieldAccess ; Description: Tests retrieving a single field using the $iReturnIndex parameter. ;=============================================================================== Func _TestIndividualFieldAccess() Local $aReturn[2] If Not IsAdmin() Then $aReturn[0] = 2 $aReturn[1] = "Admin rights required." Return $aReturn EndIf Local $sBuild = _WinVerDetect_GetVersion(@WindowsDir, $WINVER_BUILD) If @error Or $sBuild = "" Or Int($sBuild) < 1000 Then $aReturn[0] = 0 $aReturn[1] = "Failed to retrieve individual Build Number. Error: " & @error Return $aReturn EndIf Local $sProductName = _WinVerDetect_GetVersion(@WindowsDir, $WINVER_PRODUCTNAME) If @error Or $sProductName = "" Then $aReturn[0] = 0 $aReturn[1] = "Failed to retrieve individual ProductName. Error: " & @error Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "Build: " & $sBuild & ", Product: " & $sProductName Return $aReturn EndFunc ;==>_TestIndividualFieldAccess ;=============================================================================== ; Test Case: _TestSpecificBuildsAndNames ; Description: Tests version name generation against known data points. ;=============================================================================== Func _TestSpecificBuildsAndNames() Local $aReturn[2] ; Test Data Format: [Build, Expected Product Name, Expected Display Version] Local $aTestCases[4][3] = [ _ [19045, "Windows 10", "22H2"], _ [22000, "Windows 11", "21H2"], _ [26100, "Windows Server 2025", "24H2"], _ [20348, "Windows Server 2022", "21H2"] _ ] For $aCase In $aTestCases Local $iBuild = $aCase[0] Local $sExpectedProduct = $aCase[1] Local $sExpectedDisplay = $aCase[2] Local $sFullName = __WinVerDetect_GetVersionNameByBuild($iBuild, "", $sExpectedProduct) If Not StringInStr($sFullName, $sExpectedProduct) Or Not StringInStr($sFullName, $sExpectedDisplay) Then $aReturn[0] = 0 $aReturn[1] = StringFormat("Build %d failed. Expected '%s %s', got '%s'", $iBuild, $sExpectedProduct, $sExpectedDisplay, $sFullName) Return $aReturn EndIf Next $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestSpecificBuildsAndNames ;=============================================================================== ; Test Case: _TestShortNameEdgeCases ; Description: Tests the GetShortName function with server and unknown values. ;=============================================================================== Func _TestShortNameEdgeCases() Local $aReturn[2] If __WinVerDetect_GetShortName("Windows Server 2022") <> "WIN_2022" Then $aReturn[0] = 0 $aReturn[1] = "Failed to get short name for Server 2022." Return $aReturn EndIf Local $sReturn = __WinVerDetect_GetShortName("Some Unknown OS") If $sReturn <> "UNKNOWN" Then $aReturn[0] = 0 $aReturn[1] = "Failed to return '" & $sReturn & "' for an unrecognized OS name." Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestShortNameEdgeCases ;=============================================================================== ; Test Case: _TestLiveSystemDetails ; Description: Displays detailed information about the live operating system. ;=============================================================================== Func _TestLiveSystemDetails() Local $aReturn[2] If Not IsAdmin() Then $aReturn[0] = 2 $aReturn[1] = "Admin rights required." Return $aReturn EndIf Local $aResult = _WinVerDetect_GetVersion() If @error Then $aReturn[0] = 0 $aReturn[1] = "Could not retrieve system details. Error: " & @error Return $aReturn EndIf Local $sDetails = @CRLF $sDetails &= "> State: " & $aResult[$WINVER_STATE] & @CRLF $sDetails &= "> Short Name: " & $aResult[$WINVER_SHORTNAME] & @CRLF $sDetails &= "> ProductName: " & $aResult[$WINVER_PRODUCTNAME] & @CRLF $sDetails &= "> Full Name: " & $aResult[$WINVER_FULLNAME] & @CRLF $sDetails &= "> Build: " & $aResult[$WINVER_BUILD] & @CRLF $sDetails &= "> UBR: " & $aResult[$WINVER_UBR] & @CRLF $sDetails &= "> DisplayVersion: " & $aResult[$WINVER_DISPLAYVERSION] & @CRLF $sDetails &= "> EditionID: " & $aResult[$WINVER_EDITIONID] & @CRLF $sDetails &= "> EditionType: " & $aResult[$WINVER_EDITIONTYPE] & @CRLF $sDetails &= "> IsInsider: " & ($aResult[$WINVER_ISINSIDER] ? "Yes" : "No") & @CRLF $aReturn[0] = 1 $aReturn[1] = $sDetails Return $aReturn EndFunc ;==>_TestLiveSystemDetails ;=============================================================================== ; Test Case: _TestSpecialEditionDetection ; Description: Tests the __WinVerDetect_InferEditionType function for special edition detection. ;=============================================================================== Func _TestSpecialEditionDetection() Local $aReturn[2] Local $iPassEdition = 0 ; Test Data Format: [ProductName, EditionID, Expected EditionType] Local $aTestCases[14][3] = [ _ ["Windows 10 Home", "CoreCountrySpecific", "Home China"], _ ["Windows 11 Home", "CoreCountrySpecific", "Home China"], _ ["Windows 10 Pro", "ProfessionalCountrySpecific", "Pro China"], _ ["Windows 10 Home N", "CoreN", "Home N"], _ ["Windows 11 Pro N", "ProfessionalN", "Pro N"], _ ["Windows 10 Home KN", "CoreKN", "Home KN"], _ ["Windows 10 Enterprise G", "EnterpriseG", "Enterprise G"], _ ["Windows 10 Enterprise LTSC", "EnterpriseS", "Enterprise LTSC"], _ ["Windows 10 IoT Enterprise", "IoTEnterprise", "IoT Enterprise"], _ ["Windows Server 2019", "ServerStandard", "Server Standard"], _ ["Windows Server 2022", "ServerDatacenter", "Server Datacenter"], _ ["Windows Server 2022", "ServerStandardCore", "Server Standard"], _ ["Windows 11 Enterprise", "Enterprise", "Enterprise"], _ ["Windows 10 Education", "Education", "Education"] _ ] ConsoleWrite("> Testing special edition detection capabilities:" & @CRLF) For $i = 0 To UBound($aTestCases) - 1 Local $sProductName = $aTestCases[$i][0] Local $sEditionID = $aTestCases[$i][1] Local $sExpected = $aTestCases[$i][2] Local $sResult = __WinVerDetect_InferEditionType($sProductName, $sEditionID) Local $sStatus = ($sResult = $sExpected) ? "+ ✓ PASS" : "! ✗ FAIL" ConsoleWrite($sStatus & " | ProductName: " & StringFormat("%-28s", $sProductName) & " | EditionID: " & StringFormat("%-27s", $sEditionID) & " | Result: " & $sResult & @CRLF) If $sResult = $sExpected Then $iPassEdition += 1 Next Local $sSummary = "Result: " & $iPassEdition & "/" & UBound($aTestCases) & " passed" If $iPassEdition = UBound($aTestCases) Then $aReturn[0] = 1 $aReturn[1] = $sSummary Else $aReturn[0] = 0 $aReturn[1] = $sSummary EndIf ConsoleWrite("> " & $sSummary & @CRLF & @CRLF) Return $aReturn EndFunc ;==>_TestSpecialEditionDetection ;=============================================================================== ; Test Case: _TestComprehensiveVersionNames ; Description: Tests __WinVerDetect_GetVersionNameByBuild with various build numbers and product names. ;=============================================================================== Func _TestComprehensiveVersionNames() Local $aReturn[2] Local $iPassVersion = 0 ; Test Data Format: [Build, DisplayVersion, ProductName, Expected Full Name] Local $aTestCases[32][4] = [ _ [528, "", "", "Windows NT 3.1 (Build 528) (July 1993) (Razzle)"], _ [807, "", "", "Windows NT 3.5 (Build 807) (September 1994) (Daytona)"], _ [1057, "", "", "Windows NT 3.51 (Build 1057) (May 1995) (Daytona)"], _ [1381, "", "", "Windows NT 4.0 (Build 1381) (August 1996) (Cairo)"], _ [1381, "", "Windows NT Server 4.0", "Windows NT Server 4.0 (Build 1381) (August 1996) (Cairo)"], _ [950, "", "", "Windows 95 Version 4.0 (Build 950) (August 1995) (Chicago)"], _ [1998, "", "", "Windows 98 Version 4.1 (Build 1998) (June 1998) (Memphis)"], _ [2222, "", "", "Windows 98 SE (Build 2222) (May 1999) (Memphis)"], _ [3000, "", "", "Windows Me Version 4.9 (Build 3000) (September 2000) (Millennium)"], _ [2195, "", "", "Windows 2000 Version 5.0 (Build 2195) (February 2000) (NT 5.0)"], _ [2195, "", "Windows 2000 Server", "Windows 2000 Server Version 5.0 (Build 2195) (February 2000) (NT 5.0)"], _ [2600, "", "", "Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler)"], _ [2600, "5.1", "", "Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler)"], _ [2600, "5.1", "Windows XP Professional", "Windows XP Professional Version 5.1 (Build 2600) (October 2001) (Whistler)"], _ [3790, "", "", "Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)"], _ [3790, "5.2", "", "Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)"], _ [3790, "", "Windows Server 2003", "Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)"], _ [6000, "", "", "Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn)"], _ [6000, "6.0", "", "Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn)"], _ [7600, "", "", "Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb)"], _ [7600, "6.1", "", "Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb)"], _ [9200, "", "", "Windows 8 Version 6.2 (Build 9200) (October 2012) (Metro)"], _ [9600, "", "", "Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue)"], _ [9600, "Update1", "", "Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue)"], _ [10240, "", "", "Windows 10 1507 (Build 10240)"], _ [10240, "1507", "Windows 10", "Windows 10 1507 (Build 10240)"], _ [19045, "", "", "Windows 10 22H2 (Build 19045)"], _ [19045, "22H2", "Windows 10", "Windows 10 22H2 (Build 19045)"], _ [22000, "", "", "Windows 11 21H2 (Build 22000)"], _ [22000, "21H2", "Windows 11", "Windows 11 21H2 (Build 22000)"], _ [20348, "", "Windows Server 2022", "Windows Server 2022 22H2 (Build 20348)"], _ [26100, "", "Windows Server 2025", "Windows Server 2025 24H2 (Build 26100)"] _ ] ConsoleWrite("> Testing comprehensive version name generation for __WinVerDetect_GetVersionNameByBuild:" & @CRLF) For $i = 0 To UBound($aTestCases) - 1 Local $iBuild = $aTestCases[$i][0] Local $sDisplayVersion = $aTestCases[$i][1] Local $sProductName = $aTestCases[$i][2] Local $sExpected = $aTestCases[$i][3] Local $sActual = __WinVerDetect_GetVersionNameByBuild($iBuild, $sDisplayVersion, $sProductName) ;~ ConsoleWrite('['&$iBuild&', "'&$sDisplayVersion&'", "'&$sProductName&'", "'&$sActual&'"], _' & @CRLF) Local $sStatus = ($sActual = $sExpected) ? "+ ✓ PASS" : "! ✗ FAIL" ConsoleWrite($sStatus & " | Build: " & StringFormat("%-6s", $iBuild) & " | DisplayVersion: " & StringFormat("%-10s", $sDisplayVersion) & " | ProductName: " & StringFormat("%-30s", $sProductName) & " | Result: " & $sActual & @CRLF) If $sActual <> $sExpected Then ConsoleWrite(" -> Expected: " & $sExpected & @CRLF) ConsoleWrite(" -> Actual: " & $sActual & @CRLF) EndIf If $sActual = $sExpected Then $iPassVersion += 1 Next Local $sSummary = "Result: " & $iPassVersion & "/" & UBound($aTestCases) & " passed" If $iPassVersion = UBound($aTestCases) Then $aReturn[0] = 1 $aReturn[1] = $sSummary Else $aReturn[0] = 0 $aReturn[1] = $sSummary EndIf ConsoleWrite("> " & $sSummary & @CRLF & @CRLF) Return $aReturn EndFunc ;==>_TestComprehensiveVersionNames #EndRegion TEST_SUITE > Result test: expandcollapse popup> [ INFO ] STARTING COMPREHENSIVE TEST SUITE > UDF Library: Windows Version Detector ===================================================================================== + [ PASSED ] Database Initialization + [ PASSED ] Live System Detection Current OS: Windows 10 Enterprise LTSC 2021 + [ PASSED ] Utility Functions + [ PASSED ] Error Handling + [ PASSED ] Version Inference + [ PASSED ] Path Validation + [ PASSED ] Individual Field Access Build: 19045, Product: Windows 10 Enterprise LTSC 2021 + [ PASSED ] Specific Builds And Names + [ PASSED ] Short Name Edge Cases + [ PASSED ] Live System Details > State: Live > Short Name: WIN_10 > ProductName: Windows 10 Enterprise LTSC 2021 > Full Name: Windows 10 Version 22H2 (Build 19045.6216) > Build: 19045 > UBR: 6216 > DisplayVersion: 22H2 > EditionID: EnterpriseS > EditionType: Enterprise LTSC > IsInsider: No > Testing special edition detection capabilities: + ✓ PASS | ProductName: Windows 10 Home | EditionID: CoreCountrySpecific | Result: Home China + ✓ PASS | ProductName: Windows 11 Home | EditionID: CoreCountrySpecific | Result: Home China + ✓ PASS | ProductName: Windows 10 Pro | EditionID: ProfessionalCountrySpecific | Result: Pro China + ✓ PASS | ProductName: Windows 10 Home N | EditionID: CoreN | Result: Home N + ✓ PASS | ProductName: Windows 11 Pro N | EditionID: ProfessionalN | Result: Pro N + ✓ PASS | ProductName: Windows 10 Home KN | EditionID: CoreKN | Result: Home KN + ✓ PASS | ProductName: Windows 10 Enterprise G | EditionID: EnterpriseG | Result: Enterprise G + ✓ PASS | ProductName: Windows 10 Enterprise LTSC | EditionID: EnterpriseS | Result: Enterprise LTSC + ✓ PASS | ProductName: Windows 10 IoT Enterprise | EditionID: IoTEnterprise | Result: IoT Enterprise + ✓ PASS | ProductName: Windows Server 2019 | EditionID: ServerStandard | Result: Server Standard + ✓ PASS | ProductName: Windows Server 2022 | EditionID: ServerDatacenter | Result: Server Datacenter + ✓ PASS | ProductName: Windows Server 2022 | EditionID: ServerStandardCore | Result: Server Standard + ✓ PASS | ProductName: Windows 11 Enterprise | EditionID: Enterprise | Result: Enterprise + ✓ PASS | ProductName: Windows 10 Education | EditionID: Education | Result: Education > Result: 14/14 passed + [ PASSED ] Special Edition Detection Result: 14/14 passed > Testing comprehensive version name generation for __WinVerDetect_GetVersionNameByBuild: + ✓ PASS | Build: 528 | DisplayVersion: | ProductName: | Result: Windows NT 3.1 (Build 528) (July 1993) (Razzle) + ✓ PASS | Build: 807 | DisplayVersion: | ProductName: | Result: Windows NT 3.5 (Build 807) (September 1994) (Daytona) + ✓ PASS | Build: 1057 | DisplayVersion: | ProductName: | Result: Windows NT 3.51 (Build 1057) (May 1995) (Daytona) + ✓ PASS | Build: 1381 | DisplayVersion: | ProductName: | Result: Windows NT 4.0 (Build 1381) (August 1996) (Cairo) + ✓ PASS | Build: 1381 | DisplayVersion: | ProductName: Windows NT Server 4.0 | Result: Windows NT Server 4.0 (Build 1381) (August 1996) (Cairo) + ✓ PASS | Build: 950 | DisplayVersion: | ProductName: | Result: Windows 95 Version 4.0 (Build 950) (August 1995) (Chicago) + ✓ PASS | Build: 1998 | DisplayVersion: | ProductName: | Result: Windows 98 Version 4.1 (Build 1998) (June 1998) (Memphis) + ✓ PASS | Build: 2222 | DisplayVersion: | ProductName: | Result: Windows 98 SE (Build 2222) (May 1999) (Memphis) + ✓ PASS | Build: 3000 | DisplayVersion: | ProductName: | Result: Windows Me Version 4.9 (Build 3000) (September 2000) (Millennium) + ✓ PASS | Build: 2195 | DisplayVersion: | ProductName: | Result: Windows 2000 Version 5.0 (Build 2195) (February 2000) (NT 5.0) + ✓ PASS | Build: 2195 | DisplayVersion: | ProductName: Windows 2000 Server | Result: Windows 2000 Server Version 5.0 (Build 2195) (February 2000) (NT 5.0) + ✓ PASS | Build: 2600 | DisplayVersion: | ProductName: | Result: Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler) + ✓ PASS | Build: 2600 | DisplayVersion: 5.1 | ProductName: | Result: Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler) + ✓ PASS | Build: 2600 | DisplayVersion: 5.1 | ProductName: Windows XP Professional | Result: Windows XP Professional Version 5.1 (Build 2600) (October 2001) (Whistler) + ✓ PASS | Build: 3790 | DisplayVersion: | ProductName: | Result: Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server) + ✓ PASS | Build: 3790 | DisplayVersion: 5.2 | ProductName: | Result: Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server) + ✓ PASS | Build: 3790 | DisplayVersion: | ProductName: Windows Server 2003 | Result: Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server) + ✓ PASS | Build: 6000 | DisplayVersion: | ProductName: | Result: Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn) + ✓ PASS | Build: 6000 | DisplayVersion: 6.0 | ProductName: | Result: Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn) + ✓ PASS | Build: 7600 | DisplayVersion: | ProductName: | Result: Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb) + ✓ PASS | Build: 7600 | DisplayVersion: 6.1 | ProductName: | Result: Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb) + ✓ PASS | Build: 9200 | DisplayVersion: | ProductName: | Result: Windows 8 Version 6.2 (Build 9200) (October 2012) (Metro) + ✓ PASS | Build: 9600 | DisplayVersion: | ProductName: | Result: Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue) + ✓ PASS | Build: 9600 | DisplayVersion: Update1 | ProductName: | Result: Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue) + ✓ PASS | Build: 10240 | DisplayVersion: | ProductName: | Result: Windows 10 1507 (Build 10240) + ✓ PASS | Build: 10240 | DisplayVersion: 1507 | ProductName: Windows 10 | Result: Windows 10 1507 (Build 10240) + ✓ PASS | Build: 19045 | DisplayVersion: | ProductName: | Result: Windows 10 22H2 (Build 19045) + ✓ PASS | Build: 19045 | DisplayVersion: 22H2 | ProductName: Windows 10 | Result: Windows 10 22H2 (Build 19045) + ✓ PASS | Build: 22000 | DisplayVersion: | ProductName: | Result: Windows 11 21H2 (Build 22000) + ✓ PASS | Build: 22000 | DisplayVersion: 21H2 | ProductName: Windows 11 | Result: Windows 11 21H2 (Build 22000) + ✓ PASS | Build: 20348 | DisplayVersion: | ProductName: Windows Server 2022 | Result: Windows Server 2022 22H2 (Build 20348) + ✓ PASS | Build: 26100 | DisplayVersion: | ProductName: Windows Server 2025 | Result: Windows Server 2025 24H2 (Build 26100) > Result: 32/32 passed + [ PASSED ] Comprehensive Version Names Result: 32/32 passed ===================================================================================== > [ INFO ] TEST SUITE SUMMARY + Passed : 12 ! Failed : 0 - Skipped : 0 > Total : 12 > Success Rate (excluding skipped): 100.0% Edited September 11 by Trong v5 WildByDesign, argumentum and Musashi 3 Enjoy my work? Buy me a 🍻 or tip via ❤️ PayPal
wakillon Posted September 3 Posted September 3 Result for my PC : !_OSVersion: WIN_11 !Offline OS: UNKNOWN Build: 0 +Current OS: WIN_11 Build: 26100.4946 - ProductName: Windows 10 Home - BuildNumber: 26100|24H2|2009|6.3|4946 - VersionName: Windows 11 Version 24H2 (2024 Update) (Build 26100.4946) - Edition: Home - SystemType: Live AutoIt 3.3.18.0 X86 - SciTE 4.4.6 - WIN 11 24H2 X64 - Other Examples Scripts
argumentum Posted September 3 Posted September 3 (edited) !Offline OS: UNKNOWN Build: 0 +Current OS: WIN_2025 Build: 26100.1742 - ProductName: Windows Server 2025 Standard - BuildNumber: 26100|24H2|2009|6.3|1742 - VersionName: Windows Server 2025 (Build 26100.1742) - Edition: Server Standard - SystemType: Live !Offline OS: UNKNOWN Build: 0 +Current OS: WIN_FUTURE Build: 26200.5670 - ProductName: Windows 10 Pro - BuildNumber: 26200|25H2|2009|6.3|5670 - VersionName: Windows 11 (Insider Preview) (Build 26200.5670) - Edition: Pro - SystemType: Live !_OSVersion: WIN_11 !Offline OS: WIN_11 Build: 22621.4387 +Current OS: WIN_11 Build: 22621.4387 - ProductName: - BuildNumber: - VersionName: - Edition: - SystemType: Offline Edited September 3 by argumentum more Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Trong Posted September 4 Author Posted September 4 I have released version 2, you might want to try it argumentum 1 Enjoy my work? Buy me a 🍻 or tip via ❤️ PayPal
argumentum Posted September 4 Posted September 4 expandcollapse popup!=== Enhanced Windows Version Detector Test === > 1. Testing current system detection: - ProductName: Windows 10 Pro for Workstations - BuildNumber: 22631|23H2|2009|6.3|3737 - VersionName: Windows 11 Version 23H2 (2023 Update) (Build 22631.3737) - Edition: Professional - SystemType: Live - EditionID: ProfessionalWorkstation > 2. Testing short OS version: - OS Version: WIN_11 > 3. Testing detailed OS version: - Short Version: WIN_11 - Build with UBR: 22631.3737 - Display Version: 23H2 - Product Name: Windows 10 Pro for Workstations - Edition Type: Professional - System Type: Live > 4. Testing special edition detection capabilities: + ✓ PASS | ProductName: Windows 10 Home | EditionID: CoreCountrySpecific | Result: Home China + ✓ PASS | ProductName: Windows 11 Home | EditionID: CoreCountrySpecific | Result: Home China + ✓ PASS | ProductName: Windows 10 Pro | EditionID: ProfessionalCountrySpecific | Result: Pro China + ✓ PASS | ProductName: Windows 10 Home N | EditionID: CoreN | Result: Home N + ✓ PASS | ProductName: Windows 11 Pro N | EditionID: ProfessionalN | Result: Pro N + ✓ PASS | ProductName: Windows 10 Home KN | EditionID: CoreKN | Result: Home KN + ✓ PASS | ProductName: Windows 10 Enterprise G | EditionID: EnterpriseG | Result: Enterprise G + ✓ PASS | ProductName: Windows 10 Enterprise LTSC | EditionID: EnterpriseS | Result: Enterprise LTSC + ✓ PASS | ProductName: Windows 10 IoT Enterprise | EditionID: IoTEnterprise | Result: IoT Enterprise > 5. Testing offline system detection: - No offline Windows installations found for testing. > 6. Testing error handling with invalid path: - Error code: 3 - Result array size: 6 > 7. China-specific Windows detection capabilities: - ✓ CoreCountrySpecific EditionID → Home China - ✓ ProfessionalCountrySpecific EditionID → Pro China - ✓ EnterpriseG EditionID → Enterprise G (Government) - ✓ EnterpriseGovChina EditionID → Enterprise Government China - ✓ Supports N editions (Europe) and KN editions (Korea) - ✓ Enhanced regional market detection !=== Test Complete === I had to use a MsgBox to display: ... Console_WriteR("!=== Test Complete ===" & @CRLF) Console_WriteR() EndFunc ;==>_TEST #EndRegion TEST Func Console_WriteR($sStr = Default, $iError = @error, $iExtended = @extended) Local Static $sBuffer = "" If $sStr = Default Then MsgBox(0, @ScriptName, StringReplace($sBuffer, @LF, "")) Return SetError($iError, $iExtended,"") Else $sBuffer &= $sStr Return SetError($iError, $iExtended, ConsoleWrite($sStr)) EndIf EndFunc Are you going to have a v3 with "test 7" in the future ? How does test 4 work ?, is it broken ? Please don't answer the question with a reaction. I do not understand those as answers. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Trong Posted September 4 Author Posted September 4 Main Cause Relying entirely on the ProductName string in the registry to determine the product name. But from Windows 11 onwards, Microsoft still keeps the registry label as “Windows 10 …”, even though the OS is actually Windows 11, so you will always see ProductName = "Windows 10 Pro for Workstations". Meanwhile, the build index (22631) shows that this is exactly Windows 11. Solution: Standardize ProductName based on build Instead of forcing Windows 10 to be assigned to every ProductName containing “Windows 10”, we should reverse the situation: if build ≥ 22000 (Windows 11), change the registry label to “Windows 11 …” to reflect reality. You can try again! Enjoy my work? Buy me a 🍻 or tip via ❤️ PayPal
wakillon Posted September 4 Posted September 4 Thanks, result is ok now - ProductName: Windows 11 Home - BuildNumber: 26100|24H2|2009|6.3|4946 - VersionName: Windows 11 Version 24H2 (2024 Update) (Build 26100.4946) - Edition: Home - SystemType: Live AutoIt 3.3.18.0 X86 - SciTE 4.4.6 - WIN 11 24H2 X64 - Other Examples Scripts
argumentum Posted September 4 Posted September 4 Spoiler expandcollapse popup!=== Enhanced Windows Version Detector Test === > 1. Testing current system detection: - ProductName: Windows 11 Pro for Workstations - BuildNumber: 22631|23H2|2009|6.3|3737 - VersionName: Windows 11 Version 23H2 (2023 Update) (Build 22631.3737) - Edition: Professional - SystemType: Live - EditionID: ProfessionalWorkstation > 2. Testing short OS version: - OS Version: WIN_11 > 3. Testing detailed OS version: - Short Version: WIN_11 - Build with UBR: 22631.3737 - Display Version: 23H2 - Product Name: Windows 11 Pro for Workstations - Edition Type: Professional - System Type: Live > 4. Testing special edition detection capabilities: + ✓ PASS | ProductName: Windows 10 Home | EditionID: CoreCountrySpecific | Result: Home China + ✓ PASS | ProductName: Windows 11 Home | EditionID: CoreCountrySpecific | Result: Home China + ✓ PASS | ProductName: Windows 10 Pro | EditionID: ProfessionalCountrySpecific | Result: Pro China + ✓ PASS | ProductName: Windows 10 Home N | EditionID: CoreN | Result: Home N + ✓ PASS | ProductName: Windows 11 Pro N | EditionID: ProfessionalN | Result: Pro N + ✓ PASS | ProductName: Windows 10 Home KN | EditionID: CoreKN | Result: Home KN + ✓ PASS | ProductName: Windows 10 Enterprise G | EditionID: EnterpriseG | Result: Enterprise G + ✓ PASS | ProductName: Windows 10 Enterprise LTSC | EditionID: EnterpriseS | Result: Enterprise LTSC + ✓ PASS | ProductName: Windows 10 IoT Enterprise | EditionID: IoTEnterprise | Result: IoT Enterprise > 5. Testing offline system detection: - No offline Windows installations found for testing. > 6. Testing error handling with invalid path: - Error code: 3 - Result array size: 6 > 7. China-specific Windows detection capabilities: - ✓ CoreCountrySpecific EditionID → Home China - ✓ ProfessionalCountrySpecific EditionID → Pro China - ✓ EnterpriseG EditionID → Enterprise G (Government) - ✓ EnterpriseGovChina EditionID → Enterprise Government China - ✓ Supports N editions (Europe) and KN editions (Korea) - ✓ Enhanced regional market detection !=== Test Complete === My setup is: Keyboard:00000409 OS:WIN_11/2009 CPU:X64 OS:X64 Environment(Language:0409) Hope that helps. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Trong Posted September 11 Author Posted September 11 Updated to v5, really want to explode ><. No more fixes, I have to go back to project ImageSearchUDF beta Enjoy my work? Buy me a 🍻 or tip via ❤️ PayPal
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now