Get-WMIObject \ Get-CimInstance 实际上做了什么?



我正在开发一个新的 WMI 实例提供程序,但我遇到了一些麻烦。我能够使用regsvr32.exe成功注册我的提供商。regsvr32应用程序调用我的DllRegisterServer实现,并创建以下注册表项和值:

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

(其中{00000001-0000-0000-0000-00000000000F}只是一个测试类 ID (CLSID((

我还能够使用mofcomp.exe成功添加在我的ManagedObjectFormat (MOF( 文件中定义的 WMI 类定义。我能够通过运行以下命令来验证我的定义是否存在于 WMI 存储库中:

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

下面是我的 MOF 文件的外观示例:

#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;
};

现在,如果我运行以下内容:

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

这会在 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

同样,执行此命令时会生成三 (3( 个事件查看器日志:

  1. MyWmiProvider 提供程序从结果代码0x80041013开始。HostProcess = wmiprvse.exe;进程 ID = 2144;ProviderPath = C:\MyWmiProvider.dll

  2. ID = {FB6B3CF7-293E-0002-9316-73FB3E29D601};客户端计算机 = RTR 用户名;用户 = 我的域\用户名;客户端进程 ID = 19416;组件 = 未知;操作 = 启动 IWbemServices::CreateInstanceEnum - root\MyNamespace : MyClass_ExampleName;结果代码 = 0x80041013;可能的原因 = 未知

  3. MyWmiProvider 提供程序从结果代码0x80041013开始。HostProcess = wmiprvse.exe;进程 ID = 24636;ProviderPath = C:\MyWmiProvider.dll

(显示 WMI 确实正确找到了 DLL(

如果我尝试调用Get-WMIObject,我会得到类似的结果,除了第二个事件查看器日志显示"操作">"启动IWbemServices::ExecQuery - root\MyNamespace : MyClass_ExampleName"。

Get-WMIObjectGet-CimInstance在后台到底在做什么?

我已经查找了Get-WMIObject源代码[这里],尽管有简单的 6 行,但查找尊重类和函数调用并不能产生详细的细节。我的DLL接口只包括四(4(个导出的函数:DllGetClassObject()DllCanUnloadNow()DllRegisterServer()DllUnregisterServer()。我认为Get-WMIObjectGet-CimInstance首先调用DllGetClassObject()以获取WMI类工厂,但是如果我放置函数调用以将字符串保存到DllGetClassObject()中的临时文件,则在调用这些PowerShell命令时,我注意到不会创建临时文件。

通过在此答案之后创建一个新项目,我变得更加具体,以便我可以调用以下内容:

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);

在这种情况下,调用CoCreateInstance()成功。我什至注意到创建了临时日志文件,表明实际上调用了DllGetClassObject()

即使我采用我拥有的工作实例提供程序并将相同的打印语句(或类似地调用创建注册表项/值(放在其DllGetClassObject()函数中,也不会保存任何内容来指示在调用这些 PowerShell 命令时调用此函数。

1. 我在这里错过了什么?
2. 为什么在执行Get-WMIObjectGet-CimInstance时从不调用DllGetClassObject()函数?
3. 为什么我能够成功执行CoCreateInstance(),证明我的提供程序编码正确,但在执行其中一个 PowerShell 命令时出现"提供程序加载失败">

(旁注:为了使事情变得简单,我用WBEM_E_NOT_SUPPORTED标记了所有服务功能。在工作实例提供程序中执行此操作时,我仍然看不到">提供程序加载失败",而是"不支持"。

Get-CimInstanceGet-WmiObject都使用 .NET API 与 WMI 通信。在第一种情况下,它使用 https://learn.microsoft.com/en-us/dotnet/api/microsoft.management.infrastructure,在后一种情况下使用 https://learn.microsoft.com/en-us/dotnet/api/system.management。 这两者之间的主要区别在于CIM API是跨平台兼容的,而WMI API具有仅适用于Windows的CIM的Windows扩展。

无论您决定使用 PowerShell cmdlet、WMIC、wbemtest 还是其他东西,它们最终都会调用 WMI COM API https://learn.microsoft.com/en-us/windows/win32/wmisdk/com-api-for-wmi 与 WMI 通信,以便与 WMI 提供程序通信。

你跟着 https://learn.microsoft.com/en-us/windows/win32/wmisdk/writing-an-instance-provider 吗? 您似乎没有在 COM 服务器中实现 IWbemServices?

最新更新