Iterating over SWbemPropertySet objects

com, wmi

Solution

First, the `ItemIndex` property only exist in some versions of the `Microsoft WMI Scripting Library` you can find more info about this topic on this article which I wrote some time ago ` Be careful when you import the Microsoft WMI Scripting Library` (The code uses Delphi but the same applies to any language using this Library).

Now to iterate over the elements of an `SWbemPropertySet` you must get a instance to the enumerator accessing the `_NewEnum` property which provides a method for enumerating a collection of variants using the `IEnumVARIANT` interface. This is done automagically by vbscript, but in others languages like Delphi or C++ must be done manually.

Try this Delphi sample

{$APPTYPE CONSOLE}    

uses
  SysUtils,
  ActiveX,
  ComObj,
  Variants,
  WbemScripting_TLB in 'WbemScripting_TLB.pas';

procedure ShowProperties(const WMINameSpace, WMIClass : string);
var
  WMIServices     : ISWbemServices;
  SWbemObjectSet  : ISWbemObjectSet;
  SObject         : ISWbemObject;
  LProperty       : ISWbemProperty;
  Enum, Enum2     : IEnumVariant;
  TempObj, TempObj2: OleVariant;
  Value           : Cardinal;
  SWbemPropertySet: ISWbemPropertySet;
begin
  WMIServices := CoSWbemLocator.Create.ConnectServer('.', WMINameSpace,'', '', '', '', 0, nil);
  SWbemObjectSet := WMIServices.ExecQuery(Format('Select * FROM %s',[WMIClass]), 'WQL', 0, nil);
  Enum := (SWbemObjectSet._NewEnum) as IEnumVariant;
  if (Enum.Next(1, TempObj, Value) = S_OK) then
  begin
    SObject     := IUnknown(TempObj) as ISWBemObject;
    SWbemPropertySet := SObject.Properties_;
    Enum2 := (SWbemPropertySet._NewEnum) as IEnumVariant;
    while (Enum2.Next(1, TempObj2, Value) = S_OK) do
    begin
      LProperty     := IUnknown(TempObj2) as ISWbemProperty;
      Writeln(LProperty.Name);
      TempObj2:=Unassigned;
    end;
    TempObj:=Unassigned;
  end;
end;

begin
 try
    CoInitialize(nil);
    try
      ShowProperties('root\cimv2','Win32_BaseBoard');
    finally
      CoUninitialize;
    end;
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.

I hope which you can translate this sample to the Go language.

Problem

A WQL query in WMI using the COM API returns a SWbemObjectSet. From this, we can use the ItemIndex method to iterate over all objects in the set, resulting in many SWbemObjects. These have a `Properties_` property, which returns a SWbemPropertySet. This object has a `Count` property, but no `ItemIndex` method, instead only an `Item` method, which takes a string name of the property to fetch. I'd like to iterate over all available properties, thus I don't have the name available. I've tried calling an `ItemIndex` method, but (as per the documentation) it does not exist on this object. There are many VBScript documents around that do something like `For Each prop in object.Properties_`, so I assume this is somehow possible. How can I find all properties?

Original source

Related problems