Windows version in c# [duplicate] - c#

This question already has answers here:
Detect Windows version in .NET
(18 answers)
Closed 6 years ago.
I want to know which Windows version the PC has.. in C# Framework 3.5
I have tried using
OperatingSystem os = Environment.OSVersion;
Version ver = os.Version;
But the result is
Plataform: WIN32NT
version 6.2.9200
Version minor: 2
Version Major: 6
The problem is that I have "Windows 8 Pro"...
How can I detect it?
Thanks

You will have to match version numbers with the appropriate string value yourself.
Here is a list of the most recent Windows OS and their corresponding version number:
Windows Server 2016 & 2019 - 10.0*
Windows 10 - 10.0*
Windows 8.1 - 6.3*
Windows Server 2012 R2 - 6.3*
Windows 8 - 6.2
Windows Server 2012 - 6.2
Windows 7 - 6.1
Windows Server 2008 R2 - 6.1
Windows Server 2008 - 6.0
Windows Vista - 6.0
Windows Server 2003 R2 - 5.2
Windows Server 2003 - 5.2
Windows XP 64-Bit Edition - 5.2
Windows XP - 5.1
Windows 2000 - 5.0
*For applications that have been manifested for Windows 8.1 or 10. Applications not manifested for 8.1 / 10 will return the Windows 8 OS version value (6.2).
Here's the source.
Also, from the same source:
Identifying the current operating system is usually not the best way
to determine whether a particular operating system feature is present.
This is because the operating system may have had new features added
in a redistributable DLL. Rather than using the Version API Helper
functions to determine the operating system platform or version
number, test for the presence of the feature itself.

