MatthewKing / DeviceId

A simple library providing functionality to generate a 'device ID' that can be used to uniquely identify a computer.
MIT License
729 stars 118 forks source link

System.Management equivelants? #24

Closed derekantrican closed 3 years ago

derekantrican commented 3 years ago

Previously, I've been using this to generate a unique ID (based on this SO answer):

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

    foreach (ManagementObject mo in moc)
    {
        cpuInfo = mo.Properties["processorID"].Value.ToString();
        break;
    }

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

    return cpuInfo + volumeSerial;
}

Running that on my computer gives me the ID BFEBFBFF000306C34408F4F4.

I figured the equivalent in the DeviceId library would be something like:

public static string GetUniquePCIdentifier()
{
    return new DeviceIdBuilder().AddProcessorId().AddSystemDriveSerialNumber().ToString();
}

But that gives me the ID nS9mx7meCmiAvsfZpyTLK_aQtGkgPljmld7nl4po35A (which isn't anywhere close to what I had above). Does the DeviceId library use one of the hashing formatters by default?

If possible, I'd like to migrate to this library and still keep generating the same IDs as I was before. Am I using the library correctly or is this just not possible?

derekantrican commented 3 years ago

Ah, after some digging I found that the ID is hashed by default. So doing this:

public static string GetUniquePCIdentifier()
{
    return new DeviceIdBuilder()
                        .AddProcessorId()
                        .AddSystemDriveSerialNumber()
                        .UseFormatter(new StringDeviceIdFormatter(new PlainTextDeviceIdComponentEncoder()))
                        .ToString();
}

Gives me BFEBFBFF000306C3.TW0N42H7550855222632 so I've at least got the processorid the same. Now to see if I can also get the SystemDriveSerialNumber the same...

MatthewKing commented 3 years ago

I was just typing up a reply but I see you've solved half of your issue already. Yep, you're on the right track. There's WmiDeviceIdComponent which will let you get the system drive serial number, but it'll give you results for each drive, not just C:\ as per your example. You can implement a custom IDeviceIdComponent that will do what you want, though. Your next issue will be that the StringDeviceIdFormatter concats the component values with a . rather than a space, but a custom IDeviceIdFormatter can be used to get the result you want. Give me a few minutes and I'll post an example.

MatthewKing commented 3 years ago

You can define a custom component as follows:

public class ExampleCustomComponent : IDeviceIdComponent
{
    public string Name { get; } = "ExampleCustomComponent";

    public string GetValue()
    {
        using var mo = new ManagementObject("win32_logicaldisk.deviceid=\"C:\"");
        return mo["VolumeSerialNumber"].ToString();
    }
}

And then a simple formatter that just concats the component values:

public class ExampleCustomFormatter : IDeviceIdFormatter
{
    public string GetDeviceId(IEnumerable<IDeviceIdComponent> components)
    {
        return string.Join(string.Empty, components.Select(x => x.GetValue()));
    }
}

And then you can tie it all together like so:

var deviceId = new DeviceIdBuilder()
    .AddProcessorId()
    .AddComponent(new ExampleCustomComponent())
    .UseFormatter(new ExampleCustomFormatter())
    .ToString();

This gives me the same result as your original code.

Hope this helps!

MatthewKing commented 3 years ago

Having said that, if all you want to do is replicate your original code, you'd have fewer dependencies (and LOC) if you just kept what you originally had. DeviceId will only be useful if you want to start constructing more complex device identifiers.

derekantrican commented 3 years ago

Perfect - I implemented your examples and that provided me exactly what I needed!

I plan on using this cross-platform so implementing the DeviceId library seems like a good way to go. I'm aware that processorId isn't available for OSX according to the readme, so I'll generate a different combination for OSX.

Thanks for all your help!