Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What do Get-WMIObject \ Get-CimInstance actually do?

I have developing a new WMI instance provider and I am having a bit of trouble. I am able to register my provider successfully using regsvr32.exe. The regsvr32 application calls my implementation of DllRegisterServer and creates the following registry keys and values:

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{00000001-0000-0000-0000-00000000000F}                : (default)      = "WMI Provider"
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{00000001-0000-0000-0000-00000000000F}\InprocServer32 : (default)      = "C:\MyWmiProvider.dll"
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{00000001-0000-0000-0000-00000000000F}\InprocServer32 : ThreadingModel = Neutral
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{00000001-0000-0000-0000-00000000000F}\Version        : (default)      = 1.0.0

(Where {00000001-0000-0000-0000-00000000000F} is just a test Class ID (CLSID))

I am also able to successfully add my WMI class definitions defined in my Managed Object Format (MOF) file by using mofcomp.exe. I am able to verify that my definitions are present in the WMI repository by running the following command:

Get-CimClass -Namespace "root/MyNamespace" | Where-Object CimClassName -like "MyClass_*"

Here is an example of what my MOF file looks like:

#pragma namespace("\\\\.\\root\\MyNamespace")
#pragma autorecover

instance of __Win32Provider as $P
{
    Name = "MyWmiProvider";
    ClsId = "{00000001-0000-0000-0000-00000000000F}";
};

instance of __InstanceProviderRegistration
{
    Provider = $P;
    SupportsGet = FALSE;
    SupportsPut = FALSE;
    SupportsDelete = FALSE;
    SupportsEnumeration = TRUE;
};

[dynamic, provider("MyWmiProvider")]
class MyClass_ExampleName
{
    [key]
    uint14 Id;

    [PropertyContext("Name")]
    String Name;
};

Now, if I run the following:

Get-CimInstance -Namespace "root/MyNamespace" -Class "MyClass_ExampleName"

This produces the following error in PowerShell:

Get-CimInstance : Provider load failure  
At line:1 char:1
+ Get-CimInstance -Namespace "root/MyNamespace" -Class "MyClass_ExampleName"  
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
    + CategoryInfo          : NotSpecified: (root/Surface:Device_Status:String) [Get-CimInstance], CimException  
    + FullyQualifiedErrorId : HRESULT 0x80041013,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand

Likewise, there are three (3) Event Viewer logs that are generated when this command is executed:

  1. MyWmiProvider provider started with result code 0x80041013. HostProcess = wmiprvse.exe; ProcessID = 2144; ProviderPath = C:\MyWmiProvider.dll

  2. Id = {FB6B3CF7-293E-0002-9316-73FB3E29D601}; ClientMachine = RTR-USERNAME; User = MYDOMAIN\username; ClientProcessId = 19416; Component = Unknown; Operation = Start IWbemServices::CreateInstanceEnum - root\MyNamespace : MyClass_ExampleName; ResultCode = 0x80041013; PossibleCause = Unknown

  3. MyWmiProvider provider started with result code 0x80041013. HostProcess = wmiprvse.exe; ProcessID = 24636; ProviderPath = C:\MyWmiProvider.dll

(It is shown that WMI did find the DLL correctly)

I get similar results if I try calling Get-WMIObject, except the second Event Viewer log says the "Operation" was "Start IWbemServices::ExecQuery - root\MyNamespace : MyClass_ExampleName".

What exactly are Get-WMIObject and Get-CimInstance doing in the background?

I have looked up the source for Get-WMIObject [here] and despite the simple 6 lines, looking up the respect classes and function calls does not yield detailed specifics. My DLL interface only includes four (4) exported functions: DllGetClassObject(), DllCanUnloadNow(), DllRegisterServer(), and DllUnregisterServer(). I thought both Get-WMIObject and Get-CimInstance first made a call to DllGetClassObject() in order to get the WMI class factory, however if I place a function call to save a string to a temporary file within DllGetClassObject(), I notice when calling these PowerShell commands that no temporary file is created.

I got even more specific by creating a new project following this answer so that I could be able to call the following:

DEFINE_GUID(InstanceProviderClassID, 0x00000001, 0x00000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F);

IWbemServices * pLoc = NULL;
CoCreateInstance(InstanceProviderClassID, NULL, CLSCTX_INPROC_SERVER, IID_IWbemServices, (LPVOID *)&pLoc);

The call to CoCreateInstance() in this case was successful. I even noticed the temporary log file was created, indicating that DllGetClassObject() was in fact called!

Even if I take a working instance provider that I have and put this same printing statement (or similarly a call to create a registry key/value) in its DllGetClassObject() function, nothing is ever saved to indicate that this function is called when calling these PowerShell commands.

1. What am I missing here?
2. Why is the DllGetClassObject() function never called when executing both Get-WMIObject and Get-CimInstance?
3. Why am I able to execute CoCreateInstance() successfully, demonstrating my provider is coded correctly, but get a "provider load failure" when executing one of the PowerShell commands?

(A side note: In order to make things easy, I have labeled all service functions with WBEM_E_NOT_SUPPORTED. When this is done in the working instance provider, I still do not see "provider load failure," but rather "not supported.")

like image 799
Code Doggo Avatar asked May 14 '20 02:05

Code Doggo


1 Answers

Get-CimInstance and Get-WmiObject both use .NET APIs to communicate with WMI. In the first case, it uses https://learn.microsoft.com/en-us/dotnet/api/microsoft.management.infrastructure and in the latter case uses https://learn.microsoft.com/en-us/dotnet/api/system.management. The main difference between these two is that the CIM APIs are cross-platform compatible, while the WMI APIs have Windows extensions to CIM that only work on Windows.

Whether you decide to use the PowerShell cmdlets, WMIC, wbemtest, or something else, they ultimately call the WMI COM API https://learn.microsoft.com/en-us/windows/win32/wmisdk/com-api-for-wmi to talk to WMI to talk to WMI Providers.

Did you follow https://learn.microsoft.com/en-us/windows/win32/wmisdk/writing-an-instance-provider? It doesn't seem like you may have implemented IWbemServices in your COM server?

like image 189
Steve Lee Avatar answered Nov 15 '22 23:11

Steve Lee