Why is IEnumWbemClassObject->Next returning E_ACCESSDENIED

Posted on 2006-04-02
Last Modified: 2012-06-22
I am trying to query the WMI information on other computers on the local network.  All of the computers are running Windows XP (with SP) and are on the same local workgroup.  All of the computers have the same administrator password which has been verified by successfully connecting to each computer and mapping to the C$ share using the administrator username/password.  However, the following code works correctly on 3 out of the 4 computers.  On one of the computers the code works up until the call to enumerator->Next which failes with an HRESULT of E_ACCESSDENIED.  First of all, how could the administrator get an access denied result.  Second, why does it only get an access denied on the next and not on any of the prior calls to connect to the computer or to setup the WMI query.  Thirdly, why would this work on 3 other extremely similar computers and not the 4th?

int main(int argc,char** argv)
      HRESULT hres;
      char username[]="administrator";
      char password[]="adminPassword";
      char domain[]="";
      char wmiNamespace[]="\\\\ServerName\\ROOT\\CIMV2";

      hres =  CoInitializeEx(0, COINIT_MULTITHREADED);
      if (FAILED(hres))
            cout << "Failed to initialize COM library. Error code = 0x" << hex << hres << endl;
            return 1;                  // Program has failed.

      hres =  CoInitializeSecurity(
            -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(hres)) {
        cout << "Failed to initialize security. Error code = 0x" << hex << hres << endl;
        return 1;                    // Program has failed.

      IWbemLocator *pLoc = NULL;
      hres = CoCreateInstance( CLSID_WbemLocator,0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
      if (FAILED(hres))
            cout << "Failed to create IWbemLocator object." << " Err code = 0x" << hex << hres << endl;
            return 1;                 // Program has failed.

      IWbemServices *pSvc = NULL;
      hres = pLoc->ConnectServer(
            T2W(wmiNamespace),                              // Object path of WMI namespace
            T2W(username),                    // User name. NULL = current user
            T2W(password),                    // User password. NULL = current
            0,                       // Locale. NULL indicates current              
            WBEM_FLAG_CONNECT_USE_MAX_WAIT,                    // Security flags.
            0,                       // Authority (e.g. Kerberos)        
            0,                       // Context object
            &pSvc                    // pointer to IWbemServices proxy

      if (FAILED(hres))
            cout << "Could not connect. Error code = 0x" << hex << hres << endl;
            return 1;                // Program has failed.

      cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;

      SEC_WINNT_AUTH_IDENTITY        authidentity;
      SecureZeroMemory( &authidentity, sizeof(authidentity) );
      authidentity.User = (LPUSTR)T2W( (LPTSTR)(LPCTSTR)username);
      authidentity.UserLength = strlen(username);
      authidentity.Domain = (LPUSTR)T2W( (LPTSTR)(LPCTSTR)domain);
      authidentity.DomainLength = strlen(domain );
      authidentity.Password = (LPUSTR)T2W( (LPTSTR)(LPCTSTR)password);
      authidentity.PasswordLength = strlen(password );
      authidentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;

      hres = CoSetProxyBlanket(
            pSvc,                        // 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
            &authidentity,                        // client identity
            EOAC_NONE                    // proxy capabilities

      if (FAILED(hres))
            cout << "Could not set proxy blanket. Error code = 0x" << hex << hres << endl;
            return 1;               // Program has failed.

      IEnumWbemClassObject* pEnumerator = NULL;
      hres = pSvc->ExecQuery( bstr_t("WQL"),
            bstr_t("SELECT * FROM Win32_Desktop"),
      if (FAILED(hres))
            cout << "Query for operating system name failed."
                  << " Error code = 0x"
                  << hex << hres << endl;
            return 1;               // Program has failed.

      IWbemClassObject *pclsObj=NULL;
      ULONG uReturn = 0;
      while (pEnumerator)
            HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
            if(0 == uReturn) break;
            VARIANT vtProp;
            hr = pclsObj->Get(L"ScreenSaverExecutable", 0, &vtProp, 0, 0);    
            cout << "Executable: ";
            char* executableName = W2T(vtProp.bstrVal);
            cout << executableName;
Question by:gmain
    LVL 11

    Expert Comment

    >> First of all, how could the administrator get an access denied result.
    Administrator accounts do not have access rights to everything on Windows just because they are administrators. It's possible to remove access rights even for adminstrators from files, directories (i.e. by default no access to /System Volume Information) or registry subtrees (i.e. cannot write to HKLM\SYSTEM\CurrentControlSet\Enum\Root by default). Although Administrators can modify all access rights they want and as a consequence of this gain access to everything. Revoking administrators (i.e. your own) access rights is sometimes actually quite usefull, i.e. to prevent programs (or malwale) from modifying certain files or registry entries.

    Author Comment

    Just as added info, the following VBScript works on all of the machines:

    Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
    Set objWMIService = objSWbemLocator.ConnectServer("computerName", _
        "root\CIMV2", "Administrator", "AdminPassword",NULL,NULL)
    Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Desktop",,48)

    For Each objItem in colItems
        Wscript.Echo "ScreenSaverExecutable: " & objItem.ScreenSaverExecutable

    The key now is to get this same functionality to work in C++ code

    Author Comment

    In an effort to discover the reason for the E_ACCESSDENIED, I have done the following on the computer where the Next operation fails:
       - Ran WmiMgmt.msc and verified that the administrators group has full access to the CIMV2 namespace
       - Enabled WMI verbose logging (in WmiMgmt.msc) and ran the C++ code again and no errors appeared in the generated logs

    Author Comment

    Figured out the problem.... per a Microsoft website, you MUST call CoSetProxyBlanket on EVERY interface you retrieve.  This would include the enumerator class.  Once I successfully called that on the enumerator object I no longer got the E_ACCESSDENIED return from the next function.
    LVL 11

    Expert Comment

    I'm happy that gmain found a solution to his problem and refunding the points is perfectly o.k. for me.

    Accepted Solution

    PAQ-ing the question and refunding 500 points

    Thanks x4u !

    The Experts Exchange
    Community Support Moderator of all Ages

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    How your wiki can always stay up-to-date

    Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
    - Increase transparency
    - Onboard new hires faster
    - Access from mobile/offline

    Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
    Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
    The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
    The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

    760 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    10 Experts available now in Live!

    Get 1:1 Help Now