Exemple : Obtention de données WMI à partir d’un ordinateur distant

Vous pouvez utiliser la procédure et les exemples de code dans cette rubrique pour créer une application cliente WMI complète qui effectue l’initialisation COM, se connecte à WMI sur un ordinateur distant, obtient des données de manière semi-synchrone, puis nettoie. Pour plus d’informations sur la façon d’obtenir des données à partir de l’ordinateur local, veuillez consulter la section Exemple : Obtention de données WMI à partir de l’ordinateur local. Pour plus d’informations sur la façon d’obtenir les données de manière asynchrone, veuillez consulter la section Exemple : Obtention de données WMI à partir de l’ordinateur local de manière asynchrone.

Remarque

Si vous essayez de vous connecter à un ordinateur distant, consultez les informations dans Connexion à WMI à distance.

 

La procédure suivante montre comment exécuter l’application WMI. Les étapes 1 à 5 contiennent toutes les étapes nécessaires pour configurer et se connecter à WMI, et les étapes 6 et 7 concernent la requête et la réception des données.

Pour obtenir des données WMI à partir d’un ordinateur distant

  1. Initialisez les paramètres COM avec un appel à CoInitializeEx.

    Pour plus d’informations, consultez la section Initialisation de COM pour une application WMI.

  2. Initialisez la sécurité du processus COM en appelant CoInitializeSecurity.

    Pour plus d’informations, consultez la section Définition du niveau de sécurité du processus par défaut en utilisant C++.

  3. Obtenez le localisateur initial vers WMI en appelant CoCreateInstance.

    Pour plus d’informations, consultez la section Création d’une connexion à un espace de noms WMI.

  4. Obtenez un pointeur vers IWbemServices pour l’espace de noms \\root\cimv2 sur un ordinateur distant en appelant IWbemLocator::ConnectServer. Lorsque vous vous connectez à un ordinateur distant, vous devez connaître le nom de l’ordinateur, le domaine, le nom d’utilisateur et le mot de passe de l’ordinateur distant auquel vous vous connectez. Ces attributs sont tous passés dans la méthode IWbemLocator::ConnectServer. Assurez-vous également que le nom d’utilisateur de l’ordinateur qui tente de se connecter à l’ordinateur distant dispose des privilèges d’accès appropriés sur l’ordinateur distant. Pour plus d’informations, consultez la section Connexion via le pare-feu Windows. Pour se connecter à l’ordinateur local, veuillez consulter les sections Exemple : Obtention de données WMI à partir de l’ordinateur local et Création d’une connexion à un espace de noms WMI.

    Lors de la gestion des noms d’utilisateur et des mots de passe, il est recommandé de demander ces informations à l’utilisateur, de les utiliser, puis de les supprimer, afin de réduire le risque que ces informations soient interceptées par un utilisateur non autorisé. L’étape 4 du code d’exemple ci-dessous utilise CredUIPromptForCredentials pour obtenir le nom d’utilisateur et le mot de passe, puis utilise SecureZeroMemory pour se débarrasser des informations après leur utilisation dans IWbemLocator::ConnectServer. Pour plus d’informations, consultez les sections Gestion des mots de passe et Demander des informations d’identification à l’utilisateur.

  5. Créez une structure COAUTHIDENTITY pour fournir les informations d’identification nécessaires à la définition de la sécurité du proxy.

  6. Définissez la sécurité du proxy IWbemServices afin que le service WMI puisse se faire passer pour le client en appelant CoSetProxyBlanket.

    Pour plus d’informations, consultez la section Définition des niveaux de sécurité sur une connexion WMI.

  7. Utilisez le pointeur IWbemServices pour faire des requêtes à WMI. Une requête est exécutée pour obtenir le nom du système d’exploitation et la quantité de mémoire physique libre en appelant IWbemServices::ExecQuery.

    La requête WQL suivante est l’un des arguments de la méthode.

    SELECT * FROM Win32_OperatingSystem

    Le résultat de cette requête est stocké dans un pointeur IEnumWbemClassObject. Cela permet de récupérer les objets de données de la requête de manière semi-synchrone avec l’interface IEnumWbemClassObject. Pour plus d’informations, consultez la section Énumération WMI. Pour obtenir les données de manière asynchrone, consultez la section Exemple : Obtention de données WMI à partir de l’ordinateur local de manière asynchrone.

    Pour plus d’informations sur la façon de faire des requêtes à WMI, consultez les sections Manipulation des informations de classe et d’instance, Requêtes WMI, et Appel d’une méthode.

  8. Définissez la sécurité du proxy de l’énumérateur IEnumWbemClassObject. Assurez-vous d’effacer les informations d’identification de la mémoire après avoir fini de les utiliser.

    Pour plus d’informations, consultez la section Définition de la sécurité sur IWbemServices et autres proxys.

  9. Obtenez et affichez les données de la requête WQL. Le pointeur IEnumWbemClassObject est lié aux objets de données retournés par la requête, et les objets de données peuvent être récupérés avec la méthode IEnumWbemClassObject::Next. Cette méthode lie les objets de données à un pointeur IWbemClassObject qui est passé dans la méthode. Utilisez la méthode IWbemClassObject::Get pour obtenir les informations souhaitées à partir des objets de données.

    Le code d’exemple suivant est utilisé pour obtenir la propriété Name à partir de l’objet de données, qui fournit le nom du système d’exploitation.

    VARIANT vtProp;
    
    // Get the value of the Name property
    hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
    wcout << " OS Name : " << vtProp.bstrVal << endl;
    

    Une fois la valeur de la propriété Name stockée dans la variable VARIANT vtProp, elle peut ensuite être affichée à l’utilisateur.

    Le code d’exemple suivant montre comment la variable VARIANT peut être utilisée à nouveau pour stocker et afficher la valeur de la quantité de mémoire physique libre.

    hr = pclsObj->Get(L"FreePhysicalMemory",
        0, &vtProp, 0, 0);
    wcout << " Free physical memory (in kilobytes): "
        << vtProp.uintVal << endl;
    

    Pour plus d’informations, consultez la section Énumération WMI.

