Trong Posted Saturday at 08:01 PM Posted Saturday at 08:01 PM (edited) Windows Version Detector v2: expandcollapse popup#include-once ; #INDEX# ======================================================================================================================= ; Title .........: Windows Version Detector v2 ; AutoIt Version : 3.3.16.1+ ; Description ...: Functions for accurately detecting Windows version for current or offline systems ; Author(s) .....: Dao Van Trong - TRONG.PRO ; Dll(s) ........: kernel32.dll, advapi32.dll, version.dll ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ; _DetectWindowsVersion ; _OSVersion ; _GetOSVersionDetailed ; =============================================================================================================================== ; #INTERNAL_USE_ONLY# =========================================================================================================== ; __IsSystemLive ; __IsFileLocked ; __GetLiveSystemInfo ; __GetOfflineSystemInfo ; __ReadVersionFromFiles ; __ReadOfflineRegistryDirect ; __ParseVersionFromNtoskrnl ; __ParseVersionFromKernel32 ; __GetVersionNameByBuild ; __GetEditionType ; __LoadOfflineHive ; __UnloadOfflineHive ; __EnableBackupPrivilege ; __NormalizePath ; __IsValidWindowsPath ; __ExtractBuildFromPE ; __ReadFileVersionInfo ; =============================================================================================================================== ; #CONSTANTS# =================================================================================================================== #include <FileConstants.au3> #include <APIRegConstants.au3> #include <APIErrorsConstants.au3> #include <WinAPIFiles.au3> #include <Array.au3> ; Additional constants Global Const $IMAGE_DOS_SIGNATURE = 0x5A4D ; "MZ" Global Const $IMAGE_NT_SIGNATURE = 0x00004550 ; "PE\0\0" ;~ Global Const $IMAGE_FILE_MACHINE_I386 = 0x014c ;~ Global Const $IMAGE_FILE_MACHINE_AMD64 = 0x8664 ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name ..........: _DetectWindowsVersion ; Description ...: Detects Windows version information for current or offline systems ; Syntax ........: _DetectWindowsVersion([$sWindowsPath = @WindowsDir]) ; Parameters ....: $sWindowsPath - [optional] Path to Windows directory. Default is @WindowsDir. ; Return values .: Success - Array with Windows information: ; |[0] - Product Name (e.g., "Windows 11 Pro") ; |[1] - Build Number with metadata (e.g., "22621|23H2|2009|10.0|2787") ; |[2] - Version Name (e.g., "Windows 11 Version 23H2 (2023 Update) (Build 22621.2787)") ; |[3] - Edition Type (e.g., "Professional", "Server", "Home") ; |[4] - System Type ("Live" or "Offline") ; Failure - Empty array, @error set: ; |1 - Failed to get live system info ; |2 - Failed to get offline system info ; |3 - Invalid Windows path ; Author ........: Dao Van Trong - TRONG.PRO ; Remarks .......: This function automatically detects whether the target system is live or offline ; Related .......: _OSVersion, _GetOSVersionDetailed ; =============================================================================================================================== Func _DetectWindowsVersion($sWindowsPath = @WindowsDir) Local $aResult[6] = ["", "", "", "", ""] ; [0] = ProductName, [1] = BuildNumber, [2] = VersionName, [3] = Edition, [4] = SystemType (Live/Offline), [5]=EditionID ; Validate and normalize path $sWindowsPath = __NormalizePath($sWindowsPath) If Not __IsValidWindowsPath($sWindowsPath) Then Return SetError(3, 0, $aResult) EndIf ; Determine if system is live or offline Local $bIsLive = __IsSystemLive($sWindowsPath) $aResult[4] = $bIsLive ? "Live" : "Offline" ; Get Windows information based on system type If $bIsLive Then If Not __GetLiveSystemInfo($aResult) Then Return SetError(1, 0, $aResult) EndIf Else If Not __GetOfflineSystemInfo($sWindowsPath, $aResult) Then Return SetError(2, 0, $aResult) EndIf EndIf ; Ensure we have basic information If $aResult[0] = "" Or $aResult[1] = "" Then Return SetError(2, 0, $aResult) EndIf ; Determine version name from build number $aResult[2] = __GetVersionNameByBuild($aResult[1], $aResult[0]) ; Determine edition type If $aResult[5] <> "" Then $aResult[3] = __GetEditionType($aResult[0], $aResult[5]) Else $aResult[3] = __GetEditionType($aResult[0]) EndIf Return $aResult EndFunc ;==>_DetectWindowsVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: _OSVersion ; Description ...: Returns short OS version string similar to @OSVersion macro ; Syntax ........: _OSVersion([$sWindowsPath = @WindowsDir]) ; Parameters ....: $sWindowsPath - [optional] Path to Windows directory. Default is @WindowsDir. ; Return values .: Success - Short version string: ; |Windows Client: "WIN_11", "WIN_10", "WIN_81", "WIN_8", "WIN_7", "WIN_VISTA", "WIN_XP", "WIN_XPe" ; |Windows Server: "WIN_2025", "WIN_2022", "WIN_2019", "WIN_2016", "WIN_2012R2", "WIN_2012", "WIN_2008R2", "WIN_2008", "WIN_2003" ; |Legacy: "WIN_NT4", "WIN_2000", "WIN_ME", "WIN_98SE", "WIN_98", "WIN_95" ; Failure - "UNKNOWN" ; Author ........: Dao Van Trong - TRONG.PRO ; Remarks .......: This function provides a quick way to identify OS version for conditional logic ; Related .......: _DetectWindowsVersion, _GetOSVersionDetailed ; =============================================================================================================================== Func _OSVersion($sWindowsPath = @WindowsDir) Local $aInfo = _DetectWindowsVersion($sWindowsPath) If @error Then Return "UNKNOWN" ; Parse build info Local $aBuildParts = StringSplit($aInfo[1], "|") If $aBuildParts[0] < 1 Then Return "UNKNOWN" Local $iBuild = Int($aBuildParts[1]) Local $sProductName = $aInfo[0] Local $bIsServer = (StringInStr($sProductName, "Server") > 0) ; Return appropriate short version string Select ;--- Windows NT Classic --- Case $iBuild = 528 Return "WIN_NT31" Case $iBuild = 807 Return "WIN_NT35" Case $iBuild = 1057 Return "WIN_NT351" Case $iBuild = 1381 Return "WIN_NT4" ;--- Windows 9x/ME --- Case $iBuild >= 950 And $iBuild <= 1111 Return "WIN_95" Case $iBuild = 1998 Return "WIN_98" Case $iBuild = 2222 Return "WIN_98SE" Case $iBuild = 3000 Return "WIN_ME" ;--- Windows 2000/XP/Server 2003 --- Case $iBuild = 2195 Return $bIsServer ? "WIN_2000SRV" : "WIN_2000" Case $iBuild = 2600 ; Check if it's Windows XP Embedded If StringInStr($sProductName, "Embedded") Then Return "WIN_XPe" Else Return "WIN_XP" EndIf Case $iBuild = 3790 Return $bIsServer ? "WIN_2003" : "WIN_XP64" ;--- Windows Vista/Server 2008 --- Case $iBuild >= 6000 And $iBuild <= 6003 Return $bIsServer ? "WIN_2008" : "WIN_VISTA" ;--- Windows 7/Server 2008 R2 --- Case $iBuild = 7600 Or $iBuild = 7601 Return $bIsServer ? "WIN_2008R2" : "WIN_7" ;--- Windows 8/Server 2012 --- Case $iBuild = 9200 Return $bIsServer ? "WIN_2012" : "WIN_8" ;--- Windows 8.1/Server 2012 R2 --- Case $iBuild = 9600 Return $bIsServer ? "WIN_2012R2" : "WIN_81" ;--- Windows 10/Server 2016 --- Case $iBuild >= 10240 And $iBuild <= 19045 If $bIsServer Then ; Determine server version by build If $iBuild = 14393 Then Return "WIN_2016" ElseIf $iBuild = 17763 Then Return "WIN_2019" ElseIf $iBuild = 20348 Then Return "WIN_2022" Else Return "WIN_2016" ; Default for Windows 10 era servers EndIf Else Return "WIN_10" EndIf ;--- Windows Server 2022 --- Case $iBuild = 20348 Return "WIN_2022" ;--- Windows 11/Server 2025 --- Case $iBuild >= 22000 And $iBuild <= 26200 If $bIsServer Then If $iBuild = 26100 Then Return "WIN_2025" Else Return "WIN_2022" ; Fallback for unknown server builds EndIf Else Return "WIN_11" EndIf ;--- Future versions --- Case $iBuild > 26200 Return $bIsServer ? "WIN_SRV_FUTURE" : "WIN_FUTURE" ;--- Unknown --- Case Else Return "UNKNOWN" EndSelect EndFunc ;==>_OSVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: _GetOSVersionDetailed ; Description ...: Returns detailed OS version information in a structured array format ; Syntax ........: _GetOSVersionDetailed([$sWindowsPath = @WindowsDir]) ; Parameters ....: $sWindowsPath - [optional] Path to Windows directory. Default is @WindowsDir. ; Return values .: Success - Array with detailed version information: ; |[0] - Short Version (e.g., "WIN_11", "WIN_10", "WIN_2022") ; |[1] - Build Number with UBR (e.g., "22621.2787", "19045.3448") ; |[2] - Display Version (e.g., "23H2", "22H2", "21H2" or "N/A") ; |[3] - Product Name (e.g., "Windows 11 Pro", "Windows Server 2022 Datacenter") ; |[4] - Edition Type (e.g., "Professional", "Server", "Home", "Enterprise") ; |[5] - System Type ("Live" or "Offline") ; Failure - Array with error values, @error set: ; |Same error codes as _DetectWindowsVersion ; Author ........: Dao Van Trong - TRONG.PRO ; Remarks .......: This function provides comprehensive version information for detailed analysis ; Related .......: _DetectWindowsVersion, _OSVersion ; =============================================================================================================================== Func _GetOSVersionDetailed($sWindowsPath = @WindowsDir) Local $aInfo = _DetectWindowsVersion($sWindowsPath) If @error Then Local $aResult[6] = ["UNKNOWN", "0", "N/A", "Unknown", "Unknown", "Error"] Return SetError(@error, 0, $aResult) EndIf ; Parse build info Local $aBuildParts = StringSplit($aInfo[1], "|") If $aBuildParts[0] < 1 Then Local $aResult[6] = ["UNKNOWN", "0", "N/A", "Unknown", "Unknown", "Error"] Return SetError(4, 0, $aResult) EndIf Local $iBuild = Int($aBuildParts[1]) Local $sDisplayVersion = ($aBuildParts[0] >= 2) ? $aBuildParts[2] : "" Local $sUBR = ($aBuildParts[0] >= 5) ? $aBuildParts[5] : "" ; Create detailed result array Local $aResult[6] $aResult[0] = _OSVersion($sWindowsPath) ; Short version $aResult[1] = $iBuild & ($sUBR <> "" And $sUBR <> "0" ? "." & $sUBR : "") ; Full build with UBR $aResult[2] = $sDisplayVersion <> "" ? $sDisplayVersion : "N/A" ; Display version like 23H2 $aResult[3] = $aInfo[0] ; Product name $aResult[4] = $aInfo[3] ; Edition type $aResult[5] = $aInfo[4] ; System type (Live/Offline) Return $aResult EndFunc ;==>_GetOSVersionDetailed ; #INTERNAL_USE_ONLY# =========================================================================================================== Func __IsSystemLive($sWindowsPath) ; Check if we're analyzing the current running system Local $sCurrentWin = __NormalizePath(@WindowsDir) If $sWindowsPath = $sCurrentWin Then Return True ; Check if critical system files are locked (indicating live system) Local $aSystemFiles = [ _ $sWindowsPath & "\System32\Config\SYSTEM", _ $sWindowsPath & "\System32\Config\SOFTWARE", _ $sWindowsPath & "\System32\ntoskrnl.exe" _ ] For $sFile In $aSystemFiles If __IsFileLocked($sFile) Then Return True Next Return False EndFunc ;==>__IsSystemLive Func __IsFileLocked($sFilePath) If Not FileExists($sFilePath) Then Return False ; Try to open file exclusively - if fails, it's locked Local $hFile = DllCall("kernel32.dll", "handle", "CreateFileW", _ "wstr", $sFilePath, _ "dword", $GENERIC_READ, _ "dword", 0, _ ; No sharing "ptr", 0, _ "dword", $OPEN_EXISTING, _ "dword", 0, _ "handle", 0) If @error Or $hFile[0] = -1 Then Return True DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hFile[0]) Return False EndFunc ;==>__IsFileLocked Func __GetLiveSystemInfo(ByRef $aResult) ; Read from live registry Local $sRegPath = "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" Local $sEditionID = RegRead($sRegPath, "EditionID") $aResult[0] = RegRead($sRegPath, "ProductName") If @error Then $aResult[0] = $sEditionID ; Fallback $aResult[1] = RegRead($sRegPath, "CurrentBuildNumber") If @error Then $aResult[1] = RegRead($sRegPath, "CurrentBuild") ; Get additional version info for precise identification Local $sDisplayVersion = RegRead($sRegPath, "DisplayVersion") ; 22H2, 23H2, etc. Local $sReleaseId = RegRead($sRegPath, "ReleaseId") ; 1903, 1909, 2004, etc. Local $sCurrentVersion = RegRead($sRegPath, "CurrentVersion") ; 6.3, 10.0, etc. Local $sUBR = RegRead($sRegPath, "UBR") ; Update Build Revision ; Store additional info for precise version detection If $sDisplayVersion <> "" Then $aResult[1] &= "|" & $sDisplayVersion If $sReleaseId <> "" Then $aResult[1] &= "|" & $sReleaseId If $sCurrentVersion <> "" Then $aResult[1] &= "|" & $sCurrentVersion If $sUBR <> "" Then $aResult[1] &= "|" & $sUBR ; Thêm EditionID và o vị trà [5] $aResult[5] = $sEditionID Return ($aResult[0] <> "" And StringLen($aResult[1]) > 0) EndFunc ;==>__GetLiveSystemInfo Func __GetOfflineSystemInfo($sWindowsPath, ByRef $aResult) ; Multiple strategies for offline detection with fallback chain Local $bSuccess = False ; Strategy 1: Try to load offline registry hive (requires admin privileges) If Not $bSuccess Then $bSuccess = __ReadOfflineRegistryDirect($sWindowsPath, $aResult) EndIf ; Strategy 2: Read version from PE files (kernel32.dll, ntoskrnl.exe) If Not $bSuccess Then $bSuccess = __ReadVersionFromFiles($sWindowsPath, $aResult) EndIf ; Strategy 3: Extract build from PE headers directly If Not $bSuccess Then $bSuccess = __ExtractBuildFromPE($sWindowsPath, $aResult) EndIf Return $bSuccess EndFunc ;==>__GetOfflineSystemInfo Func __ReadOfflineRegistryDirect($sWindowsPath, ByRef $aResult) ; Try to load offline registry hive Local $sTempHive = "TEMP_SW_" & Random(1000, 9999, 1) Local $sHivePath = $sWindowsPath & "\System32\Config\SOFTWARE" If Not FileExists($sHivePath) Then Return False If __LoadOfflineHive($sHivePath, $sTempHive) Then Local $sRegPath = "HKLM\" & $sTempHive & "\Microsoft\Windows NT\CurrentVersion" Local $sEditionID = RegRead($sRegPath, "EditionID") $aResult[5] = $sEditionID $aResult[0] = RegRead($sRegPath, "ProductName") If @error Or $aResult[0] = "" Then $aResult[0] = $sEditionID EndIf $aResult[1] = RegRead($sRegPath, "CurrentBuildNumber") If @error Or $aResult[1] = "" Then $aResult[1] = RegRead($sRegPath, "CurrentBuild") EndIf ; Get additional version info for precise identification Local $sDisplayVersion = RegRead($sRegPath, "DisplayVersion") Local $sReleaseId = RegRead($sRegPath, "ReleaseId") Local $sCurrentVersion = RegRead($sRegPath, "CurrentVersion") Local $sUBR = RegRead($sRegPath, "UBR") ; Store additional info for precise version detection If $sDisplayVersion <> "" Then $aResult[1] &= "|" & $sDisplayVersion If $sReleaseId <> "" Then $aResult[1] &= "|" & $sReleaseId If $sCurrentVersion <> "" Then $aResult[1] &= "|" & $sCurrentVersion If $sUBR <> "" Then $aResult[1] &= "|" & $sUBR __UnloadOfflineHive($sTempHive) ; If registry read successful, return If $aResult[0] <> "" And $aResult[1] <> "" Then Return True EndIf Return False EndFunc ;==>__ReadOfflineRegistryDirect Func __ReadVersionFromFiles($sWindowsPath, ByRef $aResult) ; Priority order for version files Local $aFiles = [ _ $sWindowsPath & "\System32\kernel32.dll", _ $sWindowsPath & "\System32\ntoskrnl.exe", _ $sWindowsPath & "\explorer.exe", _ $sWindowsPath & "\System32\user32.dll", _ $sWindowsPath & "\System32\shell32.dll" _ ] For $sFile In $aFiles If FileExists($sFile) Then ; Enhanced version reading using version.dll If __ReadFileVersionInfo($sFile, $aResult) Then Return True EndIf EndIf Next Return False EndFunc ;==>__ReadVersionFromFiles Func __ReadFileVersionInfo($sFilePath, ByRef $aResult) ; Get version info size Local $iSize = DllCall("version.dll", "dword", "GetFileVersionInfoSizeW", "wstr", $sFilePath, "ptr", 0) If @error Or $iSize[0] = 0 Then Return False ; Allocate buffer and get version info Local $tBuffer = DllStructCreate("byte[" & $iSize[0] & "]") Local $bRet = DllCall("version.dll", "bool", "GetFileVersionInfoW", _ "wstr", $sFilePath, _ "dword", 0, _ "dword", $iSize[0], _ "ptr", DllStructGetPtr($tBuffer)) If @error Or Not $bRet[0] Then Return False ; Query fixed file info Local $tFixedInfo, $iLen Local $bQuery = DllCall("version.dll", "bool", "VerQueryValueW", _ "ptr", DllStructGetPtr($tBuffer), _ "wstr", "\", _ "ptr*", 0, _ "uint*", 0) If @error Or Not $bQuery[0] Or $bQuery[4] = 0 Then Return False ; Read VS_FIXEDFILEINFO structure $tFixedInfo = DllStructCreate("dword[13]", $bQuery[3]) ; Extract version numbers (high and low parts) Local $iFileVersionMS = DllStructGetData($tFixedInfo, 1, 3) ; dwFileVersionMS Local $iFileVersionLS = DllStructGetData($tFixedInfo, 1, 4) ; dwFileVersionLS ; Convert to version components Local $iMajor = BitShift($iFileVersionMS, 16) Local $iMinor = BitAND($iFileVersionMS, 0xFFFF) Local $iBuild = BitShift($iFileVersionLS, 16) Local $iRevision = BitAND($iFileVersionLS, 0xFFFF) ; Set build number If $iBuild > 0 Then $aResult[1] = String($iBuild) If $iRevision > 0 Then $aResult[1] &= "||||" & String($iRevision) EndIf ; Get product name from string info Local $aLanguages = __GetVersionLanguages($tBuffer) For $sLang In $aLanguages Local $sProductName = __GetVersionString($tBuffer, $sLang, "ProductName") If $sProductName <> "" Then $aResult[0] = $sProductName ExitLoop EndIf Next ; Fallback to FileDescription if ProductName is empty If $aResult[0] = "" Then For $sLang In $aLanguages Local $sFileDesc = __GetVersionString($tBuffer, $sLang, "FileDescription") If $sFileDesc <> "" Then $aResult[0] = $sFileDesc ExitLoop EndIf Next EndIf Return ($aResult[0] <> "" And $aResult[1] <> "") EndFunc ;==>__ReadFileVersionInfo Func __GetVersionLanguages($tVersionBuffer) Local $aLanguages[0] ; Query for translation table Local $bQuery = DllCall("version.dll", "bool", "VerQueryValueW", _ "ptr", DllStructGetPtr($tVersionBuffer), _ "wstr", "\VarFileInfo\Translation", _ "ptr*", 0, _ "uint*", 0) If @error Or Not $bQuery[0] Or $bQuery[4] = 0 Then ; Default to common language codes ReDim $aLanguages[2] $aLanguages[0] = "040904B0" ; English US $aLanguages[1] = "000004B0" ; Neutral Return $aLanguages EndIf ; Read translation pairs Local $iCount = $bQuery[4] / 4 ; Each entry is 4 bytes (DWORD) Local $tTranslation = DllStructCreate("dword[" & $iCount & "]", $bQuery[3]) ReDim $aLanguages[$iCount] For $i = 1 To $iCount Local $iTranslation = DllStructGetData($tTranslation, 1, $i) $aLanguages[$i - 1] = StringFormat("%04X%04X", BitAND($iTranslation, 0xFFFF), BitShift($iTranslation, 16)) Next Return $aLanguages EndFunc ;==>__GetVersionLanguages Func __GetVersionString($tVersionBuffer, $sLanguage, $sKey) Local $sSubBlock = "\StringFileInfo\" & $sLanguage & "\" & $sKey Local $bQuery = DllCall("version.dll", "bool", "VerQueryValueW", _ "ptr", DllStructGetPtr($tVersionBuffer), _ "wstr", $sSubBlock, _ "ptr*", 0, _ "uint*", 0) If @error Or Not $bQuery[0] Or $bQuery[4] = 0 Then Return "" ; Read string value Local $tString = DllStructCreate("wchar[" & $bQuery[4] & "]", $bQuery[3]) Return DllStructGetData($tString, 1) EndFunc ;==>__GetVersionString Func __ExtractBuildFromPE($sWindowsPath, ByRef $aResult) ; Try ntoskrnl.exe first as it's the kernel Local $sKernelPath = $sWindowsPath & "\System32\ntoskrnl.exe" If FileExists($sKernelPath) Then If __ParseVersionFromNtoskrnl($sKernelPath, $aResult) Then Return True EndIf ; Try kernel32.dll as fallback Local $sKernel32Path = $sWindowsPath & "\System32\kernel32.dll" If FileExists($sKernel32Path) Then If __ParseVersionFromKernel32($sKernel32Path, $aResult) Then Return True EndIf Return False EndFunc ;==>__ExtractBuildFromPE Func __ParseVersionFromNtoskrnl($sFilePath, ByRef $aResult) ; Open file for reading Local $hFile = FileOpen($sFilePath, $FO_READ + $FO_BINARY) If $hFile = -1 Then Return False ; Read DOS header Local $tDOSHeader = FileRead($hFile, 64) If @error Or BinaryLen($tDOSHeader) < 64 Then FileClose($hFile) Return False EndIf ; Check DOS signature Local $iDOSSignature = Number("0x" & StringMid($tDOSHeader, 1, 4)) If $iDOSSignature <> $IMAGE_DOS_SIGNATURE Then FileClose($hFile) Return False EndIf ; Get PE header offset Local $iPEOffset = Number("0x" & StringMid($tDOSHeader, 121, 8)) ; Seek to PE header and read FileSetPos($hFile, $iPEOffset, $FILE_BEGIN) Local $tPEHeader = FileRead($hFile, 24) If @error Or BinaryLen($tPEHeader) < 24 Then FileClose($hFile) Return False EndIf ; Check PE signature Local $iPESignature = Number("0x" & StringMid($tPEHeader, 1, 8)) If $iPESignature <> $IMAGE_NT_SIGNATURE Then FileClose($hFile) Return False EndIf ; Extract timestamp (can be used to determine build) Local $iTimestamp = Number("0x" & StringMid($tPEHeader, 17, 8)) FileClose($hFile) ; Use FileGetVersion as more reliable method Local $sVersion = FileGetVersion($sFilePath) If Not @error And $sVersion <> "" Then Local $aVer = StringSplit($sVersion, ".") If $aVer[0] >= 3 Then $aResult[1] = $aVer[3] ; Build number $aResult[0] = FileGetVersion($sFilePath, "ProductName") If @error Or $aResult[0] = "" Then $aResult[0] = FileGetVersion($sFilePath, "FileDescription") EndIf Return ($aResult[0] <> "" And $aResult[1] <> "") EndIf EndIf Return False EndFunc ;==>__ParseVersionFromNtoskrnl Func __ParseVersionFromKernel32($sFilePath, ByRef $aResult) ; Similar to ntoskrnl parsing but for kernel32.dll Local $sVersion = FileGetVersion($sFilePath) If Not @error And $sVersion <> "" Then Local $aVer = StringSplit($sVersion, ".") If $aVer[0] >= 3 Then $aResult[1] = $aVer[3] ; Build number $aResult[0] = FileGetVersion($sFilePath, "ProductName") If @error Or $aResult[0] = "" Then $aResult[0] = FileGetVersion($sFilePath, "FileDescription") EndIf Return ($aResult[0] <> "" And $aResult[1] <> "") EndIf EndIf Return False EndFunc ;==>__ParseVersionFromKernel32 Func __GetVersionNameByBuild($sBuildData, $sProductName = "") ; Parse build info and additional data If Not StringInStr($sBuildData, "|") And StringIsDigit($sBuildData) Then ; Simple build number without metadata $sBuildData &= "||||" EndIf Local $aBuildParts = StringSplit($sBuildData, "|") If $aBuildParts[0] < 1 Then Return "Unknown Windows Version" Local $iBuild = Int($aBuildParts[1]) Local $sDisplayVersion = ($aBuildParts[0] >= 2) ? $aBuildParts[2] : "" Local $sReleaseId = ($aBuildParts[0] >= 3) ? $aBuildParts[3] : "" Local $sCurrentVersion = ($aBuildParts[0] >= 4) ? $aBuildParts[4] : "" Local $sUBR = ($aBuildParts[0] >= 5) ? $aBuildParts[5] : "" Local $bIsServer = (StringInStr($sProductName, "Server") > 0) Local $sVersionName = "" ; Precise version detection based on build number and additional info Select ;--- Windows NT Classic --- Case $iBuild = 528 $sVersionName = "Windows NT 3.1" Case $iBuild = 807 $sVersionName = "Windows NT 3.5" Case $iBuild = 1057 $sVersionName = "Windows NT 3.51" Case $iBuild = 1381 $sVersionName = "Windows NT 4.0" ;--- Windows 9x/ME --- Case $iBuild >= 950 And $iBuild <= 1111 $sVersionName = ($iBuild <= 1110) ? "Windows 95" : "Windows 95 OSR2" Case $iBuild = 1998 $sVersionName = "Windows 98" Case $iBuild = 2222 $sVersionName = "Windows 98 Second Edition" Case $iBuild = 3000 $sVersionName = "Windows Millennium Edition" ;--- Windows 2000/XP/Server 2003 --- Case $iBuild = 2195 $sVersionName = $bIsServer ? "Windows 2000 Server" : "Windows 2000 Professional" Case $iBuild = 2600 $sVersionName = "Windows XP" Case $iBuild = 3790 $sVersionName = $bIsServer ? "Windows Server 2003 R2" : "Windows XP Professional x64 Edition" ;--- Windows Vista/Server 2008 --- Case $iBuild = 6000 $sVersionName = $bIsServer ? "Windows Server 2008" : "Windows Vista" Case $iBuild = 6001 $sVersionName = $bIsServer ? "Windows Server 2008 SP1" : "Windows Vista SP1" Case $iBuild = 6002 Or $iBuild = 6003 $sVersionName = $bIsServer ? "Windows Server 2008 SP2" : "Windows Vista SP2" ;--- Windows 7/Server 2008 R2 --- Case $iBuild = 7600 $sVersionName = $bIsServer ? "Windows Server 2008 R2" : "Windows 7" Case $iBuild = 7601 $sVersionName = $bIsServer ? "Windows Server 2008 R2 SP1" : "Windows 7 SP1" ;--- Windows 8/Server 2012 --- Case $iBuild = 9200 $sVersionName = $bIsServer ? "Windows Server 2012" : "Windows 8" ;--- Windows 8.1/Server 2012 R2 --- Case $iBuild = 9600 $sVersionName = $bIsServer ? "Windows Server 2012 R2" : "Windows 8.1" ;--- Windows 10 Versions --- Case $iBuild = 10240 $sVersionName = "Windows 10 Version 1507 (RTM)" Case $iBuild = 10586 $sVersionName = "Windows 10 Version 1511 (November Update)" Case $iBuild = 14393 $sVersionName = $bIsServer ? "Windows Server 2016" : "Windows 10 Version 1607 (Anniversary Update)" Case $iBuild = 15063 $sVersionName = "Windows 10 Version 1703 (Creators Update)" Case $iBuild = 16299 $sVersionName = "Windows 10 Version 1709 (Fall Creators Update)" Case $iBuild = 17134 $sVersionName = "Windows 10 Version 1803 (April 2018 Update)" Case $iBuild = 17763 $sVersionName = $bIsServer ? "Windows Server 2019" : "Windows 10 Version 1809 (October 2018 Update)" Case $iBuild = 18362 $sVersionName = "Windows 10 Version 1903 (May 2019 Update)" Case $iBuild = 18363 $sVersionName = "Windows 10 Version 1909 (November 2019 Update)" Case $iBuild >= 19041 And $iBuild <= 19045 ; Use DisplayVersion or ReleaseId for precise identification If $sDisplayVersion <> "" Then Switch $sDisplayVersion Case "20H2" $sVersionName = "Windows 10 Version 20H2 (October 2020 Update)" Case "21H1" $sVersionName = "Windows 10 Version 21H1 (May 2021 Update)" Case "21H2" $sVersionName = "Windows 10 Version 21H2 (November 2021 Update)" Case "22H2" $sVersionName = "Windows 10 Version 22H2 (2022 Update)" Case Else $sVersionName = "Windows 10 Version 2004 (May 2020 Update)" EndSwitch ElseIf $sReleaseId <> "" Then Switch $sReleaseId Case "2009" $sVersionName = "Windows 10 Version 20H2 (October 2020 Update)" Case Else $sVersionName = "Windows 10 Version 2004 (May 2020 Update)" EndSwitch Else $sVersionName = "Windows 10 Version 2004 (May 2020 Update)" EndIf ;--- Windows Server 2022 --- Case $iBuild = 20348 $sVersionName = "Windows Server 2022" ;--- Windows 11 Versions --- Case $iBuild = 22000 $sVersionName = "Windows 11 Version 21H2" Case $iBuild >= 22621 And $iBuild <= 22631 ; Use DisplayVersion for precise identification If $sDisplayVersion <> "" Then Switch $sDisplayVersion Case "22H2" $sVersionName = "Windows 11 Version 22H2 (2022 Update)" Case "23H2" $sVersionName = "Windows 11 Version 23H2 (2023 Update)" Case Else $sVersionName = "Windows 11 Version 22H2 (2022 Update)" EndSwitch Else $sVersionName = "Windows 11 Version 22H2 (2022 Update)" EndIf Case $iBuild >= 26000 And $iBuild <= 26100 $sVersionName = $bIsServer ? "Windows Server 2025" : "Windows 11 Version 24H2 (2024 Update)" ;--- Future/Insider Builds --- Case $iBuild > 26100 $sVersionName = $bIsServer ? "Windows Server (Insider Preview)" : "Windows 11 (Insider Preview)" ;--- Unknown --- Case Else ; Try to determine by product name if available If StringInStr($sProductName, "Windows 11") Then $sVersionName = "Windows 11" ElseIf StringInStr($sProductName, "Windows 10") Then $sVersionName = "Windows 10" ElseIf StringInStr($sProductName, "Server") Then $sVersionName = "Windows Server" Else $sVersionName = "Unknown Windows Version" EndIf EndSelect ; Add build number and UBR if available Local $sBuildDetails = " (Build " & $iBuild If $sUBR <> "" And $sUBR <> "0" Then $sBuildDetails &= "." & $sUBR $sBuildDetails &= ")" Return $sVersionName & $sBuildDetails EndFunc ;==>__GetVersionNameByBuild Func __GetEditionType($sProductName, $sEditionID = '') ; Prefer EditionID when provided Local $sLowerID = StringLower($sEditionID) If $sLowerID <> '' Then Switch True ; China-specific Case StringInStr($sLowerID, 'corecountryspecific') Or StringInStr($sLowerID, 'corechina') Return 'Home China' Case StringInStr($sLowerID, 'professionalcountryspecific') Or StringInStr($sLowerID, 'professionalchina') Return 'Pro China' Case StringInStr($sLowerID, 'enterprisegovchina') Return 'Enterprise Government China' Case StringInStr($sLowerID, 'enterpriseg') Or StringInStr($sLowerID, 'enterprisegovernment') Return 'Enterprise G' ; Europe N editions Case StringInStr($sLowerID, 'coren') Return 'Home N' Case StringInStr($sLowerID, 'professionaln') Return 'Pro N' Case StringInStr($sLowerID, 'enterprisen') Return 'Enterprise N' Case StringInStr($sLowerID, 'educationn') Return 'Education N' ; Korea KN editions Case StringInStr($sLowerID, 'corekn') Return 'Home KN' Case StringInStr($sLowerID, 'professionalkn') Return 'Pro KN' Case StringInStr($sLowerID, 'enterprisekn') Return 'Enterprise KN' ; LTSC / LTSB Case StringInStr($sLowerID, 'enterprises') Or _ StringInStr($sLowerID, 'enterpriseltsc') Or _ StringInStr($sLowerID, 'enterpriseltsb') Return 'Enterprise LTSC' ; IoT editions Case StringInStr($sLowerID, 'iotenterprise') Return 'IoT Enterprise' Case StringInStr($sLowerID, 'iotcore') Return 'IoT Core' ; Mobile editions Case StringInStr($sLowerID, 'mobileenterprise') Return 'Mobile Enterprise' Case StringInStr($sLowerID, 'mobile') Return 'Mobile' ; Other special SKUs Case StringInStr($sLowerID, 'mixedreality') Return 'Mixed Reality' Case StringInStr($sLowerID, 'proeducation') Return 'Pro Education' Case StringInStr($sLowerID, 'proforworkstations') Return 'Pro for Workstations' ; Generic EditionID patterns Case StringInStr($sLowerID, 'enterprise') Return 'Enterprise' Case StringInStr($sLowerID, 'professional') Return 'Professional' Case StringInStr($sLowerID, 'standard') Return 'Standard' Case StringInStr($sLowerID, 'datacenter') Return 'Datacenter' Case StringInStr($sLowerID, 'essentials') Return 'Essentials' Case StringInStr($sLowerID, 'starter') Return 'Starter' Case StringInStr($sLowerID, 'home') Return 'Home' EndSwitch EndIf ; Fallback to product name if EditionID was empty or unrecognized Local $sLower = StringLower($sProductName) ; === Windows Server Editions === If StringInStr($sLower, "server") Then ; Windows Server 2022/2025 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 ; Windows Server 2019 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 ; Windows Server 2016 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 ; Generic Server 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 ; === Windows Client Editions === ; Windows 11 Editions 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 ; Windows 10 Editions 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 ; Windows 8.1 Editions 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 ; Windows 8 Editions 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 ; Windows 7 Editions 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 ; === Generic Edition Detection (for older versions or fallback) === ; Special editions 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" ; IoT editions 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" ; Mobile editions If StringInStr($sLower, "mobile enterprise") Then Return "Mobile Enterprise" If StringInStr($sLower, "mobile") Then Return "Mobile" ; RT editions If StringInStr($sLower, "rt") Then Return "RT" ; Workstation editions If StringInStr($sLower, "pro for workstations") Then Return "Pro for Workstations" If StringInStr($sLower, "workstation") Then Return "Workstation" ; Education editions If StringInStr($sLower, "pro education") Then Return "Pro Education" If StringInStr($sLower, "education") Then Return "Education" ; Enterprise editions If StringInStr($sLower, "enterprise") Then Return "Enterprise" ; Professional editions If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then ; Check for specific Pro variants If StringInStr($sLower, "media center") Then Return "Pro with Media Center" Return "Professional" EndIf ; Home editions 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" ; Core/Standard editions If StringInStr($sLower, "core") Then Return "Core" If StringInStr($sLower, "single language") Then Return "Single Language" ; Legacy editions If StringInStr($sLower, "millennium") Then Return "Millennium Edition" If StringInStr($sLower, "second edition") Then Return "Second Edition" ; Default fallback If $sProductName <> "" Then Return "Standard" Return "Unknown" EndFunc ;==>__GetEditionType Func __LoadOfflineHive($sHiveFile, $sTempKey) If Not FileExists($sHiveFile) Then Return False ; Enable backup privilege __EnableBackupPrivilege() Local $aRet = DllCall("advapi32.dll", "long", "RegLoadKeyW", _ "handle", $HKEY_LOCAL_MACHINE, _ "wstr", $sTempKey, _ "wstr", $sHiveFile) Return (IsArray($aRet) And $aRet[0] = $ERROR_SUCCESS) EndFunc ;==>__LoadOfflineHive Func __UnloadOfflineHive($sTempKey) Local $aRet = DllCall("advapi32.dll", "long", "RegUnloadKeyW", _ "handle", $HKEY_LOCAL_MACHINE, _ "wstr", $sTempKey) Return (IsArray($aRet) And $aRet[0] = $ERROR_SUCCESS) EndFunc ;==>__UnloadOfflineHive Func __EnableBackupPrivilege() Local $hToken, $aRet ; Open process token $aRet = DllCall("advapi32.dll", "bool", "OpenProcessToken", _ "handle", DllCall("kernel32.dll", "handle", "GetCurrentProcess")[0], _ "dword", 0x00000020, _ ; TOKEN_ADJUST_PRIVILEGES "handle*", 0) If @error Or Not $aRet[0] Then Return False $hToken = $aRet[3] ; Lookup privilege value Local $tLUID = DllStructCreate("int64") $aRet = DllCall("advapi32.dll", "bool", "LookupPrivilegeValueW", _ "ptr", 0, _ "wstr", "SeBackupPrivilege", _ "ptr", DllStructGetPtr($tLUID)) If @error Or Not $aRet[0] Then DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hToken) Return False EndIf ; Adjust token privileges 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 DllCall("advapi32.dll", "bool", "AdjustTokenPrivileges", _ "handle", $hToken, _ "bool", False, _ "ptr", DllStructGetPtr($tPriv), _ "dword", 0, _ "ptr", 0, _ "ptr", 0) DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hToken) Return True EndFunc ;==>__EnableBackupPrivilege Func __NormalizePath($sPath) Local Const $MAX_PATH = 260 Local $tBuffer = DllStructCreate("wchar[" & $MAX_PATH & "]") Local $aRet = DllCall("kernel32.dll", "dword", "GetFullPathNameW", _ "wstr", $sPath, _ "dword", $MAX_PATH, _ "ptr", DllStructGetPtr($tBuffer), _ "ptr", 0) If @error Or $aRet[0] = 0 Then Return StringReplace($sPath, "/", "\") Local $sNormalized = DllStructGetData($tBuffer, 1) Return StringRegExpReplace($sNormalized, "\\+$", "") ; Remove trailing backslashes EndFunc ;==>__NormalizePath Func __IsValidWindowsPath($sPath) ; Check if the path exists and contains essential Windows files/directories If Not FileExists($sPath) Then Return False ; Check for essential Windows directories Local $aEssentialDirs = [ _ $sPath & "\System32", _ $sPath & "\System32\Config" _ ] For $sDir In $aEssentialDirs If Not FileExists($sDir) Then Return False Next ; Check for essential Windows files Local $aEssentialFiles = [ _ $sPath & "\System32\kernel32.dll", _ $sPath & "\System32\ntdll.dll" _ ] Local $iFoundFiles = 0 For $sFile In $aEssentialFiles If FileExists($sFile) Then $iFoundFiles += 1 Next ; At least one essential file should exist Return ($iFoundFiles > 0) EndFunc ;==>__IsValidWindowsPath ; =============================================================================================================================== ; TEST SECTION - Enhanced testing with better error handling ; =============================================================================================================================== #Region TEST If Not @Compiled Then _TEST() Func _TEST() ConsoleWrite("!=== Enhanced Windows Version Detector Test ===" & @CRLF & @CRLF) ; Test 1: Current system detection ConsoleWrite("> 1. Testing current system detection:" & @CRLF) Local $aResult = _DetectWindowsVersion() If @error Then ConsoleWrite("! ERROR: " & @error & "- Failed to detect current system" & @CRLF) Else ConsoleWrite("- ProductName: " & $aResult[0] & @CRLF) ConsoleWrite("- BuildNumber: " & $aResult[1] & @CRLF) ConsoleWrite("- VersionName: " & $aResult[2] & @CRLF) ConsoleWrite("- Edition: " & $aResult[3] & @CRLF) ConsoleWrite("- SystemType: " & $aResult[4] & @CRLF) ; Display EditionID if available If UBound($aResult) > 5 And $aResult[5] <> "" Then ConsoleWrite("- EditionID: " & $aResult[5] & @CRLF) EndIf EndIf ConsoleWrite(@CRLF) ; Test 2: Short OS version ConsoleWrite("> 2. Testing short OS version:" & @CRLF) Local $sOS = _OSVersion() ConsoleWrite("- OS Version: " & $sOS & @CRLF) ConsoleWrite(@CRLF) ; Test 3: Detailed OS version ConsoleWrite("> 3. Testing detailed OS version:" & @CRLF) Local $aDetailed = _GetOSVersionDetailed() If @error Then ConsoleWrite("! ERROR: " & @error & "- Failed to get detailed info" & @CRLF) Else ConsoleWrite("- Short Version: " & $aDetailed[0] & @CRLF) ConsoleWrite("- Build with UBR: " & $aDetailed[1] & @CRLF) ConsoleWrite("- Display Version: " & $aDetailed[2] & @CRLF) ConsoleWrite("- Product Name: " & $aDetailed[3] & @CRLF) ConsoleWrite("- Edition Type: " & $aDetailed[4] & @CRLF) ConsoleWrite("- System Type: " & $aDetailed[5] & @CRLF) EndIf ConsoleWrite(@CRLF) ; Test 4: Special Edition Detection Test ConsoleWrite("> 4. Testing special edition detection capabilities:" & @CRLF) ; Test various EditionID scenarios Local $aTestCases = [ _ ["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"] _ ] For $i = 0 To UBound($aTestCases) - 1 Local $sProductName = $aTestCases[$i][0] Local $sEditionID = $aTestCases[$i][1] Local $sExpected = $aTestCases[$i][2] Local $sResult = __GetEditionType($sProductName, $sEditionID) Local $sStatus = ($sResult = $sExpected) ? "✓ PASS" : "✗ FAIL" ConsoleWrite("+ " & $sStatus & " | ProductName: " & $sProductName & " | EditionID: " & $sEditionID & " | Result: " & $sResult & @CRLF) Next ConsoleWrite(@CRLF) ; Test 5: Offline system detection (if another Windows installation exists) ConsoleWrite("> 5. Testing offline system detection:" & @CRLF) Local $aOfflinePaths = ["C:\Windows", "D:\Windows", "E:\Windows"] ; Common offline paths Local $bFoundOffline = False For $sOfflinePath In $aOfflinePaths If FileExists($sOfflinePath) And $sOfflinePath <> @WindowsDir Then ConsoleWrite("- Testing path: " & $sOfflinePath & @CRLF) Local $aOfflineResult = _DetectWindowsVersion($sOfflinePath) If @error Then ConsoleWrite("! ERROR: " & @error & "- Failed to detect offline system at " & $sOfflinePath & @CRLF) Else ConsoleWrite("- Offline ProductName: " & $aOfflineResult[0] & @CRLF) ConsoleWrite("- Offline BuildNumber: " & $aOfflineResult[1] & @CRLF) ConsoleWrite("- Offline VersionName: " & $aOfflineResult[2] & @CRLF) ConsoleWrite("- Offline Edition: " & $aOfflineResult[3] & @CRLF) ConsoleWrite("- Offline SystemType: " & $aOfflineResult[4] & @CRLF) ; Display EditionID if available If UBound($aOfflineResult) > 5 And $aOfflineResult[5] <> "" Then ConsoleWrite("- Offline EditionID: " & $aOfflineResult[5] & @CRLF) EndIf EndIf ConsoleWrite(@CRLF) $bFoundOffline = True ExitLoop ; Test only the first found offline Windows EndIf Next If Not $bFoundOffline Then ConsoleWrite("- No offline Windows installations found for testing." & @CRLF & @CRLF) EndIf ; Test 6: Error handling - invalid path ConsoleWrite("> 6. Testing error handling with invalid path:" & @CRLF) Local $aInvalidResult = _DetectWindowsVersion("C:\NonExistentPath") ConsoleWrite("- Error code: " & @error & @CRLF) ConsoleWrite("- Result array size: " & UBound($aInvalidResult) & @CRLF) ConsoleWrite(@CRLF) ; Test 7: China-specific detection demonstration ConsoleWrite("> 7. China-specific Windows detection capabilities:" & @CRLF) ConsoleWrite("- ✓ CoreCountrySpecific EditionID → Home China" & @CRLF) ConsoleWrite("- ✓ ProfessionalCountrySpecific EditionID → Pro China" & @CRLF) ConsoleWrite("- ✓ EnterpriseG EditionID → Enterprise G (Government)" & @CRLF) ConsoleWrite("- ✓ EnterpriseGovChina EditionID → Enterprise Government China" & @CRLF) ConsoleWrite("- ✓ Supports N editions (Europe) and KN editions (Korea)" & @CRLF) ConsoleWrite("- ✓ Enhanced regional market detection" & @CRLF) ConsoleWrite(@CRLF) ConsoleWrite("!=== Test Complete ===" & @CRLF) EndFunc ;==>_TEST #EndRegion TEST RT: expandcollapse popup!=== Enhanced Windows Version Detector Test === > 1. Testing current system detection: - ProductName: Windows 10 Enterprise LTSC 2021 - BuildNumber: 19045|22H2|2009|6.3|6216 - VersionName: Windows 10 Version 22H2 (2022 Update) (Build 19045.6216) - Edition: Enterprise LTSC - SystemType: Live - EditionID: EnterpriseS > 2. Testing short OS version: - OS Version: WIN_10 > 3. Testing detailed OS version: - Short Version: WIN_10 - Build with UBR: 19045.6216 - Display Version: 22H2 - Product Name: Windows 10 Enterprise LTSC 2021 - Edition Type: Enterprise LTSC - 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: - Testing path: C:\Offline\Windows - Offline ProductName: Microsoft® Windows® Operating System - Offline BuildNumber: 19041||||3636 - Offline VersionName: Windows 10 Version 2004 (May 2020 Update) (Build 19041.3636) - Offline Edition: Standard - Offline SystemType: Offline > 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 ===    UDF v1: expandcollapse popup#include-once ; #INDEX# ======================================================================================================================= ; Title .........: Windows Version Detector V1 ; AutoIt Version : 3.3.16.1+ ; Description ...: Functions for accurately detecting Windows version for current or offline systems ; Author(s) .....: Dao Van Trong - TRONG.PRO ; Dll(s) ........: kernel32.dll, advapi32.dll ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ; _DetectWindowsVersion ; _OSVersion ; _GetOSVersionDetailed ; =============================================================================================================================== ; #INTERNAL_USE_ONLY# =========================================================================================================== ; __IsSystemLive ; __IsFileLocked ; __GetLiveSystemInfo ; __GetOfflineSystemInfo ; __ReadVersionFromFiles ; __GetVersionNameByBuild ; __GetEditionType ; __LoadOfflineHive ; __UnloadOfflineHive ; __EnableBackupPrivilege ; __NormalizePath ; =============================================================================================================================== ; #CONSTANTS# =================================================================================================================== #include <FileConstants.au3> #include <APIRegConstants.au3> #include <APIErrorsConstants.au3> ;~ Global Const $HKEY_LOCAL_MACHINE = 0x80000002 ;~ Global Const $ERROR_SUCCESS = 0 ;~ Global Const $GENERIC_READ = 0x80000000 ;~ Global Const $FILE_SHARE_READ = 0x00000001 ;~ Global Const $OPEN_EXISTING = 3 ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name ..........: _DetectWindowsVersion ; Description ...: Detects Windows version information for current or offline systems ; Syntax ........: _DetectWindowsVersion([$sWindowsPath = @WindowsDir]) ; Parameters ....: $sWindowsPath - [optional] Path to Windows directory. Default is @WindowsDir. ; Return values .: Success - Array with Windows information: ; |[0] - Product Name (e.g., "Windows 11 Pro") ; |[1] - Build Number with metadata (e.g., "22621|23H2|2009|10.0|2787") ; |[2] - Version Name (e.g., "Windows 11 Version 23H2 (2023 Update) (Build 22621.2787)") ; |[3] - Edition Type (e.g., "Professional", "Server", "Home") ; |[4] - System Type ("Live" or "Offline") ; Failure - Empty array, @error set: ; |1 - Failed to get live system info ; |2 - Failed to get offline system info ; Author ........: Dao Van Trong - TRONG.PRO ; Remarks .......: This function automatically detects whether the target system is live or offline ; Related .......: _OSVersion, _GetOSVersionDetailed ; =============================================================================================================================== Func _DetectWindowsVersion($sWindowsPath = @WindowsDir) Local $aResult[5] = ["", "", "", "", ""] ; [0] = ProductName, [1] = BuildNumber, [2] = VersionName, [3] = Edition, [4] = SystemType (Live/Offline) ; Normalize path $sWindowsPath = __NormalizePath($sWindowsPath) ; Determine if system is live or offline Local $bIsLive = __IsSystemLive($sWindowsPath) $aResult[4] = $bIsLive ? "Live" : "Offline" ; Get Windows information based on system type If $bIsLive Then If Not __GetLiveSystemInfo($aResult) Then Return SetError(1, 0, $aResult) EndIf Else If Not __GetOfflineSystemInfo($sWindowsPath, $aResult) Then Return SetError(2, 0, $aResult) EndIf EndIf ; Determine version name from build number $aResult[2] = __GetVersionNameByBuild($aResult[1], $aResult[0]) ; Determine edition type $aResult[3] = __GetEditionType($aResult[0]) Return $aResult EndFunc ;==>_DetectWindowsVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: _OSVersion ; Description ...: Returns short OS version string similar to @OSVersion macro ; Syntax ........: _OSVersion([$sWindowsPath = @WindowsDir]) ; Parameters ....: $sWindowsPath - [optional] Path to Windows directory. Default is @WindowsDir. ; Return values .: Success - Short version string: ; |Windows Client: "WIN_11", "WIN_10", "WIN_81", "WIN_8", "WIN_7", "WIN_VISTA", "WIN_XP", "WIN_XPe" ; |Windows Server: "WIN_2025", "WIN_2022", "WIN_2019", "WIN_2016", "WIN_2012R2", "WIN_2012", "WIN_2008R2", "WIN_2008", "WIN_2003" ; |Legacy: "WIN_NT4", "WIN_2000", "WIN_ME", "WIN_98SE", "WIN_98", "WIN_95" ; Failure - "UNKNOWN" ; Author ........: Dao Van Trong - TRONG.PRO ; Remarks .......: This function provides a quick way to identify OS version for conditional logic ; Related .......: _DetectWindowsVersion, _GetOSVersionDetailed ; =============================================================================================================================== Func _OSVersion($sWindowsPath = @WindowsDir) Local $aInfo = _DetectWindowsVersion($sWindowsPath) If @error Then Return "UNKNOWN" ; Parse build info Local $aBuildParts = StringSplit($aInfo[1], "|") Local $iBuild = Int($aBuildParts[1]) Local $sProductName = $aInfo[0] Local $bIsServer = (StringInStr($sProductName, "Server") > 0) ; Return appropriate short version string Select ;--- Windows NT Classic --- Case $iBuild = 528 Return "WIN_NT31" Case $iBuild = 807 Return "WIN_NT35" Case $iBuild = 1057 Return "WIN_NT351" Case $iBuild = 1381 Return "WIN_NT4" ;--- Windows 9x/ME --- Case $iBuild >= 950 And $iBuild <= 1111 Return "WIN_95" Case $iBuild = 1998 Return "WIN_98" Case $iBuild = 2222 Return "WIN_98SE" Case $iBuild = 3000 Return "WIN_ME" ;--- Windows 2000/XP/Server 2003 --- Case $iBuild = 2195 Return $bIsServer ? "WIN_2000SRV" : "WIN_2000" Case $iBuild = 2600 ; Check if it's Windows XP Embedded If StringInStr($sProductName, "Embedded") Then Return "WIN_XPe" Else Return "WIN_XP" EndIf Case $iBuild = 3790 Return $bIsServer ? "WIN_2003" : "WIN_XP64" ;--- Windows Vista/Server 2008 --- Case $iBuild >= 6000 And $iBuild <= 6003 Return $bIsServer ? "WIN_2008" : "WIN_VISTA" ;--- Windows 7/Server 2008 R2 --- Case $iBuild = 7600 Or $iBuild = 7601 Return $bIsServer ? "WIN_2008R2" : "WIN_7" ;--- Windows 8/Server 2012 --- Case $iBuild = 9200 Return $bIsServer ? "WIN_2012" : "WIN_8" ;--- Windows 8.1/Server 2012 R2 --- Case $iBuild = 9600 Return $bIsServer ? "WIN_2012R2" : "WIN_81" ;--- Windows 10/Server 2016 --- Case $iBuild >= 10240 And $iBuild <= 19045 If $bIsServer Then ; Determine server version by build If $iBuild = 14393 Then Return "WIN_2016" ElseIf $iBuild = 17763 Then Return "WIN_2019" Else Return "WIN_2016" ; Default for Windows 10 era servers EndIf Else Return "WIN_10" EndIf ;--- Windows Server 2022 --- Case $iBuild = 20348 Return "WIN_2022" ;--- Windows 11/Server 2025 --- Case $iBuild >= 22000 And $iBuild <= 26100 If $bIsServer Then If $iBuild = 26100 Then Return "WIN_2025" Else Return "WIN_2022" ; Fallback for unknown server builds EndIf Else Return "WIN_11" EndIf ;--- Future versions --- Case $iBuild > 26100 Return $bIsServer ? "WIN_SRV_FUTURE" : "WIN_FUTURE" ;--- Unknown --- Case Else Return "UNKNOWN" EndSelect EndFunc ;==>_OSVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: _GetOSVersionDetailed ; Description ...: Returns detailed OS version information in a structured array format ; Syntax ........: _GetOSVersionDetailed([$sWindowsPath = @WindowsDir]) ; Parameters ....: $sWindowsPath - [optional] Path to Windows directory. Default is @WindowsDir. ; Return values .: Success - Array with detailed version information: ; |[0] - Short Version (e.g., "WIN_11", "WIN_10", "WIN_2022") ; |[1] - Build Number with UBR (e.g., "22621.2787", "19045.3448") ; |[2] - Display Version (e.g., "23H2", "22H2", "21H2" or "N/A") ; |[3] - Product Name (e.g., "Windows 11 Pro", "Windows Server 2022 Datacenter") ; |[4] - Edition Type (e.g., "Professional", "Server", "Home", "Enterprise") ; |[5] - System Type ("Live" or "Offline") ; Failure - Array with error values, @error set: ; |Same error codes as _DetectWindowsVersion ; Author ........: Dao Van Trong - TRONG.PRO ; Remarks .......: This function provides comprehensive version information for detailed analysis ; Related .......: _DetectWindowsVersion, _OSVersion ; =============================================================================================================================== Func _GetOSVersionDetailed($sWindowsPath = @WindowsDir) Local $aInfo = _DetectWindowsVersion($sWindowsPath) If @error Then Local $aResult[6] = ["UNKNOWN", "0", "N/A", "Unknown", "Unknown", "Error"] Return SetError(@error, 0, $aResult) EndIf ; Parse build info Local $aBuildParts = StringSplit($aInfo[1], "|") Local $iBuild = Int($aBuildParts[1]) Local $sDisplayVersion = ($aBuildParts[0] >= 2) ? $aBuildParts[2] : "" Local $sUBR = ($aBuildParts[0] >= 5) ? $aBuildParts[5] : "" ; Create detailed result array Local $aResult[6] $aResult[0] = _OSVersion($sWindowsPath) ; Short version $aResult[1] = $iBuild & ($sUBR <> "" And $sUBR <> "0" ? "." & $sUBR : "") ; Full build with UBR $aResult[2] = $sDisplayVersion <> "" ? $sDisplayVersion : "N/A" ; Display version like 23H2 $aResult[3] = $aInfo[0] ; Product name $aResult[4] = $aInfo[3] ; Edition type $aResult[5] = $aInfo[4] ; System type (Live/Offline) Return $aResult EndFunc ;==>_GetOSVersionDetailed ; #INTERNAL_USE_ONLY# =========================================================================================================== Func __IsSystemLive($sWindowsPath) ; Check if we're analyzing the current running system Local $sCurrentWin = __NormalizePath(@WindowsDir) If $sWindowsPath = $sCurrentWin Then Return True ; Check if critical system files are locked (indicating live system) Local $aSystemFiles = [ _ $sWindowsPath & "\System32\Config\SYSTEM", _ $sWindowsPath & "\System32\Config\SOFTWARE", _ $sWindowsPath & "\System32\ntoskrnl.exe" _ ] For $sFile In $aSystemFiles If __IsFileLocked($sFile) Then Return True Next Return False EndFunc ;==>__IsSystemLive Func __IsFileLocked($sFilePath) If Not FileExists($sFilePath) Then Return False ; Try to open file exclusively - if fails, it's locked Local $hFile = DllCall("kernel32.dll", "handle", "CreateFileW", _ "wstr", $sFilePath, _ "dword", $GENERIC_READ, _ "dword", 0, _ ; No sharing "ptr", 0, _ "dword", $OPEN_EXISTING, _ "dword", 0, _ "handle", 0) If @error Or $hFile[0] = -1 Then Return True DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hFile[0]) Return False EndFunc ;==>__IsFileLocked Func __GetLiveSystemInfo(ByRef $aResult) ; Read from live registry Local $sRegPath = "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" $aResult[0] = RegRead($sRegPath, "ProductName") If @error Then $aResult[0] = RegRead($sRegPath, "EditionID") ; Fallback $aResult[1] = RegRead($sRegPath, "CurrentBuildNumber") If @error Then $aResult[1] = RegRead($sRegPath, "CurrentBuild") ; Get additional version info for precise identification Local $sDisplayVersion = RegRead($sRegPath, "DisplayVersion") ; 22H2, 23H2, etc. Local $sReleaseId = RegRead($sRegPath, "ReleaseId") ; 1903, 1909, 2004, etc. Local $sCurrentVersion = RegRead($sRegPath, "CurrentVersion") ; 6.3, 10.0, etc. Local $sUBR = RegRead($sRegPath, "UBR") ; Update Build Revision ; Store additional info for precise version detection If $sDisplayVersion <> "" Then $aResult[1] &= "|" & $sDisplayVersion If $sReleaseId <> "" Then $aResult[1] &= "|" & $sReleaseId If $sCurrentVersion <> "" Then $aResult[1] &= "|" & $sCurrentVersion If $sUBR <> "" Then $aResult[1] &= "|" & $sUBR Return ($aResult[0] <> "" And StringLen($aResult[1]) > 0) EndFunc ;==>__GetLiveSystemInfo Func __GetOfflineSystemInfo($sWindowsPath, ByRef $aResult) ; Try to load offline registry hive Local $sTempHive = "TEMP_SW_" & Random(1000, 9999, 1) Local $sHivePath = $sWindowsPath & "\System32\Config\SOFTWARE" If __LoadOfflineHive($sHivePath, $sTempHive) Then Local $sRegPath = "HKLM\" & $sTempHive & "\Microsoft\Windows NT\CurrentVersion" $aResult[0] = RegRead($sRegPath, "ProductName") If @error Then $aResult[0] = RegRead($sRegPath, "EditionID") $aResult[1] = RegRead($sRegPath, "CurrentBuildNumber") If @error Then $aResult[1] = RegRead($sRegPath, "CurrentBuild") ; Get additional version info for precise identification Local $sDisplayVersion = RegRead($sRegPath, "DisplayVersion") Local $sReleaseId = RegRead($sRegPath, "ReleaseId") Local $sCurrentVersion = RegRead($sRegPath, "CurrentVersion") Local $sUBR = RegRead($sRegPath, "UBR") ; Store additional info for precise version detection If $sDisplayVersion <> "" Then $aResult[1] &= "|" & $sDisplayVersion If $sReleaseId <> "" Then $aResult[1] &= "|" & $sReleaseId If $sCurrentVersion <> "" Then $aResult[1] &= "|" & $sCurrentVersion If $sUBR <> "" Then $aResult[1] &= "|" & $sUBR __UnloadOfflineHive($sTempHive) ; If registry read successful, return If $aResult[0] <> "" And StringLen($aResult[1]) > 0 Then Return True EndIf ; Fallback to file version reading Return __ReadVersionFromFiles($sWindowsPath, $aResult) EndFunc ;==>__GetOfflineSystemInfo Func __ReadVersionFromFiles($sWindowsPath, ByRef $aResult) ; Priority order for version files Local $aFiles = [ _ $sWindowsPath & "\System32\kernel32.dll", _ $sWindowsPath & "\System32\ntoskrnl.exe", _ $sWindowsPath & "\explorer.exe", _ $sWindowsPath & "\System32\user32.dll" _ ] For $sFile In $aFiles If FileExists($sFile) Then ; Get product name If $aResult[0] = "" Then $aResult[0] = FileGetVersion($sFile, "ProductName") If @error Then $aResult[0] = FileGetVersion($sFile, "FileDescription") EndIf ; Get version info Local $sVersion = FileGetVersion($sFile) If Not @error And $sVersion <> "" Then Local $aVer = StringSplit($sVersion, ".") If $aVer[0] >= 3 Then $aResult[1] = $aVer[3] ; Build number is the 3rd component Return True EndIf EndIf EndIf Next Return False EndFunc ;==>__ReadVersionFromFiles Func __GetVersionNameByBuild($sBuildData, $sProductName = "") ; Parse build info and additional data If Not StringInStr($sBuildData, "|") Then Return SetError(-1, 0, '') Local $aBuildParts = StringSplit($sBuildData, "|") Local $iBuild = Int($aBuildParts[1]) Local $sDisplayVersion = ($aBuildParts[0] >= 2) ? $aBuildParts[2] : "" Local $sReleaseId = ($aBuildParts[0] >= 3) ? $aBuildParts[3] : "" Local $sCurrentVersion = ($aBuildParts[0] >= 4) ? $aBuildParts[4] : "" Local $sUBR = ($aBuildParts[0] >= 5) ? $aBuildParts[5] : "" Local $bIsServer = (StringInStr($sProductName, "Server") > 0) Local $sVersionName = "" ; Precise version detection based on build number and additional info Select ;--- Windows NT Classic --- Case $iBuild = 528 $sVersionName = "Windows NT 3.1" Case $iBuild = 807 $sVersionName = "Windows NT 3.5" Case $iBuild = 1057 $sVersionName = "Windows NT 3.51" Case $iBuild = 1381 $sVersionName = "Windows NT 4.0" ;--- Windows 9x/ME --- Case $iBuild >= 950 And $iBuild <= 1111 $sVersionName = ($iBuild <= 1110) ? "Windows 95" : "Windows 95 OSR2" Case $iBuild = 1998 $sVersionName = "Windows 98" Case $iBuild = 2222 $sVersionName = "Windows 98 Second Edition" Case $iBuild = 3000 $sVersionName = "Windows Millennium Edition" ;--- Windows 2000/XP/Server 2003 --- Case $iBuild = 2195 $sVersionName = $bIsServer ? "Windows 2000 Server" : "Windows 2000 Professional" Case $iBuild = 2600 $sVersionName = "Windows XP" Case $iBuild = 3790 $sVersionName = $bIsServer ? "Windows Server 2003 R2" : "Windows XP Professional x64 Edition" ;--- Windows Vista/Server 2008 --- Case $iBuild = 6000 $sVersionName = $bIsServer ? "Windows Server 2008" : "Windows Vista" Case $iBuild = 6001 $sVersionName = $bIsServer ? "Windows Server 2008 SP1" : "Windows Vista SP1" Case $iBuild = 6002 Or $iBuild = 6003 $sVersionName = $bIsServer ? "Windows Server 2008 SP2" : "Windows Vista SP2" ;--- Windows 7/Server 2008 R2 --- Case $iBuild = 7600 $sVersionName = $bIsServer ? "Windows Server 2008 R2" : "Windows 7" Case $iBuild = 7601 $sVersionName = $bIsServer ? "Windows Server 2008 R2 SP1" : "Windows 7 SP1" ;--- Windows 8/Server 2012 --- Case $iBuild = 9200 $sVersionName = $bIsServer ? "Windows Server 2012" : "Windows 8" ;--- Windows 8.1/Server 2012 R2 --- Case $iBuild = 9600 $sVersionName = $bIsServer ? "Windows Server 2012 R2" : "Windows 8.1" ;--- Windows 10 Versions --- Case $iBuild = 10240 $sVersionName = "Windows 10 Version 1507 (RTM)" Case $iBuild = 10586 $sVersionName = "Windows 10 Version 1511 (November Update)" Case $iBuild = 14393 $sVersionName = $bIsServer ? "Windows Server 2016" : "Windows 10 Version 1607 (Anniversary Update)" Case $iBuild = 15063 $sVersionName = "Windows 10 Version 1703 (Creators Update)" Case $iBuild = 16299 $sVersionName = "Windows 10 Version 1709 (Fall Creators Update)" Case $iBuild = 17134 $sVersionName = "Windows 10 Version 1803 (April 2018 Update)" Case $iBuild = 17763 $sVersionName = $bIsServer ? "Windows Server 2019" : "Windows 10 Version 1809 (October 2018 Update)" Case $iBuild = 18362 $sVersionName = "Windows 10 Version 1903 (May 2019 Update)" Case $iBuild = 18363 $sVersionName = "Windows 10 Version 1909 (November 2019 Update)" Case $iBuild >= 19041 And $iBuild <= 19045 ; Use DisplayVersion or ReleaseId for precise identification If $sDisplayVersion <> "" Then Switch $sDisplayVersion Case "20H2" $sVersionName = "Windows 10 Version 20H2 (October 2020 Update)" Case "21H1" $sVersionName = "Windows 10 Version 21H1 (May 2021 Update)" Case "21H2" $sVersionName = "Windows 10 Version 21H2 (November 2021 Update)" Case "22H2" $sVersionName = "Windows 10 Version 22H2 (2022 Update)" Case Else $sVersionName = "Windows 10 Version 2004 (May 2020 Update)" EndSwitch ElseIf $sReleaseId <> "" Then Switch $sReleaseId Case "2009" $sVersionName = "Windows 10 Version 20H2 (October 2020 Update)" Case Else $sVersionName = "Windows 10 Version 2004 (May 2020 Update)" EndSwitch Else $sVersionName = "Windows 10 Version 2004 (May 2020 Update)" EndIf ;--- Windows Server 2022 --- Case $iBuild = 20348 $sVersionName = "Windows Server 2022" ;--- Windows 11 Versions --- Case $iBuild = 22000 $sVersionName = "Windows 11 Version 21H2" Case $iBuild >= 22621 And $iBuild <= 22631 ; Use DisplayVersion for precise identification If $sDisplayVersion <> "" Then Switch $sDisplayVersion Case "22H2" $sVersionName = "Windows 11 Version 22H2 (2022 Update)" Case "23H2" $sVersionName = "Windows 11 Version 23H2 (2023 Update)" Case Else $sVersionName = "Windows 11 Version 22H2 (2022 Update)" EndSwitch Else $sVersionName = "Windows 11 Version 22H2 (2022 Update)" EndIf Case $iBuild = 26100 $sVersionName = $bIsServer ? "Windows Server 2025" : "Windows 11 Version 24H2 (2024 Update)" ;--- Future/Insider Builds --- Case $iBuild > 26100 $sVersionName = $bIsServer ? "Windows Server (Insider Preview)" : "Windows 11 (Insider Preview)" ;--- Unknown --- Case Else $sVersionName = "Unknown Windows Version" EndSelect ; Add build number and UBR if available Local $sBuildDetails = " (Build " & $iBuild If $sUBR <> "" And $sUBR <> "0" Then $sBuildDetails &= "." & $sUBR $sBuildDetails &= ")" Return $sVersionName & $sBuildDetails EndFunc ;==>__GetVersionNameByBuild Func __GetEditionType($sProductName) Local $sLower = StringLower($sProductName) ; === Windows Server Editions === If StringInStr($sLower, "server") Then ; Windows Server 2022 If StringInStr($sLower, "2022") 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" Return "Server 2022" EndIf ; Windows Server 2019 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 ; Windows Server 2016 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 ; Generic Server 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 ; === Windows Client Editions === ; Windows 11 Editions 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 ; Windows 10 Editions 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 ; Windows 8.1 Editions 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 ; Windows 8 Editions 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 ; Windows 7 Editions 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 ; === Generic Edition Detection (for older versions or fallback) === ; Special editions 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" ; IoT editions 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" ; Mobile editions If StringInStr($sLower, "mobile enterprise") Then Return "Mobile Enterprise" If StringInStr($sLower, "mobile") Then Return "Mobile" ; RT editions If StringInStr($sLower, "rt") Then Return "RT" ; Workstation editions If StringInStr($sLower, "pro for workstations") Then Return "Pro for Workstations" If StringInStr($sLower, "workstation") Then Return "Workstation" ; Education editions If StringInStr($sLower, "pro education") Then Return "Pro Education" If StringInStr($sLower, "education") Then Return "Education" ; Enterprise editions If StringInStr($sLower, "enterprise") Then Return "Enterprise" ; Professional editions If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then ; Check for specific Pro variants If StringInStr($sLower, "media center") Then Return "Pro with Media Center" Return "Professional" EndIf ; Home editions 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" ; Core/Standard editions If StringInStr($sLower, "core") Then Return "Core" If StringInStr($sLower, "single language") Then Return "Single Language" ; Legacy editions If StringInStr($sLower, "millennium") Then Return "Millennium Edition" If StringInStr($sLower, "second edition") Then Return "Second Edition" ; Default fallback If $sProductName <> "" Then Return "Standard" Return "Unknown" EndFunc ;==>__GetEditionType Func __LoadOfflineHive($sHiveFile, $sTempKey) If Not FileExists($sHiveFile) Then Return False ; Enable backup privilege __EnableBackupPrivilege() Local $aRet = DllCall("advapi32.dll", "long", "RegLoadKeyW", _ "handle", $HKEY_LOCAL_MACHINE, _ "wstr", $sTempKey, _ "wstr", $sHiveFile) Return (IsArray($aRet) And $aRet[0] = $ERROR_SUCCESS) EndFunc ;==>__LoadOfflineHive Func __UnloadOfflineHive($sTempKey) Local $aRet = DllCall("advapi32.dll", "long", "RegUnloadKeyW", _ "handle", $HKEY_LOCAL_MACHINE, _ "wstr", $sTempKey) Return (IsArray($aRet) And $aRet[0] = $ERROR_SUCCESS) EndFunc ;==>__UnloadOfflineHive Func __EnableBackupPrivilege() Local $hToken, $aRet ; Open process token $aRet = DllCall("advapi32.dll", "bool", "OpenProcessToken", _ "handle", DllCall("kernel32.dll", "handle", "GetCurrentProcess")[0], _ "dword", 0x00000020, _ ; TOKEN_ADJUST_PRIVILEGES "handle*", 0) If @error Or Not $aRet[0] Then Return False $hToken = $aRet[3] ; Lookup privilege value Local $tLUID = DllStructCreate("int64") $aRet = DllCall("advapi32.dll", "bool", "LookupPrivilegeValueW", _ "ptr", 0, _ "wstr", "SeBackupPrivilege", _ "ptr", DllStructGetPtr($tLUID)) If @error Or Not $aRet[0] Then DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hToken) Return False EndIf ; Adjust token privileges 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 DllCall("advapi32.dll", "bool", "AdjustTokenPrivileges", _ "handle", $hToken, _ "bool", False, _ "ptr", DllStructGetPtr($tPriv), _ "dword", 0, _ "ptr", 0, _ "ptr", 0) DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hToken) Return True EndFunc ;==>__EnableBackupPrivilege Func __NormalizePath($sPath) Local Const $MAX_PATH = 260 Local $tBuffer = DllStructCreate("wchar[" & $MAX_PATH & "]") Local $aRet = DllCall("kernel32.dll", "dword", "GetFullPathNameW", _ "wstr", $sPath, _ "dword", $MAX_PATH, _ "ptr", DllStructGetPtr($tBuffer), _ "ptr", 0) If @error Or $aRet[0] = 0 Then Return StringReplace($sPath, "/", "\") Local $sNormalized = DllStructGetData($tBuffer, 1) Return StringRegExpReplace($sNormalized, "\\+$", "") ; Remove trailing backslashes EndFunc ;==>__NormalizePath #Region TEST ;#include "WindowsVersionDetector.au3" ; Basic usage Local $sOS = _OSVersion() If $sOS = "WIN_10" Then ; Windows 10 logic ConsoleWrite("!_OSVersion: " & $sOS & @CRLF) ElseIf $sOS = "WIN_11" Then ; Windows 11 logic ConsoleWrite("!_OSVersion: " & $sOS & @CRLF) EndIf ; Offline system Local $aOffline = _GetOSVersionDetailed("X:\Windows") ConsoleWrite("!Offline OS: " & $aOffline[0] & " Build: " & $aOffline[1] & @CRLF) ; Details Local $aDetailed = _GetOSVersionDetailed() ConsoleWrite("+Current OS: " & $aDetailed[0] & " Build: " & $aDetailed[1] & @CRLF) Local $aResult = _DetectWindowsVersion("C:\Windows") ConsoleWrite('- ProductName: ' & $aResult[0] & @CRLF & '- BuildNumber: ' & $aResult[1] & @CRLF & '- VersionName: ' & $aResult[2] & @CRLF & '- Edition: ' & $aResult[3] & @CRLF & '- SystemType: ' & $aResult[4] & @CRLF) #EndRegion TEST RT: !_OSVersion: WIN_10 !Offline OS: UNKNOWN Build: 0 +Current OS: WIN_10 Build: 19045.6216 - ProductName: Windows 10 Enterprise LTSC 2021 - BuildNumber: 19045|22H2|2009|6.3|6216 - VersionName: Windows 10 Version 22H2 (2022 Update) (Build 19045.6216) - Edition: Enterprise - SystemType: Live  Edited 52 minutes ago by Trong v2 WildByDesign, Musashi and argumentum 3 Regards, Â
wakillon Posted 18 hours ago Posted 18 hours ago 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.16.1 X86 - SciTE 4.4.6 - WIN 11 24H2 X64 - Other Example Scripts
argumentum Posted 17 hours ago Posted 17 hours ago (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 17 hours ago by argumentum more Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Trong Posted 1 hour ago Author Posted 1 hour ago I have released version 2, you might want to try it Regards, Â
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