Что на самом деле делает Get-WMIObject\Get-CimInstance?

Я разрабатываю новый поставщик экземпляров 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

(Где {00000001-0000-0000-0000-00000000000F} — это просто идентификатор тестового класса (CLSID))

Я также могу успешно добавить определения классов WMI, определенные в моем файле Mуправляемого Object Fформата (MOF), используя mofcomp.exe. Я могу убедиться, что мои определения присутствуют в репозитории 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. #P8#
  2. #P9#
  3. #P10#

(Показано, что WMI правильно нашел DLL)

Я получаю аналогичные результаты, если пытаюсь вызвать Get-WMIObject, за исключением того, что во втором журнале просмотра событий указано, что "Операция" была "Start IWbemServices::ExecQuery - root\MyNamespace : MyClass_ExampleName".

Что именно Get-WMIObject и Get-CimInstance делают в фоновом режиме?

Я просмотрел источник для Get-WMIObject [здесь] и, несмотря на простые 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);

Вызов CoCreateInstance() в этом случае был успешен. Я даже заметил, что был создан временный файл журнала, указывающий, что DllGetClassObject() на самом деле был вызван!

Даже если я возьму поставщика рабочего экземпляра, который у меня есть, и помещу тот же оператор печати (или аналогичный вызов для создания ключа/значения реестра) в его DllGetClassObject(), ничего не сохраняется, чтобы указать, что эта функция вызывается при вызове этих команд PowerShell.

<сильный>1. Что мне здесь не хватает?
2. Почему DllGetClassObject() никогда не вызывалась при выполнении Get-WMIObject и Get-CimInstance?
3. Почему я могу выполнить CoCreateInstance() успешно, демонстрируя, что мой провайдер написан правильно, но получаю "сбой загрузки провайдера" при выполнении одного команд PowerShell?

(Примечание: для упрощения я обозначил все сервисные функции с WBEM_E_NOT_SUPPORTED. Когда это делается в рабочем экземпляре провайдера, я по-прежнему вижу не "сбой загрузки провайдера", а скорее "не поддерживается .")


person Code Doggo    schedule 14.05.2020    source источник
comment
Вы пытались запустить команду Get-CimInstance с параметром -Debug? Возможно, вы получите больше информации о том, что происходит. Кроме этого, попробуйте выполнить запрос с помощью инструмента wbemtest.exe (в System32\wbem). stackoverflow.com/a/15070084/934946   -  person Sage Pourpre    schedule 05.07.2020
comment
Вы также можете попробовать использовать wmic.exe, если вы не доверяете PowerShell (что, вероятно, делает правильно). Как вы собираетесь использовать своего провайдера WMI/CIM? Вы получаете подобные ошибки....   -  person HerbM    schedule 15.11.2020