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

Cod*_*ggo 17 com powershell wmi visual-c++ get-wmiobject

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

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
Run Code Online (Sandbox Code Playgroud)

(哪里{00000001-0000-0000-0000-00000000000F}只是一个测试类 ID(CLSID))

我也能够成功地添加在我的定义我的WMI类定义中号anaged Ø bject ˚F使用ORMAT(MOF)文件mofcomp.exe。我可以通过运行以下命令来验证我的定义是否存在于 WMI 存储库中:

Get-CimClass -Namespace "root/MyNamespace" | Where-Object CimClassName -like "MyClass_*"
Run Code Online (Sandbox Code Playgroud)

这是我的 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;
};
Run Code Online (Sandbox Code Playgroud)

现在,如果我运行以下命令:

Get-CimInstance -Namespace "root/MyNamespace" -Class "MyClass_ExampleName"
Run Code Online (Sandbox Code Playgroud)

这会在 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
Run Code Online (Sandbox Code Playgroud)

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

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

  2. Id = {FB6B3CF7-293E-0002-9316-73FB3E29D601};ClientMachine = RTR-USERNAME; 用户 = MYDOMAIN\用户名;ClientProcessId = 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-WMIObject,并Get-CimInstance在后台做什么?

我已经查找了Get-WMIObject [here]的源代码,尽管有简单的 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);
Run Code Online (Sandbox Code Playgroud)

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

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

1. 我在这里缺少什么?
2. 为什么DllGetClassObject()在同时执行Get-WMIObject和执行时,函数从不调用Get-CimInstance
3. 为什么我能够CoCreateInstance()成功执行,证明我的提供程序编码正确,但在执行 PowerShell 命令之一时出现“提供程序加载失败”

(旁注:为了使事情变得简单,我已经标记所有的服务功能WBEM_E_NOT_SUPPORTED当这种在工作实例提供做,我还没有看到。“提供程序加载失败”,而是“不支持”。

Ste*_*Lee 2

Get-CimInstance两者Get-WmiObject都使用 .NET API 与 WMI 进行通信。在第一种情况下,它使用https://learn.microsoft.com/en-us/dotnet/api/microsoft.management.infrastruct,在后一种情况下使用https://learn.microsoft.com/en-us/ dotnet/api/system.management。这两者之间的主要区别在于 CIM API 是跨平台兼容的,而 WMI API 具有 CIM 的 Windows 扩展,只能在 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?