Le code d’exemple suivant montre comment obtenir des données WMI de manière semi-synchrone à partir d’un ordinateur distant.

#define _WIN32_DCOM
#define UNICODE
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "credui.lib")
#pragma comment(lib, "comsuppw.lib")
#include <wincred.h>
#include <strsafe.h>

int __cdecl main(int argc, char **argv)
{
    HRESULT hres;

    // Step 1: --------------------------------------------------
    // Initialize COM. ------------------------------------------

    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.
    }

    // Step 2: --------------------------------------------------
    // Set general COM security levels --------------------------

    hres =  CoInitializeSecurity(
        NULL, 
        -1,                          // COM authentication
        NULL,                        // Authentication services
        NULL,                        // Reserved
        RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
        RPC_C_IMP_LEVEL_IDENTIFY,    // 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;
        CoUninitialize();
        return 1;                    // Program has failed.
    }
    
    // Step 3: ---------------------------------------------------
    // Obtain the initial locator to WMI -------------------------

    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;
        CoUninitialize();
        return 1;                 // Program has failed.
    }

    // Step 4: -----------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method

    IWbemServices *pSvc = NULL;

    // Get the user name and password for the remote computer
    CREDUI_INFO cui;
    bool useToken = false;
    bool useNTLM = true;
    wchar_t pszName[CREDUI_MAX_USERNAME_LENGTH+1] = {0};
    wchar_t pszPwd[CREDUI_MAX_PASSWORD_LENGTH+1] = {0};
    wchar_t pszDomain[CREDUI_MAX_USERNAME_LENGTH+1];
    wchar_t pszUserName[CREDUI_MAX_USERNAME_LENGTH+1];
    wchar_t pszAuthority[CREDUI_MAX_USERNAME_LENGTH+1];
    BOOL fSave;
    DWORD dwErr;

    memset(&cui,0,sizeof(CREDUI_INFO));
    cui.cbSize = sizeof(CREDUI_INFO);
    cui.hwndParent = NULL;
    // Ensure that MessageText and CaptionText identify
    // what credentials to use and which application requires them.
    cui.pszMessageText = TEXT("Press cancel to use process token");
    cui.pszCaptionText = TEXT("Enter Account Information");
    cui.hbmBanner = NULL;
    fSave = FALSE;

    dwErr = CredUIPromptForCredentials( 
        &cui,                             // CREDUI_INFO structure
        TEXT(""),                         // Target for credentials
        NULL,                             // Reserved
        0,                                // Reason
        pszName,                          // User name
        CREDUI_MAX_USERNAME_LENGTH+1,     // Max number for user name
        pszPwd,                           // Password
        CREDUI_MAX_PASSWORD_LENGTH+1,     // Max number for password
        &fSave,                           // State of save check box
        CREDUI_FLAGS_GENERIC_CREDENTIALS |// flags
        CREDUI_FLAGS_ALWAYS_SHOW_UI |
        CREDUI_FLAGS_DO_NOT_PERSIST);  

    if(dwErr == ERROR_CANCELLED)
    {
        useToken = true;
    }
    else if (dwErr)
    {
        cout << "Did not get credentials " << dwErr << endl;
        pLoc->Release();     
        CoUninitialize();
        return 1;      
    }

    // change the computerName strings below to the full computer name
    // of the remote computer
    if(!useNTLM)
    {
        StringCchPrintf(pszAuthority, CREDUI_MAX_USERNAME_LENGTH+1, L"kERBEROS:%s", L"COMPUTERNAME");
    }

    // Connect to the remote root\cimv2 namespace
    // and obtain pointer pSvc to make IWbemServices calls.
    //---------------------------------------------------------
   
    hres = pLoc->ConnectServer(
        _bstr_t(L"\\\\COMPUTERNAME\\root\\cimv2"),
        _bstr_t(useToken?NULL:pszName),    // User name
        _bstr_t(useToken?NULL:pszPwd),     // User password
        NULL,                              // Locale             
        NULL,                              // Security flags
        _bstr_t(useNTLM?NULL:pszAuthority),// Authority        
        NULL,                              // Context object 
        &pSvc                              // IWbemServices proxy
        );
    
    if (FAILED(hres))
    {
        cout << "Could not connect. Error code = 0x" 
             << hex << hres << endl;
        pLoc->Release();     
        CoUninitialize();
        return 1;                // Program has failed.
    }

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


    // step 5: --------------------------------------------------
    // Create COAUTHIDENTITY that can be used for setting security on proxy

    COAUTHIDENTITY *userAcct =  NULL ;
    COAUTHIDENTITY authIdent;

    if( !useToken )
    {
        memset(&authIdent, 0, sizeof(COAUTHIDENTITY));
        authIdent.PasswordLength = wcslen (pszPwd);
        authIdent.Password = (USHORT*)pszPwd;

        LPWSTR slash = wcschr (pszName, L'\\');
        if( slash == NULL )
        {
            cout << "Could not create Auth identity. No domain specified\n" ;
            pSvc->Release();
            pLoc->Release();     
            CoUninitialize();
            return 1;               // Program has failed.
        }

        StringCchCopy(pszUserName, CREDUI_MAX_USERNAME_LENGTH+1, slash+1);
        authIdent.User = (USHORT*)pszUserName;
        authIdent.UserLength = wcslen(pszUserName);

        StringCchCopyN(pszDomain, CREDUI_MAX_USERNAME_LENGTH+1, pszName, slash - pszName);
        authIdent.Domain = (USHORT*)pszDomain;
        authIdent.DomainLength = slash - pszName;
        authIdent.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;

        userAcct = &authIdent;

    }

    // Step 6: --------------------------------------------------
    // Set security levels on a WMI connection ------------------

    hres = CoSetProxyBlanket(
       pSvc,                           // Indicates the proxy to set
       RPC_C_AUTHN_DEFAULT,            // RPC_C_AUTHN_xxx
       RPC_C_AUTHZ_DEFAULT,            // RPC_C_AUTHZ_xxx
       COLE_DEFAULT_PRINCIPAL,         // Server principal name 
       RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  // RPC_C_AUTHN_LEVEL_xxx 
       RPC_C_IMP_LEVEL_IMPERSONATE,    // RPC_C_IMP_LEVEL_xxx
       userAcct,                       // client identity
       EOAC_NONE                       // proxy capabilities 
    );

    if (FAILED(hres))
    {
        cout << "Could not set proxy blanket. Error code = 0x" 
            << hex << hres << endl;
        pSvc->Release();
        pLoc->Release();     
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // Step 7: --------------------------------------------------
    // Use the IWbemServices pointer to make requests of WMI ----

    // For example, get the name of the operating system
    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(
        bstr_t("WQL"), 
        bstr_t("Select * from Win32_OperatingSystem"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
        NULL,
        &pEnumerator);
    
    if (FAILED(hres))
    {
        cout << "Query for operating system name failed."
            << " Error code = 0x" 
            << hex << hres << endl;
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // Step 8: -------------------------------------------------
    // Secure the enumerator proxy
    hres = CoSetProxyBlanket(
        pEnumerator,                    // Indicates the proxy to set
        RPC_C_AUTHN_DEFAULT,            // RPC_C_AUTHN_xxx
        RPC_C_AUTHZ_DEFAULT,            // RPC_C_AUTHZ_xxx
        COLE_DEFAULT_PRINCIPAL,         // Server principal name 
        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  // RPC_C_AUTHN_LEVEL_xxx 
        RPC_C_IMP_LEVEL_IMPERSONATE,    // RPC_C_IMP_LEVEL_xxx
        userAcct,                       // client identity
        EOAC_NONE                       // proxy capabilities 
        );

    if (FAILED(hres))
    {
        cout << "Could not set proxy blanket on enumerator. Error code = 0x" 
             << hex << hres << endl;
        pEnumerator->Release();
        pSvc->Release();
        pLoc->Release();     
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // When you have finished using the credentials,
    // erase them from memory.
    SecureZeroMemory(pszName, sizeof(pszName));
    SecureZeroMemory(pszPwd, sizeof(pszPwd));
    SecureZeroMemory(pszUserName, sizeof(pszUserName));
    SecureZeroMemory(pszDomain, sizeof(pszDomain));


    // Step 9: -------------------------------------------------
    // Get the data from the query in step 7 -------------------
 
    IWbemClassObject *pclsObj = NULL;
    ULONG uReturn = 0;
   
    while (pEnumerator)
    {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, 
            &pclsObj, &uReturn);

        if(0 == uReturn)
        {
            break;
        }

        VARIANT vtProp;

        // Get the value of the Name property
        hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
        wcout << " OS Name : " << vtProp.bstrVal << endl;

        // Get the value of the FreePhysicalMemory property
        hr = pclsObj->Get(L"FreePhysicalMemory",
            0, &vtProp, 0, 0);
        wcout << " Free physical memory (in kilobytes): "
            << vtProp.uintVal << endl;
        VariantClear(&vtProp);

        pclsObj->Release();
        pclsObj = NULL;
    }

    // Cleanup
    // ========
    
    pSvc->Release();
    pLoc->Release();
    pEnumerator->Release();
    if( pclsObj )
    {
        pclsObj->Release();
    }
    
    CoUninitialize();

    return 0;   // Program successfully completed.
    
}