1

I am attempting to interface with a Primera Disc Duplicator using their provided PTRobot API. Their API returns information about the recorder drives in the robotic, but the crucial piece missing is the drive letter.

The info they do return is the Model Name, Firmware, and Serial Number.

I need to differentiate between multiple same drives in a unit, and the Serial Number is the only unique value provided.

I have found many examples going the other way around (using drive letter to get the model or serial), but none of them look able to be flipped around for my use.

Jonathon Hoaglin
  • 119
  • 1
  • 12
  • 1
    just loop thru all the drives and find their serial. Then cross match it with your result set. I wouldn't imagine you having more than 10 drives so performance isn't a concern at all – Steve Dec 07 '18 at 22:50
  • @Steve that makes sense, but how could I loop through the drives to get the serial? the DriveInfo.GetDrives() does not provide this. – Jonathon Hoaglin Dec 07 '18 at 23:04
  • Unless I'm misunderstanding something, you realize you can have more than one drive letter per physical drive, right? Drive letters are for partitions... – Rufus L Dec 07 '18 at 23:06
  • @RufusL These are recorder drives. CD/DVD-ROM. I realize these can technically be partitioned, but is not something that's normally done, or well supported in most OS – Jonathon Hoaglin Dec 10 '18 at 18:21

3 Answers3

2

You could write a routine to build a dictionary of drives hashed by serial number by checking each drive. Then you have the missing information needed to work with the PTRobot api.

Edit:

From a search for c# getting a serial number for a drive

Code from an example of how to get the hard drive serial number. UNtested as I no longer have a windows device

Following can help you:

searcher = new
ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");

int i = 0;
foreach(ManagementObject wmi_HD in searcher.Get())
{
 // get the hard drive from collection
// using index
HardDrive hd = (HardDrive)hdCollection[i];

// get the hardware serial no.
if (wmi_HD["SerialNumber"] == null)
 hd.SerialNo = "None";
else
 hd.SerialNo = wmi_HD["SerialNumber"].ToString();

++i;
}
Gauravsa
  • 6,330
  • 2
  • 21
  • 30
Keith John Hutchison
  • 4,955
  • 11
  • 46
  • 64
  • Could you provide any sample code or point me in the right direction for getting the serial numbers of the drives? DriveInfo.GetDrives() does not provide this info... – Jonathon Hoaglin Dec 10 '18 at 18:16
  • Added. I'll add some code to wrap it up later in the week. Could you please add in the code you've tried so far. I don't have easy access to a windows device. – Keith John Hutchison Dec 10 '18 at 22:39
  • This looks promising, but from what I can tell, Win32_PhysicalMedia does not provide a mapping to the drive letter...in fact, it appears to only return a serial number and Tag, such as "\\.\CDROM2", so I am not sure how I can relate that to the drive letter without performing yet another query and compare – Jonathon Hoaglin Dec 11 '18 at 16:10
2

It sounds like you could get the drive whose serial number matches the one you're searching for, then get it's partitions, and for each partition get it's drive letter from the logical drive.

For example:

using System.Collections.Generic
using System.Management;

public static List<string> GetDriveLettersForSerialNumber(string driveSerialNumber)
{        
    var results = new List<string>();
    if (driveSerialNumber == null) return results;

    var drive = new ManagementObjectSearcher(
        "SELECT DeviceID, SerialNumber, Partitions FROM Win32_DiskDrive").Get()
        .Cast<ManagementObject>()
        .FirstOrDefault(device =>
            device["SerialNumber"].ToString().Trim()
                .Equals(driveSerialNumber.Trim(), StringComparison.OrdinalIgnoreCase));

    if (drive == null) return results;

    var partitions = new ManagementObjectSearcher(
        $"ASSOCIATORS OF {{Win32_DiskDrive.DeviceID='{drive["DeviceID"]}'}} " +
        "WHERE AssocClass = Win32_DiskDriveToDiskPartition").Get();

    foreach (var partition in partitions)
    {
        var logicalDrives = new ManagementObjectSearcher(
            "ASSOCIATORS OF {{Win32_DiskPartition.DeviceID=" + 
            $"'{partition["DeviceID"]}'}} " +
            "WHERE AssocClass = Win32_LogicalDiskToPartition").Get();

        foreach (var logicalDrive in logicalDrives)
        {
            var volumes = new ManagementObjectSearcher(
                "SELECT Name FROM Win32_LogicalDisk WHERE " +
                $"Name='{logicalDrive["Name"]}'").Get().Cast<ManagementObject>();

            results.AddRange(volumes.Select(v => v["Name"].ToString()));
        }
    }

    return results;
}

For CDROM it seems much easier - both "Id" and "SerialNumber" are contained in the same object:

public static string GetDriveLetterForCDROMSerialNumber(string driveSerialNumber)
{
    return new ManagementObjectSearcher(
        "SELECT Id, SerialNumber FROM Win32_CDROMDrive").Get()
        .Cast<ManagementObject>()
        .Where(drive => drive.GetPropertyValue("SerialNumber").ToString().Trim()
            .Equals(driveSerialNumber.Trim(), StringComparison.OrdinalIgnoreCase))
        .Select(drive => drive.GetPropertyValue("Id").ToString())
        .FirstOrDefault() ?? "Unknown";
}
Rufus L
  • 36,127
  • 5
  • 30
  • 43
  • Unfortunately this only works for Hard Disk Drives, whereas I am trying to work with CD/DVD-ROM drives – Jonathon Hoaglin Dec 11 '18 at 16:14
  • Looks like you already found your answer, but since I just did the research I figured I'd update this one too. – Rufus L Dec 11 '18 at 17:17
  • Sure did, but I appreciate the help pointing me in that direction. I've accepted your answer as it is more complete and provides the extra method for Hard Drives – Jonathon Hoaglin Dec 13 '18 at 15:11
0

Thanks for the suggestions and pointing me to use WMI queries. It was just a matter of finding which one had the information I needed (Win32_CDROMDrive). Here is my working code:

public static string GetDriveLetter(string serialNum){
    if (serialNum != null)
    {
        var moc = new ManagementObjectSearcher("SELECT SerialNumber, Drive FROM Win32_CDROMDrive");

        foreach(var mo in moc.Get())
        {
            string driveSerial = (string)mo.GetPropertyValue("SerialNumber");
            if (driveSerial != null)
            {
                if (driveSerial.Trim().Equals(serialNum.Trim(), StringComparison.OrdinalIgnoreCase))
                {
                    return (string)mo.GetPropertyValue("Drive");
                }
            }
        }
    }
    return "Unknown";
}
Jonathon Hoaglin
  • 119
  • 1
  • 12
  • Nice! I was literally just about to post: `return new ManagementObjectSearcher("SELECT Id, SerialNumber FROM Win32_CDROMDrive").Get().Cast().Where(drive => drive.GetPropertyValue("SerialNumber").ToString().Trim().Equals(driveSerialNumber.Trim(), StringComparison.OrdinalIgnoreCase)).Select(drive => drive.GetPropertyValue("Id").ToString()).FirstOrDefault() ?? "Unknown";` – Rufus L Dec 11 '18 at 17:14