For my application, I need to determine the best drive / partition. The requirements are as follows:
- 20GB or more free
- The drive must be fixed (as in, it mustn't be a detachable USB Drive, etc)
- The underlying disk must have a BytesPerSector value of 512 OR 4096.
Points 1 and 2 can be easily parsed with the DriveInfo class in C#. However I get stuck at point 3...
Getting the BytesPerSector value from the Win32_DiskDrive class is done with an ManagementObjectSearch. However I can't parse a specific drive.
For example. Let's say I want to find the BytesPerSector value of C:\
// Specify the drive letter (change it to the desired letter)
string driveLetter = "C:";
// Get DriveInfo for the specified drive letter
DriveInfo driveInfo = new(driveLetter);
// Check if the drive is ready (mounted)
Assert.IsTrue(driveInfo.IsReady, $"Expected drive to be ready but was not");
Console.WriteLine("Format: " + driveInfo.Name);
// Get the disk drive associated with the partition
var diskDrive = new System.Management.ManagementObjectSearcher(
"SELECT * FROM Win32_DiskDrive WHERE DeviceID = '" + driveInfo.Name + "'"
).Get().OfType<System.Management.ManagementObject>().FirstOrDefault();
// Check if the disk drive is found
Assert.IsNotNull(diskDrive, $"Expected disk drive to be found but was null");
// Get the BytesPerSector information
uint bytesPerSector = Convert.ToUInt32(diskDrive["BytesPerSector"]);
// Print out the BytesPerSector information
Assert.IsTrue(bytesPerSector == 512 || bytesPerSector == 4096, $"Expected 512 or 4096 but was {bytesPerSector}");
This fails with the exception:
Message: Test method TestSectorInfo threw exception: System.Management.ManagementException: Invalid query
Some digging around led me to the discovery that the DeviceID expected by Win32_DiskDrive looks like so:
\\.\PHYSICALDRIVE0
\\.\PHYSICALDRIVE1
etc.
But I can't know for certain whether C:\ is on DRIVE0 or DRIVE1 so I first have to somehow translate the partition letter to its underlying disk... How do I even do that?
I've also tried passing the letter of the volume to the query which doesn't work, and looked for any c# classes that might do what I need to no avail.
The issue you’re encountering is due to the fact that the DeviceID for the
Win32_DiskDriveWMI class is not the same as the drive letter. The DeviceID is a unique identifier for the physical drive, not the partition or volume.To get the
BytesPerSectorfor a specific drive letter, you’ll need to go through several steps:Get the Win32_Volume instance that corresponds to the drive letter. Get the associated
Win32_DiskPartitioninstance. Get the associatedWin32_DiskDriveinstance. Here’s how you can do it:This code first gets the
Win32_Volumeinstance for the specified drive letter. It then uses the ASSOCIATORS OF WQL query to get the associatedWin32_DiskPartitionandWin32_DiskDriveinstances. The BytesPerSector information is then retrieved from theWin32_DiskDriveinstance.You might need to run your application with administrative privileges to access some WMI classes. Also, remember to add a reference to the
System.Managementnamespace and theSystem.Managementassembly to your project.