Enumerating WMI

Enumeration is the act of moving through a set of objects and possibly modifying each object as you do so. For example, you can enumerate through a set of Win32_DiskDrive objects to find a particular serial number. Note that although you can enumerate any object, WMI only returns objects to which you have security access.

Enumerations of large data sets can require a large amount of resources and degrade performance. For more information, see Improving Enumeration Performance. You also can request data with a more specific query. For more information, see Querying WMI.

The following sections are discussed in this topic:

Enumerating WMI Using PowerShell

If you do not know the object path for a specific instance, or you want to retrieve all the instances for a specific class, use Get-WmiObject, with the name of the class in the -class parameter. If you want to use a query, you can use the -query parameter.

The following procedure describes how to enumerate the instances of a class using PowerShell.

To enumerate the instances of a class using PowerShell

  1. Enumerate the instances with a call to Get-WmiObject cmdlet.

    Get-WmiObject returns a collection of one or more WMI objects, through which you can enumerate. For more information, see Accessing a Collection.

    If you wish to retrieve a WMI class instance in another namespace or on a different computer, specify the computer and namespace in the -computer and -namespace parameters, respectively. For more information, see Creating a WMI Script. This only works if you have the appropriate access privileges. For more information, see Maintaining WMI Security and Executing Privileged Operations.

  2. Retrieve any individual instances you wish using the collection's members.

The following code example retrieves an PowerShell collection and then displays the size property for all instances of logical drives on the local computer.

$objCol = get-wmiobject -class "Win32_LogicalDisk"

# Or, alternately
#$objCol = get-wmiobject -Query "SELECT * FROM Win32_LogicalDisk"

foreach ($Drive in $objCol)
{
    if ($Drive.size -ne $null)
    { "Drive " + $Drive.deviceID + " contains " + $Drive.size + " bytes" }
    else
    { "Drive " + $Drive.deviceID + " is not available." }
}

Enumerating WMI Using C# (Microsoft.Management.Infrastructure)

  1. Add a reference to the Microsoft.Management.Infrastructure reference assembly. (This assembly ships as part of the Windows Software Development Kit (SDK) for Windows 8.)
  2. Add a using statement for the Microsoft.Management.Infrastructure namespace.
    using Microsoft.Management.Infrastructure;
  1. Instantiate a CimSession object. The following snippet uses the standard "localhost" value for the CimSession.Create method.
    CimSession cimSession = CimSession.Create("localhost");
  1. Call the CimSession.QueryInstances method passing the desired CIM namespace and WQL to use. The following snippet will return two instances representing two standard Windows processes where the handle property (representing a process ID, or PID) has a value of either 0 or 4.
    IEnumerable<CimInstance> queryInstances =     
      cimSession.QueryInstances(@"root\cimv2", 
                                "WQL", 
                                @"select name from win32_process where handle = 0 or handle = 4");
  1. Loop through the returned CimInstance objects.
    foreach (CimInstance cimInstance in enumeratedInstances)
    { 
      Console.WriteLine("Process name: {0}", cimInstance.CimInstanceProperties["Name"].Value);  
    }

The following code sample enumerates all instances of the Win32_Process class (which represents active processes) on the local machine, and prints the name of each process.

Note

In a real application you would define as parameters the computer name ("localhost") and CIM namespace ("root\cimv2"). For purposes of simplicity, these have been hardcoded in this example.

 

using System;
using System.Collections.Generic;
using Microsoft.Management.Infrastructure;

public partial class MI
{
    static void PrintCimInstance(CimInstance cimInstance)
    {
        Console.ForegroundColor = ConsoleColor.Blue;
        Console.WriteLine("{0} properties", cimInstance.CimSystemProperties.ClassName);
        Console.ResetColor();

        Console.WriteLine(String.Format("{0,-5}{1,-30}{2,-15}{3,-10}", 
                                        "Key?", "Property", "Type", "Value"));

        foreach (var enumeratedProperty in cimInstance.CimInstanceProperties)
        {
            bool isKey = ((enumeratedProperty.Flags & CimFlags.Key) == CimFlags.Key);

            if (enumeratedProperty.Value != null)
            {
                Console.WriteLine(
                    "{0,-5}{1,-30}{2,-15}{3,-10}",
                    isKey == true ? "Y" : string.Empty,
                    enumeratedProperty.Name,
                    enumeratedProperty.CimType,
                    enumeratedProperty.Value);
            }
        }
        Console.WriteLine();
    }

    public static void QueryInstance(string query)
    {
        try
        {
            CimSession cimSession = CimSession.Create("localhost");

            IEnumerable<CimInstance> queryInstances = 
              cimSession.QueryInstances(@"root\cimv2", "WQL", query);
            foreach (CimInstance cimInstance in queryInstances)
            {
                //Use the current instance. This example prints the instance. 
                PrintCimInstance(cimInstance);
            }
        }
         catch (CimException ex) 
        { 
            // Handle the exception as appropriate.
            // This example prints the message.
            Console.WriteLine(ex.Message); 
        }
    }
}

using System;

namespace MIClientManaged
{
    class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                Console.Write(&quot;Enter WQL (x = Quit): &quot;);
                string query = Console.ReadLine().ToUpper();
                if (query.CompareTo(&quot;X&quot;) == 0) break;
                MI.QueryInstance(query);
            }
        }
    }
}

