Click here to Skip to main content
15,888,461 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am trying to use WMI in C# to query the connected hard disk information. Basically, I am trying to convert a Powershell script to C#. However, I've hit a wall. In Powershell, I have a line:

$testdrv = Get-WmiObject -Class win32_volume -Filter "DriveLetter='$DriveLetter'"


Now, in C#, the following works:

var a = new ManagementObject("Win32_LogicalDisk.DeviceID='D:'");            
Console.WriteLine(a.GetPropertyValue("VolumeSerialNumber").ToString());


but this doesn't

var a = new ManagementObject("Win32_Volume.DriveLetter='D:'");            
Console.WriteLine(a.GetPropertyValue("DeviceID").ToString());


I get
Unhandled Exception: System.Management.ManagementException: Invalid object path
error.

What am I doing wrong?

What I have tried:

I have tried running Visual Studio in administrator mode, but that doesn't help. Is the only way to query Win32_Volume by building query strings and using ManagementObjectSearcher? Can't I do it using LINQ-style extension methods as can be done with Win32_LogicalDisk?
Posted
Updated 18-Feb-17 11:28am
Comments
Richard MacCutchan 18-Feb-17 11:30am    
Tried it here and received the same error.
Michael_Davies 18-Feb-17 12:25pm    
Have you tried it in WMICodeCreator (download from MS), you can select the Win32_LogicalDisk and see all the available data, run the code to see the output then generate script, VB or C# code.

The problem is you have to use a WQL query to get at the object and that's what I used in my tests.

The first example you provided works because, on the Win32_LogicalDisk class, the DeviceID property is a Key. See the documentation here[^].

On the Win32_Volume class, DriveLetter is not a Key field so you cannot use the path syntax that you're using to create the ManagementObject to get at it. You must use a WQL query instead with the ManagementObjectSearcher.
 
Share this answer
 
Comments
Sabyasachi Mukherjee 18-Feb-17 19:14pm    
Absolutely right. Thank you for the documentation link. That was very illuminating.
Richard MacCutchan 19-Feb-17 3:13am    
I have spent hours trying to understand the WMI documentation, with little success.
Looking at the documentation for these classes both properties seem the same. How do you tell whether it's a key or not?
Dave Kreskowiak 19-Feb-17 9:52am    
You have to look for the "Qualifiers" line just above the description for the property.
Richard MacCutchan 19-Feb-17 10:13am    
Thanks. Nice of Microsoft to make it so obvious.
Sabyasachi Mukherjee 19-Feb-17 4:45am    
This is from the documentation:

DeviceID
Data type: string
Access type: Read-only
Qualifiers: Key, Override ("DeviceId"), MappingStrings ("WMI")
Unique identifier of the logical disk from other devices on the system.
This property is inherited from CIM_LogicalDevice.


The "Key" qualifier shows that it can be queried using that qualifier and instead of ManagementObjectCollection, it will return one single ManagementObject.

"Unique identifier of the logical disk from other devices on the system."

The word unique is the key here. None of the other attributes are unique.
Here is the code generated using WMICodeCreator that works for your problem, you can take out a lot of the loop stuff as you know there is only one entry;

C#
using System;
using System.Management;
using System.Windows.Forms;

namespace WMISample
{
    public class MyWMIQuery
    {
        public static void Main()
        {
            try
            {
                ManagementObjectSearcher searcher = 
                    new ManagementObjectSearcher("root\\CIMV2", 
                    "SELECT * FROM Win32_Volume WHERE DriveLetter = 'D:'"); 

                foreach (ManagementObject queryObj in searcher.Get())
                {
                    Console.WriteLine("-----------------------------------");
                    Console.WriteLine("Win32_Volume instance");
                    Console.WriteLine("-----------------------------------");
                    Console.WriteLine("DeviceID: {0}", queryObj["DeviceID"]);
                }
            }
            catch (ManagementException e)
            {
                MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
            }
        }
    }
}
 
Share this answer
 
v4
Comments
Sabyasachi Mukherjee 18-Feb-17 13:00pm    
That's the ManagementObjectSearcher approach with SQL-like LINQ queries. I was hoping to solve it with extension method-like queries.
Michael_Davies 18-Feb-17 13:38pm    
Appreciate that, I've just looked at MS examples, copied them in VB and C# and tried both of them and they fail every time, tried variations on expressing D: as in VB it is enclosed with ", C# with ', no method of escaping the string changes the result and examining the management object shows the path correctly.

You might have to do it the other way.
It works fine on my machine. The problem with WMI is that not everything is required to be filled in by whatever components/drivers you have int the system. It's entirely possible that the Volume object doesn't have DriveLetter filled in.

You can check this by downloading WMI Explorer from WMI Explorer - Download Release File[^] and looking up the Win32_Volume class instances. Check to see if the volums objects have that information filled in. Simple.
 
Share this answer
 
Comments
Sabyasachi Mukherjee 18-Feb-17 12:59pm    
I actually tried it on three systems, all Windows 10 x64. Received the same error every time.

Thanks for pointing me towards the WMI Explorer tool. That might be of some help.
Michael_Davies 18-Feb-17 13:43pm    
Dave, I tried it on my PC and get the same errors, not sure what can be different, I do have a D:, tried C: too.
Dave Kreskowiak 18-Feb-17 14:56pm    
Like I said, there's nothing that says those instances have to be completely filled in. If the DriveLetter isn't filled in by the system there's nothing you can do about it.

The format on mine is "D:", no slashes, uppercase. If DriveLetter isn't filled your query will return null and that's why you're code fails. It's assuming that it will always return a good object. Calling ToString on null is a bad thing.

Dave Kreskowiak 18-Feb-17 15:00pm    
A quick way to see the objects is to open PowerShell and type:
Get-WmiObject Win32_Volume
Scroll back through the output and you can see everything in every Win32_Volume object, including the content of the DriveLetter property in each instance.
Michael_Davies 18-Feb-17 15:05pm    
Already did that to verify and DriveLetter D: exists and is filled in correctly.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900