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) 个事件查看器日志:
MyWmiProvider 提供程序以结果代码0x80041013开始。HostProcess = wmiprvse.exe; 进程ID = 2144;ProviderPath = C:\MyWmiProvider.dll
Id = {FB6B3CF7-293E-0002-9316-73FB3E29D601};ClientMachine = RTR-USERNAME; 用户 = MYDOMAIN\用户名;ClientProcessId = 19416; 组件 = 未知;操作 = 启动 IWbemServices::CreateInstanceEnum - root\MyNamespace : MyClass_ExampleName; 结果代码 = 0x80041013 ; 可能的原因 = 未知
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-WMIObject
并Get-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
当这种在工作实例提供做,我还没有看到。“提供程序加载失败”,而是“不支持”。 )
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?
归档时间: |
|
查看次数: |
850 次 |
最近记录: |