What is a good unique PC identifier?

Viewed 92479

I've been looking at the code in this tutorial, and I found that it uses My.Computer.Name to save settings that shouldn't roam between computers. It's entirely possible, however, for a user to have two identically named PCs. If they wanted to have the same username on each PC, for example, they may very well end up with two PCs named Username-PC.

What are some good methods of identifying different PCs? Do PCs have GUIDs associated with them, or should I look into pulling the serial number off of some hardware? I don't care if the identification persists through reinstallation of Windows.

(The tutorial I linked is in VB.Net, but I'm implementing it in C#)

13 Answers

In a managed network environment, the best, most reliable identifier might be the one you create, but there are some downsides.

Some (many?) manufacturers provide a utility that allows you to set an asset tag that is stored in the firmware. This might be a bootable utility, or it might run within Windows, or it might even be built into the firmware setup. This "tag" is an arbitrary text string that you can set to whatever you want, and then read it back using WMI and the Win32_SystemEnclosure class...

string[] selectedProperties = new string[] { "SMBIOSAssetTag" };
ObjectQuery enclosureQuery = new SelectQuery("Win32_SystemEnclosure", null, selectedProperties);

using (ManagementObjectSearcher enclosureSearcher = new ManagementObjectSearcher(enclosureQuery))
using (ManagementObjectCollection enclosureCollection = enclosureSearcher.Get())
{
    foreach (ManagementObject enclosure in enclosureCollection)
    {
        string assetTag = (string) enclosure.GetPropertyValue("SMBIOSAssetTag");
    }
}

Pros:

  • You can use whatever scheme you want (e.g. incorporating date, department, incrementing integers, GUIDs, etc.).
  • You can use one scheme for all machines regardless of their manufacturer, instead of having to handle manufacturer-specific schemes.
  • By allocating and tracking the identifiers yourself, you can guarantee that they are unique. Not relying on an identifier set by the manufacturer means there is no risk of duplicates within a manufacturer or between manufacturers.
  • The identifier is stored in the firmware — not on the hard drive — so it will survive reformatting, upgrades, etc. but also not be duplicated by backups/imaging/cloning.

Cons:

  • You need to actually set the asset tag; they'll all be blank until you do so.
  • Setting a machine's asset tag may require physical access and a reboot.
  • Asset tags are not write-once and could, therefore, be changed or erased.
    • Password-protected firmware should require that password before changing the tag, but that's not guaranteed.
  • By allocating and tracking the identifiers yourself, there's not only the overhead of...allocating and tracking the identifiers, but also the possibility that you'll introduce duplicates if you're not careful.
  • Using asset tags for this purpose requires that all machines support setting an asset tag and properly report it to WMI.

We use a combination of the ProcessorID from Win32_processor and the UUID from Win32_ComputerSystemProduct:

ManagementObjectCollection mbsList = null;
ManagementObjectSearcher mos = new ManagementObjectSearcher("Select ProcessorID From Win32_processor");
mbsList = mos.Get();
string processorId = string.Empty;
foreach (ManagementBaseObject mo in mbsList)
{
    processorId = mo["ProcessorID"] as string;
}

mos = new ManagementObjectSearcher("SELECT UUID FROM Win32_ComputerSystemProduct");
mbsList = mos.Get();
string systemId = string.Empty;
foreach (ManagementBaseObject mo in mbsList)
{
    systemId = mo["UUID"] as string;
}

var compIdStr = $"{processorId}{systemId}";

Previously, we used a combination: processor ID ("Select ProcessorID From Win32_processor") and the motherboard serial number ("SELECT SerialNumber FROM Win32_BaseBoard"), but then we found out that the serial number of the motherboard may not be filled in, or it may be filled in with uniform values:

  • To be filled by O.E.M.
  • None
  • Default string

Therefore, it is worth considering this situation.

Also keep in mind that the ProcessorID number may be the same on different computers.

There is a sample code with complete notes in this link for getting CPU and HD Drive ID: http://www.vcskicks.com/hardware_id.php

add this dll to refrences

 System.Management.dll

for CPU ID:

string cpuInfo = string.Empty;
ManagementClass mc = new ManagementClass("win32_processor");
ManagementObjectCollection moc = mc.GetInstances();

foreach (ManagementObject mo in moc)
{
     if (cpuInfo == "")
     {
          //Get only the first CPU's ID
          cpuInfo = mo.Properties["processorID"].Value.ToString();
          break;
     }
}
return cpuInfo;

and for Hard Drive ID (Volume Serial):

ManagementObject dsk = new ManagementObject(@"win32_logicaldisk.deviceid=""" + drive + @":""");
dsk.Get();
string volumeSerial = dsk["VolumeSerialNumber"].ToString();
Related