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

15

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.")

powershell
visual-c++
com
wmi
get-wmiobject
asked on Stack Overflow May 14, 2020 by Code Doggo • edited May 16, 2020 by Code Doggo

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0