Storage: C # Equivalent to PowerShell Command

What is the C # equivalent for this PowerShell command?

PS C:\WINDOWS\system32> gwmi win32_DiskDrive | %{gwmi -query "ASSOCIATORS OF {$($_.__RELPATH)} where resultclass = Win32_PnpEntity" | %{gwmi -query "ASSOCIATORS OF {$($_.__RELPATH)}"}} | fl __CLASS,__RELPATH

      

The result of the specified command:

...
__CLASS   : Win32_SystemDriver
__RELPATH : Win32_SystemDriver.Name="disk"

__CLASS   : Win32_ComputerSystem
__RELPATH : Win32_ComputerSystem.Name="JMR-ENG-SARAH"

__CLASS   : Win32_IDEController
__RELPATH : Win32_IDEController.DeviceID="PCI\\VEN_8086&DEV_8C82&SUBSYS_79171462&REV_00\\3&11583659&0&FA"

__CLASS   : CIM_DataFile
__RELPATH : CIM_DataFile.Name="c:\\windows\\system32\\drivers\\disk.sys"

__CLASS   : Win32_DiskDrive
__RELPATH : Win32_DiskDrive.DeviceID="\\\\.\\PHYSICALDRIVE1"


__CLASS   : Win32_SCSIController
__RELPATH : Win32_SCSIController.DeviceID="PCI\\VEN_144D&DEV_A804&SUBSYS_A801144D&REV_00\\6&381D8F6A&0&00080008"

__CLASS   : Win32_SystemDriver
__RELPATH : Win32_SystemDriver.Name="disk"

__CLASS   : Win32_ComputerSystem
__RELPATH : Win32_ComputerSystem.Name="JMR-ENG-SARAH"

__CLASS   : CIM_DataFile
__RELPATH : CIM_DataFile.Name="c:\\windows\\system32\\drivers\\disk.sys"

__CLASS   : Win32_DiskDrive
__RELPATH : Win32_DiskDrive.DeviceID="\\\\.\\PHYSICALDRIVE2"
...

      

I think I don't understand how the PowerShell command works. I know some of the translation.

            ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");

foreach (ManagementObject wmi_HD in searcher.Get())
{
    String driveDeviceId = wmi_HD["DeviceID"].ToString();
}

      

The above code is part of gwmi win32_DiskDrive

. Which property I need to extract is open to discussion. I know there is a list of properties to return properties.

I have another piece of code where I am getting drive letters associated with physical drives that use a ASSOCIATORS OF

gwmi request . So the answer should be similar to:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;

String query2 = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + driveDeviceId + "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition";
foreach (ManagementObject partition in new ManagementObjectSearcher(query2).Get())
{
    foreach (ManagementObject disk in new ManagementObjectSearcher(
                "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='"
                    + partition["DeviceID"]
                    + "'} WHERE AssocClass = Win32_LogicalDiskToPartition").Get())
    {
        String diskMount = disk["Name"].ToString();
    }
}

      

|

is just an inline for-loop where wmi's inner query will use the result of another loop element. The query I need is a little more complex with double set |

and uses double set {$($_.__RELPATH)}

.

How do I write C # code for the desired PowerShell script at the top?

+3


source to share


1 answer


Note 1: I struggled and researched for a long time and finally understood things a little better. I was able to answer my own question myself. I am posting an answer here along with an explanation in the hope of educating others. At least for me, WMI is quite difficult to understand, especially with the intricacies.

  1. Great update at the end, check it out.

My big break came with faith or not this Microsoft webpage along with ScryptingGuy and this SO article on escaping dollar signs in a WMI query filter.

I also realized that the filter at the end is applied to queries. The source code equivalent should have pulled this property only, e.g .:

String propDiskRelpaths = wmiDisks["__RELPATH"].ToString();

      

I found out that the brackets are required by WMI and indicate the value. The dollar sign simply indicates the result of the outer query. Connotation ($_.__RELPATH)

is a fancy way of saying the __RELPATH property of a previous request.

The request first lists all disks on the system. The second query then enumerates all PNP objects for the disk (there is only one), while the last query gets all the path associations (driver hierarchy) for the disk. Each request is drilled down one level.

In case anyone is interested, here is a PowerScript breakdown that then led me to the code below. Here I am listing only one drive, but at the moment I have 6 drives in my system, ranging from 0 to 5. Below is shown physical drive 3.

PS C:\WINDOWS\system32> gwmi win32_DiskDrive | fl __CLASS,__RELPATH

....
__CLASS   : Win32_DiskDrive
__RELPATH : Win32_DiskDrive.DeviceID="\\\\.\\PHYSICALDRIVE3"

      

Here is the second command that gives the PNP objects for the disk. In this case, I selected my C: drive 0, not the M.2 card, drive 3 to give an example here. The real code is in a for loop and I get all the disks.

PS C:\WINDOWS\system32> gwmi -query 'ASSOCIATORS OF {Win32_DiskDrive.DeviceID="\\\\.\\PHYSICALDRIVE0"} where resultclass = Win32_PnpEntity' | fl __CLASS,__RELPATH

