Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting Windows serial number (was: Getting MachineGuid from Registry)

I am trying to fetch MachineGuid from the registry, to create some level of binding with the OS for my license system. From the documentation I can use

string key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography";
string r = (string)Registry.GetValue(key, "MachineGuid", (object)"default");

to get it. Also, the docs tell me that I get "default" when the name is not found, or null if the key doesn't exist. I should get a security exception if I have no access.

The above code gives me "default", which means the name isn't found. However, if I look in the registry with RegEdit, it's there. How do I get the MachineGuid value from an application without administrator privileges?

Update: when using reg.exe I have no problems getting the value.

Update: I updated the title, so people looking for a unique way of determining the Windows install get here as well.

like image 672
Bart Friederichs Avatar asked Jan 08 '13 10:01

Bart Friederichs


People also ask

How to get MachineGuid in c#?

string key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography"; string r = (string)Registry. GetValue(key, "MachineGuid", (object)"default"); to get it.

What is a machine GUID?

A GUID (globally unique identifier) is a 128-bit text string that represents an identification (ID). Organizations generate GUIDs when a unique reference number is needed to identify information on a computer or network. A GUID can be used to ID hardware, software, accounts, documents and other items.


2 Answers

which is probably why it doesn't work reliably among different versions of Windows

No, that's not the reason. This problem is caused by the platform target selection for your EXE project. Project + Properties, Build tab, Platform target combobox. You have it set to x86 instead of AnyCPU. On VS2012, the "Prefer 32-bit" checkbox matters. This setting forces your program to run in 32-bit mode on a 64-bit version of Windows. Which has a number of side effects, the one that matters here is that access to registry keys are redirected. Your program is actually reading the value of HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\MachineGuid. Which doesn't exist.

The x86 selection is the default for VS2010 and up, previously AnyCPU was the default. Microsoft prefers x86, Visual Studio works better with 32-bit mode processes. Particularly when debugging, VS is a 32-bit process itself so requires the remote debugger if your program executes in 64-bit mode. Which has a few limitations like not supported mixed-mode debugging. And the Edit + Continue feature only works for 32-bit code. Your program itself however works "better" if you have the setting at AnyCPU, including not getting bitten by the file system and registry redirection appcompat features built into Windows.

If you are really stuck with x86 mode, typically because you have a dependency on 32-bit native code that you can't update then the next workaround is to use the .NET 4+ RegistryKey.OpenBaseKey() method. Which allows you to pass RegistryView.Registry64, ensuring that you'll read the non-redirected keys.

Sure, using WMI is a workaround. Just keep in mind that you are not reading the same information when you use Win32_OperatingSystem.SerialNumber. To what degree that key is reliably random on different machines isn't that clear to me, let's just say that this value is a pretty attractive target for the kind of users that are not very interested in paying the license fee for your product either.

Last but not least, do consider that it is pretty easy to generate your own unique id that doesn't depend at all on Windows. With the considerable advantage that you won't piss off your customer when he updates Windows on his machine. Just use Guid.NewGuid() once and store the value in a file. That will be lost when the drive goes bad, but that usually takes out your product as well.

like image 114
Hans Passant Avatar answered Nov 06 '22 05:11

Hans Passant


As other people have already pointed out, you are not supposed to get that value directly from the registry (which is probably why it doesn't work reliably among different versions of Windows).

A little searching led me to the Win32_OperatingSystem WMI class. Using this class, you can actually get the Windows serial number. It took me some searching and experimenting to get it right, but this is how to use it in C#.

Make sure you have the System.Management.dll reference in your project:

using System.Management;

...

ManagementObject os = new ManagementObject("Win32_OperatingSystem=@");
string serial = (string)os["SerialNumber"];

Using the [] operator, you can get any property in the class.

like image 22
Bart Friederichs Avatar answered Nov 06 '22 05:11

Bart Friederichs