In my scenario I needed my application to capture computer info for possible bug-reports and statistics.
I did not find the solutions where an application manifest had to be added satisfactory. Most of the suggestions I found while googling this suggested just that, unfortunately.
Thing is, when using a manifest, each OS version has to be added manually to it in order for that particular OS version to be able to report itself at runtime.
In other words, this becomes a race condition: A user of my app may very well be using a version of my app that pre-dates the OS in use. I would have to upgrade the app immediately when a new OS version was launched by Microsoft. I would also have to force the users to upgrade the app at the same time as they updated the OS.
In other words, not very feasible.
After browsing through the options I found some references (surprisingly few compared to the app manifest) that instead suggested using registry lookups.
My (chopped down) ComputerInfo class with only WinMajorVersion, WinMinorVersion and IsServer properties looks like this:
using Microsoft.Win32;
namespace Inspection
{
/// <summary>
/// Static class that adds convenient methods for getting information on the running computers basic hardware and os setup.
/// </summary>
public static class ComputerInfo
{
/// <summary>
/// Returns the Windows major version number for this computer.
/// </summary>
public static uint WinMajorVersion
{
get
{
dynamic major;
// The 'CurrentMajorVersionNumber' string value in the CurrentVersion key is new for Windows 10,
// and will most likely (hopefully) be there for some time before MS decides to change this - again...
if (TryGeRegistryKey(#"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentMajorVersionNumber", out major))
{
return (uint) major;
}
// When the 'CurrentMajorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion'
dynamic version;
if (!TryGeRegistryKey(#"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", out version))
return 0;
var versionParts = ((string) version).Split('.');
if (versionParts.Length != 2) return 0;
uint majorAsUInt;
return uint.TryParse(versionParts[0], out majorAsUInt) ? majorAsUInt : 0;
}
}
/// <summary>
/// Returns the Windows minor version number for this computer.
/// </summary>
public static uint WinMinorVersion
{
get
{
dynamic minor;
// The 'CurrentMinorVersionNumber' string value in the CurrentVersion key is new for Windows 10,
// and will most likely (hopefully) be there for some time before MS decides to change this - again...
if (TryGeRegistryKey(#"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentMinorVersionNumber",
out minor))
{
return (uint) minor;
}
// When the 'CurrentMinorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion'
dynamic version;
if (!TryGeRegistryKey(#"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", out version))
return 0;
var versionParts = ((string) version).Split('.');
if (versionParts.Length != 2) return 0;
uint minorAsUInt;
return uint.TryParse(versionParts[1], out minorAsUInt) ? minorAsUInt : 0;
}
}
/// <summary>
/// Returns whether or not the current computer is a server or not.
/// </summary>
public static uint IsServer
{
get
{
dynamic installationType;
if (TryGeRegistryKey(#"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "InstallationType",
out installationType))
{
return (uint) (installationType.Equals("Client") ? 0 : 1);
}
return 0;
}
}
private static bool TryGeRegistryKey(string path, string key, out dynamic value)
{
value = null;
try
{
var rk = Registry.LocalMachine.OpenSubKey(path);
if (rk == null) return false;
value = rk.GetValue(key);
return value != null;
}
catch
{
return false;
}
}
}
}

I released the OsInfo nuget to easily compare Windows versions.
bool win8OrLess = Environment.OSVersion.IsLessThanOrEqualTo(OsVersion.Win8);
bool winXp = Environment.OSVersion.IsEqualTo(OsVersion.WinXP);
int? servicePack = Environment.OSVersion.GetServicePackVersion();
bool is64bit = Environment.OSVersion.Is64Bit(); // Already covered in .NET 4.5+

Try this:
using System.Management;
private string fnGetFriendlyName()
{
var name = (from x in new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem").Get().OfType<ManagementObject>()
select x.GetPropertyValue("Caption")).FirstOrDefault();
return name != null ? name.ToString() : "Unknown";
}
Source: https://stackoverflow.com/a/2016557/3273962

Related

C# Determine OS Version in .NET 6

What is the correct way to determine the correct OS version in .NET 6?
I found many different solutions regarding this topic. All of them are quite out of date I think.
I want to get something like "Windows 10 Enterprise build 22000 (64 bit)"
Environment.OSVersion.ToString()
gives "Microsoft Windows NT 10.0.22000.0"
RuntimeInformation.OSDescription
gives "Microsoft Windows 10.0.22000.0"
RuntimeInformation.OSArchitecture.ToString()
gives "X64"
So far I'm using:
Console.WriteLine(RuntimeInformation.OSDescription + " | " + RuntimeInformation.OSArchitecture.ToString())
This gives "Microsoft Windows 10.0.22000.0 | X64"
Is there a way to get something like "Windows 10 Enterprise | X64" in .NET 6?
In addition to that, I'm looking for a way to get the Windows install language and the current language.
The function:
RuntimeInformation.OSArchitecture.ToString();
returns the architecture that the OS was compiled, that is, in this case it was x86-64 (string-shaped)
The functions:
Environment.OSVersion.ToString()
RuntimeInformation.OSDescription
returns windows version
With this and with this link here:
(Get OS Version / Friendly Name in C#) we can get to this code:
using System.Runtime.InteropServices;
using System.Management;
static int GetARCHFriendlyBits(Architecture architecture)
{
return architecture switch
{
Architecture.X64 => 64,
Architecture.X86 => 32,
Architecture.Arm64 => 64,
Architecture.Arm => 32,
Architecture.Wasm => -1,
Architecture.S390x => -1,
_ => -1,
};
}
static string GetOSFriendlyName1()
{
string result = string.Empty;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
ManagementObjectSearcher searcher = new("SELECT Caption FROM Win32_OperatingSystem");
ManagementObject os = searcher.Get().Cast<ManagementObject>().First();
if (os["Caption"].ToString() is string osResult)
result = osResult;
}
else
{
return $"{RuntimeInformation.OSDescription} ({RuntimeInformation.OSArchitecture})";
}
if (result == string.Empty)
return $"{RuntimeInformation.OSDescription} ({RuntimeInformation.OSArchitecture})";
else
return $"{result} build {Environment.OSVersion.Version.Build} ({GetARCHFriendlyBits(RuntimeInformation.OSArchitecture)} bits)";
}
static string GetOSFriendlyName2()
{
string result = string.Empty;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
ManagementObjectSearcher searcher = new("SELECT Caption FROM Win32_OperatingSystem");
ManagementObject os = searcher.Get().Cast<ManagementObject>().First();
if (os["Caption"].ToString() is string osResult)
result = osResult;
}
else
{
return $"{RuntimeInformation.OSDescription} ({RuntimeInformation.OSArchitecture})";
}
if (result == string.Empty)
return $"{RuntimeInformation.OSDescription} ({RuntimeInformation.OSArchitecture})";
else
return $"{result} | {RuntimeInformation.OSArchitecture}";
}
Console.WriteLine(GetOSFriendlyName1());
Console.WriteLine(GetOSFriendlyName2());
which in my case writes this line here on the console:
Microsoft Windows 11 Home Single Language build 22621 (64 bits)
Microsoft Windows 11 Home Single Language | X64
To use System.Management, I had to install microsoft NuGet System.Management

In what versions of Windows are Storage Management API Classes such as 'MSFT_PhysicalDisk' implemented?

I am trying pull metrics such as 'MediaType' from MSFT_PhysicalDisk. I'm successful on a Windows 10 machine, but not on a Windows 7 machine.
On what type of machines is MSFT_PhysicalDisk available?
The reference for Storage Management API Classes:
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/storage-management-api-classes
See code below for an example of what I'm trying to do:
bool isSsd;
try
{
var physDiskQuery =
$"SELECT MediaType FROM MSFT_PhysicalDisk WHERE DeviceID='{driveNumber.Value}'";
var wmiScope = #"\\.\root\microsoft\windows\storage";
using (var physicalDiskSearcher = new ManagementObjectSearcher(wmiScope, physDiskQuery))
{
var objectCollection = physicalDiskSearcher.Get();
var physicalDisk = objectCollection.Cast<ManagementBaseObject>().SingleOrDefault();
if (physicalDisk == null)
return null;
isSsd = (ushort)physicalDisk["MediaType"] == 4;
}
}
catch (Exception exception)
{
Debug.WriteLine($"Error while checking for SSD drive. Details: {exception.GetBaseException()}");
return null;
}
return isSsd;
MSDN documentation lists requirements way at the bottom of the page. For the MSFT_PhysicalDisk class it says...
Minimum supported client: Windows 8 [desktop apps only]
Minimum supported server: Windows Server 2012 [desktop apps only]
In other words, you need at least Windows version 6.2.

Get current version OS in Windows 10 in C#

I Use C#. I try to get the current version of the OS:
OperatingSystem os = Environment.OSVersion;
Version ver = os.Version;
I get on the Windows 10: 6.2.
But 6.2 is Windows 8 or WindowsServer 2012 (Detect Windows version in .net)
I found the following solution (How can I detect if my app is running on Windows 10).
static bool IsWindows10()
{
var reg = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
string productName = (string)reg.GetValue("ProductName");
return productName.StartsWith("Windows 10");
}
This is the best way to get the current version in C#?
Add application manifest to your application and add the supportedOS Id of Windows 8.1 and Windows 10 to the manifest:
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
</application>
</compatibility>
Now Environment.OSVersion includes the correct data for Windows 8.1 and Windows 10 and not 6.2 to indicate you run Windows 8. This is a change since Windows 8.1.
Here is a link from Microsoft offical, indicating how to get the System Version. It actually is a call to the Version API Helper Functions
So basically you must convert this code into C# because it's in C++, then keep only the Windows 10 part...
#include <windows.h>
#include <stdio.h>
#include <VersionHelpers.h>
int
__cdecl
wmain(
__in int argc,
__in_ecount(argc) PCWSTR argv[]
)
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
if (IsWindows10OrGreater())
{
printf("Windows10OrGreater\n");
}
}
And if you like trying to read code, you can check out this one link. This DLL can be used to get information on the OS...
I have created this simple method in C# and it has worked for me.
public static string GetWindowsVersion()
{
string registryPath = "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion";
string build = null;
int number = 0;
try
{
build = Registry.GetValue(registryPath, "CurrentBuild", null).ToString();
}
catch { return null; }
number = Int32.Parse(build);
if (number == 7601)
return "Windows 7";
else if (number == 9200)
return "Windows 8";
else if (number == 9600)
return "Windows 8.1";
else if (number >= 10240 && number <= 19045)
return "Windows 10";
else if (number >= 22000)
return "Windows 11";
else
return "Older version";
/* Go here to find more build numbers and evaluate more conditions
*
* https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
*
*/
}

C# get Windows CD Key

I've been using the below code in order to get the Windows License Key. It worked pretty well a long time. But now I discovered that it works on Windows XP (x86) but not on Windows 7 x64.
Reason: The DigitalProductID regisitry value contains only zeroes within the range we are looking for on the 64 bit operating system. Therefore the result it BBBBB-BBBBB-BBBBB-BBBBB-BBBBB. Why is it so and how can I fix this?
public static string LicenseCDKey
{
get
{
try
{
byte[] rpk = (byte[])Registry.LocalMachine
.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion")
.GetValue("DigitalProductId");
string serial = "";
const string possible = "BCDFGHJKMPQRTVWXY2346789";
for (int i = 0; i < 25; i++)
{
int accu = 0;
for (int a = 0; a < 15; a++)
{
accu <<= 8;
accu += rpk[66 - a];
rpk[66 - a] = (byte)(accu / 24 & 0xff);
accu %= 24;
}
serial = possible[accu] + serial;
if (i % 5 == 4 && i < 24)
{
serial = "-" + serial;
}
}
return serial;
}
catch
{
return ErrorString;
}
}
}
As user287107 pointed out x86 applications (32 bit) running on a x64 operating system are using a different registry (registry view).
In order to access the x64 registry you have a few options:
Change your platform target to x64 (Visual Studio project settings).
If you are using .Net Framework 4.0 you could use the RegistryKey class and RegistryView enum to access the x64 registry.
RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
RegistryView.Registry64);
string keyPath = #"Software\Microsoft\Windows NT\CurrentVersion";
byte[] rpk = (byte[])key.OpenSubKey(keyPath).GetValue("DigitalProductId");
If you are not using the .Net Framework 4.0 and you do not want to set your platform target to x64 you have to use Interop (RegOpenKeyEx() Win32 API function with the KEY_WOW64_32KEY flag) to access the x64 registry.
BEGIN EDIT
I've just found an interesting post explaining why the DigitialProductId key could be null/empty:
You are using an Volume License Key to activate your Windows 7 operating system. The VLC key is deleted from the registry after activation.
Someone deleted the registry key (modified the content of this key) manually using the command slmgr –cpky
END EDIT
32 bit applications use a different registry path
a 32 bit application accesses the registry path in
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion
where it does not find the product key.
changing the processor type to x64 worked for me to get the real key.

availability of Win32_MountPoint and Win32_Volume on Windows XP?

From the MSDN articles I've found -- http://msdn.microsoft.com/en-us/library/aa394515(v=VS.85).aspx -- Win32_Volume and Win32_MountPoint aren't available on Windows XP.
However, I'm developing a C# app on Windows XP (64bit), and I can get to those WMI classes just fine. Users of my app will be on Windows XP sp2 with .Net 3.5 sp1.
Googling around, I can't determine whether I can count on this or not.
Am I successful on my system because of one or more of the following:
- windows xp service pack 2?
- visual studio 2008 sp1 was installed?
- .Net 3.5 sp1?
Should I use something other than WMI to get at the volume/mountpoint info?
Below is sample code that's working...
public static Dictionary<string, NameValueCollection> GetAllVolumeDeviceIDs()
{
Dictionary<string, NameValueCollection> ret = new Dictionary<string, NameValueCollection>();
// retrieve information from Win32_Volume
try
{
using (ManagementClass volClass = new ManagementClass("Win32_Volume"))
{
using (ManagementObjectCollection mocVols = volClass.GetInstances())
{
// iterate over every volume
foreach (ManagementObject moVol in mocVols)
{
// get the volume's device ID (will be key into our dictionary)
string devId = moVol.GetPropertyValue("DeviceID").ToString();
ret.Add(devId, new NameValueCollection());
//Console.WriteLine("Vol: {0}", devId);
// for each non-null property on the Volume, add it to our NameValueCollection
foreach (PropertyData p in moVol.Properties)
{
if (p.Value == null)
continue;
ret[devId].Add(p.Name, p.Value.ToString());
//Console.WriteLine("\t{0}: {1}", p.Name, p.Value);
}
// find the mountpoints of this volume
using (ManagementObjectCollection mocMPs = moVol.GetRelationships("Win32_MountPoint"))
{
foreach (ManagementObject moMP in mocMPs)
{
// only care about adding directory
// Directory prop will be something like "Win32_Directory.Name=\"C:\\\\\""
string dir = moMP["Directory"].ToString();
// find opening/closing quotes in order to get the substring we want
int first = dir.IndexOf('"') + 1;
int last = dir.LastIndexOf('"');
string dirSubstr = dir.Substring(first , last - first);
// use GetFullPath to normalize/unescape any extra backslashes
string fullpath = Path.GetFullPath(dirSubstr);
ret[devId].Add(MOUNTPOINT_DIRS_KEY, fullpath);
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Problem retrieving Volume information from WMI. {0} - \n{1}",ex.Message,ex.StackTrace);
return ret;
}
return ret;
}
I guess the Win32_MountPoint and Win32_Volume classes are available on Windows XP Professional x64 Edition because it's based on the Windows Server 2003 codebase. On 32-bit versions of Windows XP, these classes don't exist and to perform your task you need to P/Invoke native volume management functions, like Tim said.
You may need to pinvoke into the Win32 Volume Management Functions

Categories