Search code examples
c#.netwindowsusb-drivedongle

Get Unique info from Pendrive C#


I want to get infos like PID, VID and SerialNumber from a Pendrive in C#, dotnet 6.

Im gonna use this to generate a dongle key.

I want to search this infos from a specific (letter, name etc.) pendrive, can't be the first or anything else, because maybe the user will have more than once pendrive plugged.

I've tried to use ManagementObjectSearcher.

ManagementObjectSearcher searcher = new ManagementObjectSearcher($"SELECT * FROM Win32_PnPEntity WHERE (PNPClass = 'USB')

But I can't search by the letter, or by the name of the pendrive.

So I need a way to list the pendrives and choose the pendrive.


Solution

  • Right, so the annoying thing is that all the info you want actually come from 3 separate locations .

    1. The USB DeviceId comes from Win32_PnPEntity
    2. The drive Name/Model comes from Win32_DiskDrive
    3. The drive Letter (e.g. D:) comes from Win32_LogicalDisk

    These 3 queries are likely to give you the same number of results, representing the same drives, but giving you different pieces of the information:

    var entities = new ManagementObjectSearcher(
      $"select * from Win32_PnPEntity where Service='USBSTOR'").Get();
    var drives = new ManagementObjectSearcher(
      $"select * from Win32_DiskDrive where InterfaceType='USB'").Get();
    var disks = new ManagementObjectSearcher(
      $"select * from Win32_LogicalDisk where DriveType='{(int)System.IO.DriveType.Removable}'").Get();
    

    They are related, but their links are not the easiest to tease out. In this example, we will start from the Drive Letters, traversing the connections using ASSOCIATORS OF, through this path: LogicalDisk -> DiskPartition -> DiskDrive -> PnPEntity

    foreach (ManagementObject disk in disks)
    {
        var partition = new ManagementObjectSearcher(
            $"associators of {{{disk.Path}}} where ResultClass=Win32_DiskPartition")
            .Get().OfType<ManagementObject>().FirstOrDefault();
    
        var drive = new ManagementObjectSearcher(
            $"associators of {{{partition?.Path}}} where ResultClass=Win32_DiskDrive")
            .Get().OfType<ManagementObject>().FirstOrDefault();
    
        var entity = new ManagementObjectSearcher(
            $"associators of {{{drive?.Path}}} where ResultClass=Win32_PnPEntity")
            .Get().OfType<ManagementObject>().FirstOrDefault();
    
        Console.WriteLine($"""
            Letter='{disk["DeviceID"]}'
            Model='{drive?["Model"]}'
            Serial='{drive?["SerialNumber"]}'
            ID='{entity?["DeviceId"]}'
            -----
            """);
    }
    

    Which, on my system with one USB stick conected, returns:

    Letter='E:'
    Model='SanDisk 3.2Gen1 USB Device'
    Serial='123456789'
    ID='USBSTOR\DISK&VEN__USB&PROD__SANDISK_3.2GEN1&REV_1.00\123456789&0'
    

    Of course, you have the possibility of using an un-formatted drive. In which case, you will neither have a Partition nor a LogicalDrive. In which case, you may want to start from DiskDrive, and traverse the associations from there.