Udostępnij przez


Przykład: pobieranie danych usługi WMI z komputera zdalnego

W tym temacie można użyć procedury i przykładów kodu, aby utworzyć kompletną aplikację kliencką usługi WMI, która wykonuje inicjowanie modelu COM, łączy się z usługą WMI na komputerze zdalnym, pobiera dane częściowo zsynchronizowane, a następnie czyści. Aby uzyskać więcej informacji na temat pobierania danych z komputera lokalnego, zobacz Przykład: pobieranie danych WMI z komputera lokalnego. Aby uzyskać więcej informacji na temat asynchronicznego pobierania danych, zobacz Przykład: pobieranie danych WMI z komputera lokalnego asynchronicznie.

Nuta

Jeśli próbujesz nawiązać połączenie z komputerem zdalnym, zapoznaj się z informacjami w Connecting to WMI Remotely.

 

Poniższa procedura pokazuje, jak wykonać aplikację WMI. Kroki od 1 do 5 zawierają wszystkie kroki wymagane do skonfigurowania usługi WMI i nawiązania połączenia z usługą WMI oraz kroki 6 i 7, w których są wysyłane zapytania o dane i odbierane.

Aby pobrać dane usługi WMI z komputera zdalnego

  1. Zainicjuj parametry MODELU COM za pomocą wywołania polecenia CoInitializeEx.

    Aby uzyskać więcej informacji, zobacz Inicjowanie modelu COM dla aplikacji WMI.

  2. Zainicjuj zabezpieczenia procesu COM, wywołując CoInitializeSecurity.

    Aby uzyskać więcej informacji, zobacz Ustawianie domyślnego poziomu zabezpieczeń procesu przy użyciu języka C++.

  3. Uzyskaj początkowy lokalizator do usługi WMI, wywołując CoCreateInstance.

    Aby uzyskać więcej informacji, zobacz Tworzenie połączenia z przestrzenią nazw usługi WMI.

  4. Uzyskaj wskaźnik IWbemServices dla przestrzeni nazw \\root\cimv2 na komputerze zdalnym, wywołując IWbemLocator::ConnectServer. Podczas nawiązywania połączenia z komputerem zdalnym należy znać nazwę komputera, domenę, nazwę użytkownika i hasło komputera zdalnego, z którym nawiązujesz połączenie. Wszystkie te atrybuty są przekazywane do metody IWbemLocator::ConnectServer. Upewnij się również, że nazwa użytkownika na komputerze, który próbuje nawiązać połączenie z komputerem zdalnym, ma odpowiednie uprawnienia dostępu na komputerze zdalnym. Aby uzyskać więcej informacji, zobacz Nawiązywanie połączenia za pośrednictwem zapory systemu Windows. Aby nawiązać połączenie z komputerem lokalnym, zobacz Przykład: pobieranie danych WMI z komputera lokalnego i Tworzenie połączenia z przestrzenią nazw usługi WMI.

    W przypadku obsługi nazw użytkowników i haseł zaleca się, aby użytkownik był monitowany o podanie informacji, używać tych informacji, a następnie usuwać je, aby nie było mniejsze prawdopodobieństwo przechwycenia informacji przez nieautoryzowanego użytkownika. Krok 4 w poniższym przykładowym kodzie używa CredUIPromptForCredentials, aby uzyskać nazwę użytkownika i hasło, a następnie używa SecureZeroMemory pozbyć się informacji po jego użyciu w IWbemLocator::ConnectServer. Aby uzyskać więcej informacji, zobacz Obsługa haseł i monitowanie użytkownika o poświadczenia.

  5. Utwórz strukturę COAUTHIDENTITY, aby podać poświadczenia służące do ustawiania zabezpieczeń serwera proxy.

  6. Ustaw zabezpieczenia serwera proxy IWbemServices, aby usługa WMI mogła personifikować klienta, wywołując coSetProxyBlanket.

    Aby uzyskać więcej informacji, zobacz Ustawianie poziomów zabezpieczeń w połączeniu usługi WMI.

  7. Użyj wskaźnika IWbemServices, aby wysyłać żądania usługi WMI. Zapytanie jest wykonywane w celu uzyskania nazwy systemu operacyjnego i ilości wolnej pamięci fizycznej przez wywołanie IWbemServices::ExecQuery.

    Następujące zapytanie WQL jest jednym z argumentów metody.

    SELECT * FROM Win32_OperatingSystem

    Wynik tego zapytania jest przechowywany w wskaźniku IEnumWbemClassObject. Dzięki temu obiekty danych z zapytania mogą być pobierane częściowo za pomocą interfejsu IEnumWbemClassObject. Aby uzyskać więcej informacji, zobacz Wyliczanie usługi WMI. Aby uzyskać dane asynchronicznie, zobacz Przykład: pobieranie danych WMI z komputera lokalnego asynchronicznie.

    Aby uzyskać więcej informacji na temat wysyłania żądań usługi WMI, zobacz Manipulowanie informacjami o klasach i wystąpieniach, wykonywanie zapytań dotyczących usługi WMIi wywoływanie metody.

  8. Ustaw zabezpieczenia serwera proxy IEnumWbemClassObject enumeratora. Pamiętaj o wymazaniu poświadczeń z pamięci po zakończeniu ich używania.

    Aby uzyskać więcej informacji, zobacz Setting the Security on IWbemServices and Other Proxyxies.

  9. Pobierz i wyświetl dane z zapytania WQL. Wskaźnik IEnumWbemClassObject jest połączony z obiektami danych zwracanymi przez zapytanie, a obiekty danych można pobrać za pomocą metody IEnumWbemClassObject::Next. Ta metoda łączy obiekty danych z wskaźnikiem IWbemClassObject przekazywanym do metody . Użyj metody IWbemClassObject::Get, aby uzyskać żądane informacje z obiektów danych.

    Poniższy przykład kodu służy do pobierania właściwości Name z obiektu danych, który zawiera nazwę systemu operacyjnego.

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

    Gdy wartość właściwości Name jest przechowywana w zmiennej VARIANTvtProp, można ją następnie wyświetlić użytkownikowi.

    Poniższy przykład kodu pokazuje, jak zmienna VARIANT może służyć ponownie do przechowywania i wyświetlania wartości wolnej pamięci fizycznej.

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

    Aby uzyskać więcej informacji, zobacz Wyliczanie usługi WMI.

Poniższy przykład kodu przedstawia sposób semisynchronicznego pobierania danych usługi WMI z komputera zdalnego.

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