Jump to content

Recommended Posts

Posted

UDF:

#include-once

; #INDEX# =======================================================================================================================
; Title .........: Windows Version Detector
; 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

EG:

#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)

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

 

Regards,
 

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   1 member

×
×
  • Create New...