__CLASS   : Win32_PnPEntity
__RELPATH : Win32_PnPEntity.DeviceID="SCSI\\DISK&VEN_NVME&PROD_SAMSUNG_SSD_960\\7&335357E&0&000000"

      



Last command and output:

PS C:\WINDOWS\system32> gwmi -query 'ASSOCIATORS OF {Win32_PnPEntity.DeviceID="SCSI\\DISK&VEN_NVME&PROD_SAMSUNG_SSD_960\\7&335357E&0&000000"}' | fl __CLASS,__RELPATH


__CLASS   : Win32_SCSIController
__RELPATH : Win32_SCSIController.DeviceID="PCI\\VEN_144D&DEV_A804&SUBSYS_A801144D&REV_00\\6&381D8F6A&0&00080008"

__CLASS   : Win32_SystemDriver
__RELPATH : Win32_SystemDriver.Name="disk"

__CLASS   : Win32_ComputerSystem
__RELPATH : Win32_ComputerSystem.Name="JMR-ENG-SARAH"

__CLASS   : CIM_DataFile
__RELPATH : CIM_DataFile.Name="c:\\windows\\system32\\drivers\\disk.sys"

__CLASS   : Win32_DiskDrive
__RELPATH : Win32_DiskDrive.DeviceID="\\\\.\\PHYSICALDRIVE0"

      

As you can see, my M.2 card appears as a SCSI device and not as an NVMe PCIe card which it actually is. I did research and this was expected because the Microsoft driver StorNVMe.sys

implements NVMe as IOCTL_SCSI_*

translated into commands IOCTL_NVME_*

at the device driver level. This was true in Windows Vista, and apparently still remains in Windows 10.

PS C:\WINDOWS\system32> gwmi -query 'ASSOCIATORS OF {Win32_PnPEntity.DeviceID="SCSI\\DISK&VEN_NVME&PROD_SAMSUNG_SSD_960\\7&335357E&0&000000"}' | fl __CLASS,__RELPATH


__CLASS   : Win32_SCSIController
__RELPATH : Win32_SCSIController.DeviceID="PCI\\VEN_144D&DEV_A804&SUBSYS_A801144D&REV_00\\6&381D8F6A&0&00080008"

__CLASS   : Win32_SystemDriver
__RELPATH : Win32_SystemDriver.Name="disk"

__CLASS   : Win32_ComputerSystem
__RELPATH : Win32_ComputerSystem.Name="JMR-ENG-SARAH"

__CLASS   : CIM_DataFile
__RELPATH : CIM_DataFile.Name="c:\\windows\\system32\\drivers\\disk.sys"

__CLASS   : Win32_DiskDrive
__RELPATH : Win32_DiskDrive.DeviceID="\\\\.\\PHYSICALDRIVE0"

      

Here is the final code I wanted. I must add that for IDE based drives I can enumerate the IDE class and get the supported modes for that drive (IDE, AHCI, RAID, etc.).

Hope this explanation is clear. Let me know if you need more explanation. Oh, the code below assumes VS2017 or higher.

using System;
using System.Collections.Generic;
using System.Management;
using SiloStor.Tools;

internal static void EnumerateClassPaths()
{
    try
    {
        // Enumerate all disk drives.
        ManagementObjectSearcher oSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
        foreach (ManagementObject wmiDisks in oSearcher.Get())
        {
            // Get the properties needed.
            String propDiskRelpaths = wmiDisks["__RELPATH"].ToString();

            // 
            String wmiQuery1 = "ASSOCIATORS OF {" + propDiskRelpaths + "} WHERE ResultClass = Win32_PnpEntity";
            foreach (ManagementObject wmiPnp in new ManagementObjectSearcher(wmiQuery1).Get())
            {
                // Get the properties needed.
                String propPnpRelpaths = wmiPnp["__RELPATH"].ToString();

                // 
                String wmiQuery2 = "ASSOCIATORS OF {" + propPnpRelpaths + "}";
                foreach (ManagementObject wmiDrivers in new ManagementObjectSearcher(wmiQuery2).Get())
                {
                    String driverClass = wmiDrivers["__CLASS"].ToString();
                    String driverRelpath = wmiDrivers["__RELPATH"].ToString();
                    Console.WriteLine($"__CLASS   : {driverClass}");
                    Console.WriteLine($"__RELPATH : {driverRelpath}");
                    Console.WriteLine("");
                }
            }
        }
    }

    catch (Exception ex)
    {
        // Log the error.
        Errors.LogError(ex);
    }
}

      

UPDATE:

Yesterday (Aug 9, 2017) I found a link at Microsoft WMI Code Creator

v1.0. I don't get paid by Microsoft, and I don't think this tool is a "must have" for WMI to work, but it's actually pretty good and isn't advertised at all.

WMI Code Creator

, for which source code for the application, generates C # and VB.Net source code for WMI queries. Unfortunately, WMI queries are limited to basic commands, but still very useful. Another useful thing is that the tool shows the classes that the user can request, which is also very useful. Unfortunately there are no ASSOCIATORS OF

or concatenated queries, but there are many other useful features. Check it out and hope it helps.

+5


source







All Articles