c++ WMI: Failure to both enumerate and get instance methods (Windows 10 21H2)

36 views Asked by At

Attempting to use WMI to locate and set up (initialize/partition/format) newly minted VHD disks.

I have C++ code which appears to work perfectly well at finding and retrieving instances properties for both the MSFT_Partition and MSFT_Volume classes. When the MRE (below) is run it will faithfully display the new VHD attributes of interest (VHD was initialized/partitioned/formatted in disk manager).

The HRESULT is 0x8004101e which tends to indicate I'm using the wrong root or something.

hr = wbemLocator->ConnectServer(_bstr_t(L"ROOT\\microsoft\\windows\\storage"),...

I'm baffled. Can anyone set me right here please?

N.B. Exercise extreme caution here. This code is going to try and access WMI formatting capabilities and the MRE does attract the attention of Windows Defender.

N.B. The Format() method can be invoked successfully from WMI Explorer via the same path (https://github.com/vinaypamnani/wmie2). All testing is being done from a run-as-administrator instance of VS2022, Windows 10 x64.

enter image description here

The example of method invocation shown here does work (https://learn.microsoft.com/en-gb/windows/win32/wmisdk/example--calling-a-provider-method?redirectedfrom=MSDN)

SELECT * FROM MSFT_Volume WHERE FileSystemLabel="61MBVHD" =>
ObjId:{1}\\I7\root/Microsoft/Windows/Storage/Providers_v2\WSP_Volume.ObjectId="{f709bd83-a92c-11e8-a069-806e6f6e6963}:VO:\\?\Volume{00000001-0000-0000-0000-010000000000}\"
Path:\\?\Volume{00000001-0000-0000-0000-010000000000}\
UniqueId:\\?\Volume{00000001-0000-0000-0000-010000000000}\
FileSystemLabel:61MBVHD
Size:63959040

Here is the MRE. It will enumerate all partitions.

/*
    MRE for WMI/WBEM setup/connection/query/enumeration
    compile from a VS shell: cl /W4 /EHsc mre.cpp
    WMI example link: https://github.com/vinaypamnani/wmie2.
*/
#include <windows.h>
#include <Wbemidl.h>
#include <comdef.h>
#include <vector>
#include <iostream>
#include <atlbase.h>
#include <atlcom.h>
#pragma comment(lib, "wbemuuid.lib")
//const char* pquery = R"(SELECT * FROM MSFT_Volume WHERE FileSystemLabel="61MBVHD")";
const char* pquery = R"(SELECT * FROM MSFT_Volume)";
//-----------------------------------------------------------------------------
// attempt to get a methods interface (?)
void GetMethod(CComPtr<IWbemClassObject>& storageWbemObject) {
    // can we get the format method????
    bstr_t methodName(L"Format");
    CComPtr<IWbemClassObject> ppInSignature;
    CComPtr<IWbemClassObject> ppOutSignature;
    //HRESULT hr = storageWbemObject->GetMethod(methodName,0,&ppInSignature,&ppOutSignature);
    IWbemClassObject* pInParamsDefinition = nullptr;
    HRESULT hr = storageWbemObject->GetMethod((BSTR)methodName, 0, &pInParamsDefinition, NULL);
    if (FAILED(hr))
        std::wcout << _com_error(hr).ErrorMessage() << std::endl;
}
//-----------------------------------------------------------------------------
// try to enumerate all methods like WMI Explorer. Fails. No examples found.
void GetMethods(CComPtr<IWbemClassObject>& storageWbemObject) {
    long lFlags = 0;
    // fails here.
    HRESULT hr = storageWbemObject->BeginMethodEnumeration(lFlags);
    if (FAILED(hr)) {
        std::wcout << _com_error(hr).ErrorMessage() << std::endl;
        return;
    }
    for (;;) {
        BSTR name = nullptr;
        hr = storageWbemObject->NextMethod(0, &name, NULL, NULL);
        if (FAILED(hr)) {
            std::wcout << _com_error(hr).ErrorMessage() << std::endl;
            break;
        }
    }
    hr = storageWbemObject->EndMethodEnumeration();
}
//-----------------------------------------------------------------------------
void EnumVolume(CComPtr<IWbemServices>& wbemServices) {
    // check we have a valid instance.
    std::cout << pquery << " => " << std::endl;
    CComPtr<IEnumWbemClassObject> storageEnumerator;
    HRESULT hr = wbemServices->ExecQuery(bstr_t("WQL"),
                        bstr_t(pquery),
                        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
                        NULL,
                        &storageEnumerator);
    if (FAILED(hr))
        throw std::runtime_error("Query for MSFT_Volume");
    while (storageEnumerator) {
        ULONG uReturn = 0;
        CComPtr<IWbemClassObject> storageWbemObject;
        hr = storageEnumerator->Next(WBEM_INFINITE, 1, &storageWbemObject, &uReturn);
        if (0 == uReturn || hr != S_OK)
            break;
        VARIANT ObjectId;
        storageWbemObject->Get(L"ObjectId", 0, &ObjectId, 0, 0);
        VARIANT Path;
        storageWbemObject->Get(L"Path", 0, &Path, 0, 0);
        VARIANT UniqueId;
        storageWbemObject->Get(L"UniqueId", 0, &UniqueId, 0, 0);
        VARIANT FileSystemLabel;
        storageWbemObject->Get(L"FileSystemLabel", 0, &FileSystemLabel, 0, 0);
        VARIANT Size;
        storageWbemObject->Get(L"Size", 0, &Size, 0, 0);
        // we obviously(?) have a valaid instance as attributes as per WMI Explorer.
        std::cout << "ObjId:" << std::string(ObjectId.bstrVal == NULL ? "NULL" : _bstr_t(ObjectId.bstrVal)) << std::endl
            << "Path:" << std::string(Path.bstrVal == NULL ? "NULL" : _bstr_t(Path.bstrVal)) << std::endl
            << "UniqueId:" << std::string(UniqueId.bstrVal == NULL ? "NULL" : _bstr_t(UniqueId.bstrVal)) << std::endl
            << "FileSystemLabel:" << std::string(FileSystemLabel.bstrVal == NULL ? "NULL" : _bstr_t(FileSystemLabel.bstrVal)) << std::endl
            << "Size:" << std::string(_bstr_t(Size.bstrVal)) << std::endl;
        // enumerate methods???
        GetMethods(storageWbemObject);
    }
}
//-----------------------------------------------------------------------------
int main() {
    int ret = -2;
    try {
        CComPtr<IWbemLocator> wbemLocator;
        CComPtr<IWbemServices> wbemServices;
        HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
        if (FAILED(hr))
            throw std::runtime_error("Failed to initialize COM");
        // flag COM as initialized
        ret = -1;
        // Set general COM security levels --------------------------
        hr = CoInitializeSecurity(NULL,
            -1,                          // COM authentication
            NULL,                        // Authentication services
            NULL,                        // Reserved
            RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
            RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
            NULL,                        // Authentication info
            EOAC_NONE,                   // Additional capabilities 
            NULL);                         // Reserved
        if (FAILED(hr))
            throw std::runtime_error("Failed to initialize security");
        // Obtain the initial locator to WMI -------------------------
        hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&wbemLocator);
        if (FAILED(hr))
            throw std::runtime_error("Failed to create IWbemLocator");
        // Connect to the ROOT\\\microsoft\\windows\\storage
        hr = wbemLocator->ConnectServer(
            _bstr_t(L"ROOT\\microsoft\\windows\\storage"), // Object path of WMI namespace
            NULL,                    // User name. NULL = current user
            NULL,                    // User password. NULL = current
            0,                       // Locale. NULL indicates current
            NULL,                    // Security flags.
            0,                       // Authority (for example, Kerberos)
            0,                       // Context object 
            &wbemServices);         // pointer to IWbemServices proxy
        if (FAILED(hr))
            throw std::runtime_error("Could not connecct");
        // Set security levels on the proxy -------------------------
        hr = CoSetProxyBlanket(
            wbemServices,                        // Indicates the proxy to set
            RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
            RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
            NULL,                        // Server principal name 
            RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
            RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
            NULL,                        // client identity
            EOAC_NONE);                  // proxy capabilities 
        if (FAILED(hr))
            throw std::runtime_error("CoSetProxyBlanket()");
        // do the work
        EnumVolume(wbemServices);
        ret = 0;
    }
    catch (const std::exception& ex) {
        std::cout << "Exception: " << ex.what() << std::endl;
    }
    // is it safe>?
    if (ret >= -1)
        CoUninitialize();
    return ret;
}

0

There are 0 answers