Enumerating WMI Using C# (System.Management)

If you do not know the object path for a specific instance, or you want to retrieve all the instances for a specific class, use the ManagementClass object to retrieve a ManagementObjectCollection that contains all instances of a given class in the WMI namespace. Alternately, you can query WMI through a ManagementObjectSearcher to obtain the same set of objects.

Note

System.Management was the original .NET namespace used to access WMI; however, the APIs in this namespace generally are slower and do not scale as well relative to their more modern Microsoft.Management.Infrastructure counterparts.

 

The following procedure describes how to enumerate the instances of a class using C#.

To enumerate the instances of a class using C#

  1. Enumerate the instances with a call to ManagementClass.GetInstances.

    The GetInstances method returns a collection, or set, of objects through which you can enumerate. For more information, see Accessing a Collection. The returned collection is actually an ManagementObjectCollection object, so any of the methods of that object can be called.

    If you wish to retrieve a WMI class instance in another namespace or on a different computer, specify the computer and namespace in the path parameter. For more information, see Creating a WMI Script. This only works if you have the appropriate access privileges. For more information, see Maintaining WMI Security and Executing Privileged Operations.

  2. Retrieve any individual instances you wish using the collection's members.

The following code example retrieves an C# collection and then displays the size property for all instances of logical drives on the local computer.

using System.Management;
...

ManagementClass mc = new ManagementClass("Win32_LogicalDisk");
ManagementObjectCollection objCol = mc.GetInstances();

//or, alternately
//ManagementObjectSearcher mgmtObjSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_LogicalDisk");
//ManagementObjectCollection objCol = mgmtObjSearcher.Get();

if (objCol.Count != 0)
{
   foreach (ManagementObject Drive in objCol)
   {
      if (Drive["size"] != null)
      {
         Console.WriteLine("Drive {0} contains {1} bytes.", Drive["deviceID"], Drive["size"]);
      }
      else
      {
         Console.WriteLine("Drive {0} is not available.", Drive["deviceID"]);
      }
   }
}
Console.ReadLine();

Enumerating WMI Using VBScript

If you do not know the object path for a specific instance, or you want to retrieve all the instances for a specific class, use the SWbemServices.InstancesOf method to return an SWbemObjectSet enumeration of all the instances of a class. Alternatively you can query WMI through SWbemServices.ExecQuery to obtain the same set of objects.

The following procedure describes how to enumerate the instances of a class using VBScript.

To enumerate the instances of a class using VBScript

  1. Enumerate the instances with a call to the SWbemServices.InstancesOf method.

    The InstancesOf method returns a collection, or set, of objects through which you can enumerate. For more information, see Accessing a Collection. The returned collection is actually an SWbemObjectSet object, so any of the methods of that object can be called.

    If you wish to retrieve a WMI class instance in another namespace or on a different computer, specify the computer and namespace in the moniker. For more information, see Creating a WMI Script. This only works if you have the appropriate access privileges. For more information, see Maintaining WMI Security and Executing Privileged Operations.

  2. Retrieve any individual instances you wish using the collections methods.

The following code example retrieves an SWbemServices object and then executes the InstancesOf method to display the size property for all instances of logical drives on the local computer.

Set objCol = GetObject("WinMgmts:").InstancesOf("Win32_LogicalDisk")
For Each Drive In objCol
    If Not IsNull(Drive.Size) Then    
       WScript.Echo ("Drive " & Drive.deviceid & " contains " & Drive.Size & " bytes")
    Else
       WScript.Echo ("Drive " & Drive.deviceid & " is not available.")
    End If
Next

Enumerating WMI Using C++

In addition to performing basic enumeration, you can set several flags and properties to increase the performance of your enumeration. For more information, see Improving Enumeration Performance.

To enumerate an object set in WMI

  1. Create an IEnumWbemClassObject interface describing the set of objects you wish to enumerate.

    An IEnumWbemClassObject object contains a list describing a set of WMI objects. You can use the IEnumWbemClassObject methods to enumerate forwards, skip objects, begin at the beginning, and copy the enumerator. The following table lists the methods use to create enumerators for different types of WMI objects.

    Object Method
    Class
    IWbemServices::CreateClassEnum
    [IWbemServices::CreateClassEnumAsync](/windows/desktop/api/WbemCli/nf-wbemcli-iwbemservices-createclassenumasync)
    Instance
    IWbemServices::CreateInstanceEnum
    [IWbemServices::CreateInstanceEnumAsync](/windows/desktop/api/WbemCli/nf-wbemcli-iwbemservices-createinstanceenumasync)
    Query result
    IWbemServices::ExecQuery
    [IWbemServices::ExecQueryAsync](/windows/desktop/api/WbemCli/nf-wbemcli-iwbemservices-execqueryasync)
    Event notification
    IWbemServices::ExecNotificationQuery
    [IWbemServices::ExecNotificationQueryAsync](/windows/desktop/api/WbemCli/nf-wbemcli-iwbemservices-execnotificationqueryasync)

     

  2. Traverse through the returned enumeration using multiple calls to IEnumWbemClassObject::Next or IEnumWbemClassObject::NextAsync.

For more information, see Manipulating Class and Instance Information.