How can I find the Windows product name in Windows 11?
Asked Answered
U

6

21

Windows 11, released yesterday, reports itself as Windows 10.0 just about everywhere - RtlGetVersion says 10.0, and if you ask VerifyVersionInfo if you are 11.0 or greater, it says no.

There seems to be no new GUID to shove into app.manifest to say "hey I support Windows 11" like there was for Windows 7, 8, 8.1, and 10.

Currently I rely on HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName to tell me what the current version of Windows is, but on my machine that I've upgraded, it still says "Windows 10 Enterprise", not "Windows 11 Enterprise".

There appears to only be a single place in the registry that contains the text "Windows 11" and that is the BCD section (boot configuration), which can also be renamed so I don't want to touch that.

So far I have only identified a handful of methods to tell if I am running on Windows 11:

  1. Invoke WMI to query Win32_OperatingSystem and check the Name property, which simply says "Windows 11". This is incomplete (it does not include the SKU such as "Enterprise"), and WMI is relatively slow and slightly brittle, so it's not an acceptable solution for my use-case.

  2. Check the build number to see if it is above 21996 (beta builds) or 22000 (first public release). As above, this won't include the SKU, and would require some manual jiggery-pokery in order to build the full string.

  3. Run sysinfo and parse the output. This is quite slow, and possibly brittle (I haven't checked but the output might be localised into different languages).

  4. winver knows, but it's a GUI application so I can't exactly query it programmatically.

Does anyone have any other ideas on how to get the string "Windows 11 Enterprise" (or "Windows 11 Pro", etc. as the case may be) out of my operating system in a performant and complete manner? Where do WMI, sysinfo, and winver get it from?

I need to do this from a .NET library, but P/Invokes / native function calls are acceptable solutions.

Unbeatable answered 6/10, 2021 at 6:6 Comment(7)
MS have long been advocating that you test for features as you need them, rather than OS version checks. Perhaps they've doubled down into now forcing you to do so?Knitted
This isn't being used for machine decisions, but for error reporting to inform developers - I want to be able to tell what version of Windows my application broke on.Unbeatable
Naming it Win11 was a marketing decision, it doesn't have anything to do with the OS version. It is just another Win10 release, among many, distinguished by the build number. If it is 22000 or larger then you know it is Win11.Eisen
You should log the build number, not the marketing name. That will also let you distinguish among various versions of Windows 10 (18363, 19042, etc.)Carolann
We log that as well, but I’d rather we start looking for the correct Win11 build or correct Win10 build as appropriate rather than devs getting their wires crossed early on… and I’d rather not be responsible for maintaining my own OS version mappings forever.Unbeatable
@RaymondChen Agreed BuildNumber is the way to go. It doesn't help though that the BuildNumber on the installers for windows releases that are just "enablements" report a different build number than what is actually installed... e.g., the installer for Windows 10 19043 and 19042 report a product version of 10.0.10941.1 .Endocrinology
How is using WMI any more "brittle" than relying on undocumented registry values? The accepted answer to Get Windows Edition suggests a few more properties of Win32_OperatingSystem to check. I don't have Windows 11 to test with, but Caption and OperatingSystemSku report Microsoft Windows 10 Pro and 48 (PRODUCT_PROFESSIONAL), respectively, for my Windows 10 Pro system. You can add BuildNumber and Version to your query as well.Rotatory
U
14

Leaving this here so that I can find it later:

It seems that Windows itself (e.g. winver) gets this information from Windows branding - specifically from the resource table in %WinDir%\Branding\Basebrd\en-US\basebrd.dll.mui.

To access this one could use the private APIs in %WinDir%\System32\winbrand.dll. Specifically, the function BrandingFormatString which accepts a wide string (LPW[C]STR) and returns a wide string.

e.g. BrandingFormatString("%WINDOWS_LONG%") returns "Windows 11 Pro" on my home PC.

I do not know the lifecycle semantics of the resulting string, i.e. if/when/how it should be freed.

The following code serves as a functional proof-of-concept (C# 9.0):

using System;
using System.Runtime.InteropServices;

[DllImport("winbrand.dll", CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
static extern string BrandingFormatString(string format);

Console.WriteLine(BrandingFormatString("Hello World from %WINDOWS_LONG%!"));

Unbeatable answered 6/10, 2021 at 8:57 Comment(1)
You actually need to release memory by calling GlobalFree, Here's more info.Anastigmatic
E
5

tldr - Using the EditionID and the CurrentBuild from the CurrentVersion in the registry seems to be a reliable way to determine Win10 vs Win11 and the "edition" of the software. EditionID is "Professional" on Windows 10 Pro and Windows 11 Pro, and CurrentBuild >= ~22000 tells you if it is 10 or 11.

The collection of registry values in the HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion reveals what feels like a lack of planning on Microsoft's part. There's ReleaseId, which is a number that changed with each Windows 10 release (e.g., 1903, 1909, 2004,...) until its last change for Windows 10 20H2, where it changed to 2009. At the same time, DisplayVersion was added, and was set to 20H2.

Then Windows 10 21H1 released, and ReleaseId inexplicably stayed at 2009.

The fact that both current Windows 10 and Windows 11 releases can have the same DisplayVersion (e.g., 21H2 when Windows 10 21H2 releases soon) and ProductName (e.g., Windows 10 Pro) is really head-scratching. (Thanks @yaakov for catching my mistake saying it was 21H1.)

Endocrinology answered 7/10, 2021 at 19:7 Comment(3)
Windows 11 has DisplayVersion = 21H2, which appears to be correct, and is what is shown by WinVer.Unbeatable
Doh, you are completely right. The point I was trying to make was that there will also be a Windows 10 21H2 - it isn't yet released, and it will be odd to have both 10 and 11 21H2. Thanks for the correction.Endocrinology
As of today, it's 23H2. (Win-11 Pro)Concubinage
U
5

The following code has been tested on Windows XP, 7, 10, 11. It works on 32 bit and 64 bit operating systems. It works inside 32 bit and 64 bit applications.

The following strings will be generated:

  • "Microsoft Windows XP, Build 2600, 32 bit"
  • "Windows 7 Ultimate, Build 7601, 64 bit"
  • "Windows 10 Enterprise LTSC 2019, Version 1809, Build 17763, 64 bit"
  • "Windows 10 Pro, Version 1909, Build 18362, 64 bit"
  • "Windows 11 Professional, Version 21H2, Build 22000, 64 bit"

Put the code into a static constructor so it executes only once and writes the version into a static variable.

static String ms_OperatingSystem;

static Constructor()
{
    try
    {
        String s_KernelPath = Path.Combine(Environment.SystemDirectory,"Kernel32.dll");
        FileVersionInfo k_Kernel = FileVersionInfo.GetVersionInfo(s_KernelPath);

        // on 32 bit Windows this will read the 32 bit hive instead
        using (RegistryKey i_HKLM = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
        {
            using (RegistryKey i_RegVer = i_HKLM.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion", false))
            {
                // Kernel32.dll on Windows 11 has Product Version 10.0.22000.120
                // ATTENTION: Windows 10 has the following Kernel32 versions: (Microsoft is sooooo stupid!)
                // FileVersion    =  6.2.18362
                // ProductVersion = 10.0.18362
                if (k_Kernel.ProductMajorPart == 10 && k_Kernel.ProductBuildPart >= 22000)
                {
                    ms_OperatingSystem = "Windows 11";

                    Object o_Edition = i_RegVer.GetValue("EditionID"); // "Professional"
                    if (o_Edition is String)
                        ms_OperatingSystem += " " + o_Edition;
                }
                else
                {
                    // "Microsoft Windows XP"
                    // "Windows 7 Ultimate"
                    // "Windows 10 Pro"  (same string on Windows 11. Microsoft SUCKS!)
                    ms_OperatingSystem = (String)i_RegVer.GetValue("ProductName");
                }

                // See: https://en.wikipedia.org/wiki/Windows_10_version_history
                // Windows 10 older releases --> "2009" (invalid if DisplayVersion exists)
                Object o_ReleaseID = i_RegVer.GetValue("ReleaseId");

                // Windows 10 latest release --> "21H1"
                // Windows 11 first  release --> "21H2"
                Object o_DispVer = i_RegVer.GetValue("DisplayVersion");

                // Use ReleaseID ONLY if DisplayVersion does not exist in registry!
                     if (o_DispVer   is String) ms_OperatingSystem += ", Version " + o_DispVer;
                else if (o_ReleaseID is String) ms_OperatingSystem += ", Version " + o_ReleaseID;

                ms_OperatingSystem += ", Build " + k_Kernel.ProductBuildPart;

                if (Environment.Is64BitOperatingSystem) ms_OperatingSystem += ", 64 bit";
                else                                    ms_OperatingSystem += ", 32 bit";
            }
        }
     }
     catch (Exception Ex)
     {
        ms_OperatingSystem = Ex.Message;
     }
}
Unmistakable answered 23/12, 2021 at 0:38 Comment(0)
C
1

I created a remote support tool for desktop admins (see http://www.appslife-rdt.appspot.com) In VB.Dot.Net i used a call to the WMI space Win32_OperatingSystem and got the "Name" value back. This then needs to be split to get the first object which is what you require. i.e.

Dim query2 As New SelectQuery("SELECT * FROM Win32_OperatingSystem")
Dim searcher2 As New ManagementObjectSearcher(objManagementScope2, query2, QueryOptions)
        For Each mo As ManagementObject In searcher2.[Get]()
                           OSname = mo("Name")
        Next

        Dim array1 As Array = Nothing
        array1 = Split(OSname, "|")
        OSname = array1(0).ToString

OSname then gives you the "Windows 11 Pro" or "Windows XP Professional" that you require.

I also get the OSVersion with the latest patch update info from registry as follows if needed...

THIS IS FOR CLIENT VERSIONS 10/11 :-

.SetPropertyValue("sSubKeyName", "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Update\TargetingInfo\Installed\Client.OS.rs2.amd64") .SetPropertyValue("sValueName", "Version")

THIS IS FOR SERVER VERSIONS 2019 :-

.SetPropertyValue("sSubKeyName", "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Update\TargetingInfo\Installed\Server.OS.amd64") .SetPropertyValue("sValueName", "Version")

Hope this is of help.

Costin answered 18/11, 2021 at 19:19 Comment(0)
F
0
    Public Structure OsVersions
        Public Shared WindowsXPBuild As Integer = 2600
        Public Shared WindowsVistaBuild As Integer = 6000 
        Public Shared Windows7Build As Integer = 7601 
        Public Shared Windows8Build As Integer = 9200 
        Public Shared Windows8Point1Build As Integer = 9600 
        Public Shared Windows10Build As Integer = 14393 
        Public Shared Windows11Build As Integer = 22000 
    End Structure

    Public Shared Function GetWindwosInfo() As (RealWindowsName As String, RealWindowsVersion As Integer)
        Dim RealWindowsNameResult As String = Nothing
        Dim RealWindowsVersionResult As Integer = Nothing
        With Environment.OSVersion.Version
            RealWindowsVersionResult = .Build
            If .Build >= MyIO.OsVersions.Windows11Build Then RealWindowsNameResult = "Windows 11" : GoTo Finish
            If .Build >= MyIO.OsVersions.Windows10Build Then RealWindowsNameResult = "Windows 10" : GoTo Finish
            If .Build >= MyIO.OsVersions.Windows8Build Then RealWindowsNameResult = "Windows 8" : GoTo Finish
            If .Build >= MyIO.OsVersions.Windows7Build Then RealWindowsNameResult = "Windows 7" : GoTo Finish
            If .Build >= MyIO.OsVersions.WindowsVistaBuild Then RealWindowsNameResult = "Windows Vista" : GoTo Finish
            If .Build >= MyIO.OsVersions.WindowsXPBuild Then RealWindowsNameResult = "Windows XP" : GoTo Finish
        End With
Finish:
        Return (
            RealWindowsName:=RealWindowsNameResult,
            RealWindowsVersion:=RealWindowsVersionResult
            )
    End Function
Foamflower answered 28/6, 2023 at 15:24 Comment(2)
the Public Shared WindowsVistaBuild As Integer = 6000 is only for modern windows vista that lunched in 2007 not the earlier version from 2003Foamflower
Answer needs supporting information Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Gambill
L
0

The powershell command Get-ComputerInfo reports "OsName" as e.g. "Microsoft Windows 11 Pro"

Livery answered 18/5, 2024 at 9:25 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.