title: Find Windows Drive Letter of a removable disk from USB VID/PID
body: <p>This question has been asked before, and there is one answer that supposedly works <a href="https://stackoverflow.com/questions/17371578/find-usb-drive-letter-from-vid-pid-needed-for-xp-and-higher">here</a>. But I've tried it out and it does not work for me. </p>
  
  <p>The issue is that the PNPDeviceID returned by the Query on Win32_DiskDrive and that returned by the "Device" class are different. For example in my case the Query returns something like - PNPDeviceID: <strong>USBSTOR\DISK&amp;VEN_ABCD&amp;PROD_1234&amp;REV_0001\8&amp;2C3C9390&amp;0</strong> while the Device class returns the actual VID/PID combination --> <strong>USB\VID_4568&amp;PID_QWER&amp;MI_00\7&amp;15b8d7f0&amp;3&amp;0000</strong>.</p>
  
  <p>So the SELECT query on Win32_DiskDrive always fails.</p>
  
  <p>Main Code:</p>
  
  <pre><code>    var usbDevices = GetUSBDevices();
  
      //Enumerate the USB devices to see if any have specific VID/PID
      foreach (var usbDevice in usbDevices)
      {
          if (usbDevice.DeviceID.Contains("ABCD") &amp;&amp; usbDevice.DeviceID.Contains("1234"))
          {
              foreach (string name in usbDevice.GetDiskNames())
              {
                  //Open dialog to show file names
                  Debug.WriteLine(name);
              }
          }                   
      }
  </code></pre>
  
  <p>USBDeviceInfo Class</p>
  
  <pre><code>class USBDeviceInfo
  {
      public USBDeviceInfo(string deviceID, string pnpDeviceID, string description)
      {
          this.DeviceID = deviceID;
          this.PnpDeviceID = pnpDeviceID;
          this.Description = description;
      }
  
      public string DeviceID { get; private set; }
      public string PnpDeviceID { get; private set; }
      public string Description { get; private set; }
  
      public IEnumerable&lt;string&gt; GetDiskNames()
      {
          using (Device device = Device.Get(PnpDeviceID))
          {
              // get children devices
              foreach (string childDeviceId in device.ChildrenPnpDeviceIds)
              {
                  // get the drive object that correspond to this id (escape the id)
                  Debug.WriteLine(childDeviceId.Replace(@"\", @"\\") );
                  foreach (ManagementObject drive in new ManagementObjectSearcher("SELECT DeviceID FROM Win32_DiskDrive WHERE PNPDeviceID='" + childDeviceId.Replace(@"\", @"\\") + "'").Get())
                  {
  
                      foreach (PropertyData usb in drive.Properties){
                          if (usb.Value != null &amp;&amp; usb.Value.ToString() != "")
                          {
                              Debug.Write(usb.Name + "=");
                              Debug.Write(usb.Value + "\r\n");
                          }
                      }
  
                      // associate physical disks with partitions
                      foreach (ManagementObject partition in new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + drive["DeviceID"] + "'} WHERE AssocClass=Win32_DiskDriveToDiskPartition").Get())
                      {
                          // associate partitions with logical disks (drive letter volumes)
                          foreach (ManagementObject disk in new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" + partition["DeviceID"] + "'} WHERE AssocClass=Win32_LogicalDiskToPartition").Get())
                          {
                              yield return (string)disk["DeviceID"];
                          }
                      }
                  }
              }
          }
      }
  </code></pre>
  
  <p>As a side note, I am able to get the Query using "Model" property pass and then find the drive letter, as explained <a href="http://www.codeproject.com/Articles/63878/Enumerate-and-Auto-Detect-USB-Drives" rel="nofollow noreferrer">here</a>. But I'm looking for a solution that can tie VID/PID to the drive letter.</p>