3

I am trying to put together a list which shows all LogicalDisk instances in my Computer System and the drive letters they have been associated with. Coding is in C#.

The WMI classes Win32_LogicalDiskToPartition, Win32_DiskPartition and Win32_LogicalDisk appeared to be the right data sources to get that Job done:

  • Win32_LogicalDiskToPartition contains the property "Antecedent" which obviously links to a "DeviceId" property of class Win32_DiskPartition

  • and Win32_LogicalDiskToPartition contains the property "Dependent" which obviously links to a "DeviceId" property of class Win32_LogicalDisk

And here's my problem:

The Antecedent property of Win32_LogicalDiskToPartition returns a string value like:

\\\\HOME-PC\\root\\cimv2:Win32_DiskPartition.DeviceID=\"Disk #2, Partition #0\

but I need only Disk #2, Partition #0 to match it with the DeviceId property values of class Win32_DiskPartition.

Similar Problem with the Dependent property value.

Is there a way to obtain this substring (except by hard coded string parsing)?

I am afraid a query does not help because I do also need additional information about the logical disk and the associated disk Partition. I am aware that I have to cover Extended partitions with multiple drive letters - this can be done with the StartingAddress property of the Win32_LogicalDiskToPartition instance.

Jimi
  • 29,621
  • 8
  • 43
  • 61
PaulTheHacker
  • 179
  • 1
  • 8

1 Answers1

4

This type of enumeration is usually performed using System.Management ManagementObjectSearcher
This is one sequential path you can follow to retrieve information on drives in a system:

Enumerate the Disk Drives => For Each [DeviceID] =>
Enumerate Disk Drive To Partition => For Each [DeviceID]
Enumerate Logical Disk To Partition

Objects in each class have their associated properties:

Disk Drives (MSDN)
Partition (MSDN)
Logical Disk (MSDN)

using System.Management;

 //Define an initial scope for the following queries
 var scope = new ManagementScope(@"\\" + Environment.MachineName + @"\root\CIMV2");

 //Select all Disk Drives
 var query = new SelectQuery("SELECT * FROM Win32_DiskDrive");
 //Options => Timeout infinite to avoid timeouts and forward only for speed
 var options = new EnumerationOptions();
 options.Timeout = EnumerationOptions.InfiniteTimeout;
 options.Rewindable = false;
 options.ReturnImmediately = true;

 //New root Management Object
 var searcher = new ManagementObjectSearcher(scope, query, options);

 //Enumerate all Disk Drives
 foreach (ManagementObject moDisk in searcher.Get())
 {
    //Query the associated partitions of the current DeviceID
    string assocQuery = "Associators of {Win32_DiskDrive.DeviceID='" + 
                                         mobDisk.Properties["DeviceID"].Value.ToString() + "'}" +
                                         "where AssocClass=Win32_DiskDriveToDiskPartition";
    var assocPart = new ManagementObjectSearcher(assocQuery);
    assocPart.Options.Timeout = EnumerationOptions.InfiniteTimeout;

    //For each Disk Drive, query the associated partitions
    foreach (ManagementObject moPart in assocPart.Get())
    {
       Console.WriteLine("DeviceID: {0}  BootPartition: {1}", 
                         moPart.Properties["DeviceID"].Value.ToString(), 
                         moPart.Properties["BootPartition"].Value.ToString());

       //Query the associated logical disk of the current PartitionID
       string logDiskQuery = "Associators of {Win32_DiskPartition.DeviceID='" + 
                              moPart.Properties["DeviceID"].Value.ToString() + "'} " +
                              "where AssocClass=Win32_LogicalDiskToPartition";

       var logDisk = new ManagementObjectSearcher(logDiskQuery);
       logDisk.Options.Timeout = EnumerationOptions.InfiniteTimeout;

       //For each partition, query the Logical Drives
       foreach (var logDiskEnu in logDisk.Get())
       {
          Console.WriteLine("Volume Name: {0}  Serial Number: {1}  System Name: {2}",
                            logDiskEnu.Properties["VolumeName"].Value.ToString(),
                            logDiskEnu.Properties["VolumeSerialNumber"].Value.ToString(),
                            logDiskEnu.Properties["SystemName"].Value.ToString());
          Console.WriteLine("Description: {0}  DriveType: {1}  MediaType: {2}",
                            logDiskEnu.Properties["Description"].Value.ToString(),
                            logDiskEnu.Properties["DriveType"].Value.ToString(),
                            logDiskEnu.Properties["MediaType"].Value.ToString());
       }
    }
 }
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • 1
    Thank you for your effort with providing the code example. I get now (almost) all Information I want. Your Response made it evident that I should look into WMI scripting. – PaulTheHacker Jan 06 '18 at 16:32
  • very nice answer. thanks. but how can I get Partition FreeSpace? – Mahmood Jenami Jul 27 '21 at 09:23
  • @Mahmood Jenami Get the *bigger guy*: [Get the serial number of USB storage devices in .Net Core 2.1](https://stackoverflow.com/a/51806262/7444103). Per Partition, you have a `List` and for each `LogicalDisk` there's a `FreeSpace` property value (ulong). By chance, I've just modified that class. If you use it and find a bug, let me know. – Jimi Jul 27 '21 at 09:30