Get information about the USB device from Win32_DiskDrive and Win32_LogicalDisk I want to know the information about a USB device from Win32_DiskDrive and Win32_LogicalDisk.

I use the following code:

private void Add(string letter) // letter is a logical name of the USB device, e.g. "G:\\"
{
  foreach (var drive in new ManagementObjectSearcher("SELECT DeviceID, SerialNumber, Partitions FROM Win32_DiskDrive WHERE InterfaceType='USB'").Get())
  {
    var partition = new ManagementObjectSearcher(string.Format("ASSOCIATORS OF {{Win32_DiskDrive.DeviceID='{0}'}} WHERE AssocClass = Win32_DiskDriveToDiskPartition", drive["DeviceID"])).First();

    if (partition != null)
    {
      var logical = new ManagementObjectSearcher(string.Format("ASSOCIATORS OF {{Win32_DiskPartition.DeviceID='{0}'}} WHERE AssocClass = Win32_LogicalDiskToPartition", partition["DeviceID"])).First();

      if (logical != null)
      {
        var volume = new ManagementObjectSearcher(string.Format("SELECT Name, FreeSpace FROM Win32_LogicalDisk WHERE Name='{0}'", logical["Name"])).First();

        string name = (string)volume["Name"];
        string serialNumber = (string)drive["SerialNumber"];
        ulong freeSpace = (ulong)volume["FreeSpace"];
        break;
      }
    }
  }
}

  public static class WmiExtensions
  {
    // Fetch the first item from the search result collection.
        public static ManagementObject First(this ManagementObjectSearcher searcher)
        {
          ManagementObject result = null;
          foreach (ManagementObject item in searcher.Get())
          {
            result = item;
            break;
          }
          return result;
        }
      }
    }


Is there a way to make it shorter and more elegant?
1: Add() doesn't appear to access any class members, so it can be declared static. But then again, it looks like it wants to return the name, serial number, and free space. Make it do so - create a quick container type

public sealed class DriveInfo
{
    public DriveInfo(string name, string serialNumber, ulong freeSpace)
    {
        this.Name = name;
        this.SerialNumber = serialNumber;
        this.FreeSpace = freeSpace;
    }

    public string Name { get; }

    public string SerialNumber { get; }

    public ulong FreeSpace { get; }
}


usage becomes:

return new DriveInfo(
    (string)volume["Name"],
    (string)drive["SerialNumber"],
    (ulong)volume["FreeSpace"]);


2: The parameter letter is completely unused in the method and the comment is a lie. Remove the parameter and comment or use the parameter appropriately.

3: Invert your if blocks, to prevent so much indention as well as keeping the tests looking cleaner (equality vs. non-equality):

if (partition == null) continue;
...
if (logical == null) continue;


4: Both ManagementObject and ManagementObjectSearcher descend from Component, which implements IDisposable. Their lifetime should therefore be wrapped in a using statement:

using (var searcher = new ManagementObjectSearcher($"ASSOCIATORS OF {{Win32_DiskDrive.DeviceID='{drive["DeviceID"]}'}} WHERE AssocClass = Win32_DiskDriveToDiskPartition"))
using (var partition = searcher.First())
{
}


5: Your extension method's body can be replaced by a quick one-liner:

return searcher.Get().Cast&lt;ManagementObject&gt;().FirstOrDefault();