4 рисунка

WMI.NET: путь к системе

Путешествие в мир системной информации Windows



Михаил Перов



Что такое WMI?



В 1998 г. корпорации Cisco, Compaq, Intel, Microsoft и BMC Software выступили с инициативой создания единого интерфейса для управления предприятием, выполненного на основе веб-технологий. Позднее аббревиатура WBEM (Web-Based Enterprise Management) поменялась на CIM (Common Information Model), единая расширяемая объектная компьютерная структура.

Не осталась в стороне и Microsoft, предложившая технологию WMI (Windows Management Instrumentation) -- фундаментальное решение для централизованного управления и слежения за работой различных частей компьютерной сети под управлением Windows. Технология оказалась очень полезной для администраторов и разработчиков программного обеспечения. Изначально ее было удобно применять для администрирования компьютеров через Windows Script Host. Сейчас доступ к WMI имеется в современной оболочке Power Shell, также ничто не мешает использовать компоненты WMI чисто «программистским» путем, например в проектах C++. А с появлением Delphi Prism полноценная возможность работы с WMI стала доступна и Delphi-программистам.

 

Архитектура WMI

Главный компонент WMI -- менеджер объектов CIM (Common Information Model Object Manager, CIMOM). Он обрабатывает все запросы, приходящие к WMI от конечных приложений, и отвечает за доставку результата в виде подготовленного объекта с ответной информацией. В Windows имеется утилита winmgmt.exe (находится в папке …System32wbem), выполняющая такую задачу в режиме системной службы. Если вы не нашли эту программу, то смело идите на сайт Microsoft за инсталляционным файлом wmicore.exe.

У менеджера CIM имеется хранилище классов -- отдельная база данных. Каждый класс CIM описывает какую-то сущность и содержит соответствующие свойства и методы для работы с ней. Большинство таких классов хранится в MOF-файлах (Managed Object Format). Когда потребитель (например, какое-то клиентское приложение) отправляет в WMI запросы, то получает в ответ экземпляры этих классов. Потребитель получает результат в виде объекта от соответствующего провайдера WMI. Таким образом, вся внутренняя кухня скрыта от пользователя, на поверхности только удобная структурированная информация для мониторинга интересующей его части компьютерной инфраструктуры. Кроме того, существуют средства WMI SDK, для того чтобы независимые разработчики могли создавать собственные провайдеры WMI.

Клиентское приложение способно осуществить запрос к WMI на получение информации о любом удаленном компьютере, поддерживающем данную технологию, и после соединения с соответствующим CIMOM получить ответ. Им могут быть данные об аппаратном обеспечении и его конфигурации, о настройках операционной системы, системных событиях, службах, процессах. Для удобства также существует специальный язык запросов WMI -- это WQL. Его смело можно называть SQL для WMI, потому что он создан как подмножество ANSI SQL (http://msdn.microsoft.com/en-us/library/aa394606(VS.85).aspx).

Пример запроса WQL:

SELECT * FROM meta_class WHERE __this ISA "Win32_BaseService"



Такой запрос позволяет получить всю информацию об элементах, содержащихся в классе Win32_BaseService, дающем доступ к информации о системных службах и драйверах. Иначе говоря, класс может выдать список, куда входит «любой процесс или услуга, которая не принадлежит конкретному пользователю и обеспечивает интерфейс для некоторых функций при поддержке компьютерной системы» (http://msdn.microsoft.com/en-us/library/aa394073(VS.85).aspx).

А чтобы узнать, к каким еще объектам допустимо обращаться в данной системе, достаточно набрать в консоли команду:

wmic alias list brief

Результаты работы команды можно вывести в файл, например

wmic product list brief > c:products.tsv





>>>>Схема

Рис. 1. Основные составляющие технологии WMI



WMI.NET

Утилита WMI реализована на платформах Win32, Win64 и .NET. Наибольший интерес представляет, конечно же, доступ к WMI через программную платформу .NET. Программисту предоставляется специальное пространство имен System.Management, а также System.Management.Instrumentation, благодаря чему можно осуществлять программные обращения к менеджеру WMI из клиентских приложений.

Рассмотрим несколько примеров работы с WMI в среде Delphi Prism. В первом примере получим информацию о процессоре локальной машины.



Листинг 1

Выводим в консоль информацию о процессоре

namespace ConsoleApplication1;



interface

uses System.Management;

type

  ConsoleApp = class

  public

    class method Main;

  end;



implementation



//Получаем краткую информацию о процессоре



class method ConsoleApp.Main;

begin

 var processClass:=new ManagementClass("Win32_Processor");

           

   for each o:ManagementObject in processClass.GetInstances() do begin

          

      Console.WriteLine(" {0} {1} ", o["Name"],o["Description"]);



      Console.ReadLine;

  end;

end;

end.



Оказалось, для того чтобы пример заработал, мало использовать пространство имен System.Management, необходимо еще в лоб указать среде разработки (MS Visual Studio 2008) ссылку на соответствующую сборку. Ее нужно выбрать из списка в окне .NET, которое откроется после выбора команды Solusion Explorer->Solusion->ConsoleApplication1->References->Add Reference

Первое, что мы сделали в программе, -- использовали класс ManagementClass для указания интересующей нас информации. Этот класс и подарил нам необходимый экземпляр в соответствии с аргументом, указанным в конструкторе. Для разминки можно получить описание свойств необходимого нам объекта в виде XML, набрав в командной строке волшебную команду:

wmic /namespace: ootcimv2 class Win32_Processor

WMIC -- это реализация поддержки WMI через командную строку. Работает она в Windows XP/ Server 2003/ Server 2008.

А чтобы получить уже живые данные, чуть-чуть изменим запрос:

wmic /namespace: ootcimv2 path Win32_Processor

Или сразу из командной строки, не написав отдельную программу, отправим готовую информацию в файл:

wmic /namespace: ootcimv2 path Win32_Processor > C:proc.tsv

Как видно, сам по себе командный интерфейс без дополнительного программирования -- серьезное средство для работы с системой.

Используя WMIC, можно уже без дополнительных инструментов управлять несколькими машинами с разными версиями Microsoft Windows. Неблокирующая реализация (т.е. когда программа не задерживается в ожидании какого-либо ответа со стороны клиента) данной команды позволяет успешно использовать ее в скриптах и командных файлах. Чтобы более подробно узнать об этой команде, обратитесь к справочной системе Windows или, к примеру, к http://technet.microsoft.com/ru-ru/library/cc784966.aspx либо просто наберите в командной строке Wmic -?.

Кстати, если формат вывода данных вас раздражает, поменяйте настройки командной строки (рис. 2).



[Рис. CMD]

Рис. 2. Настройки командной строки



Вернемся к нашему примеру. Мы получили объект, который формально может содержать в себе целую коллекцию. Для перебора этой коллекции используем метод GetInstances. И теперь мы, наконец, добрались до самих данных, которые оказались представлены всего одной строкой (рис. 3).



[Рис. Ex1]

Рис. 3. Результат работы первого примера



К сожалению, нам не удалось запустить программу под управлением платформы Mono ни в Windows, ни в Linux, хотя в Delphi Prism имеется возможность делать сборки, специально заточенные под Mono. Очевидно, в данном случае проблема явно связана с System.Management.dll.

У проекта Mono есть интересная веточка -- MoMA -- Mono Migration Analizer (http://mono-project.com/MoMA) . Эта утилита просто констатировала факт непригодности программы для платформы Mono, хотя сборка и была сделана как раз для нее.



[Рис.  Moma_Result]

Рис. 4. Результат работы утилиты MoMA



Судя по тому, как обсуждалась проблема на форуме разработчиков Mono (http://go-mono.com/), кривые руки оказались не только у автора статьи. Но до сих пор ее решение не найдено.



Во втором примере мы опять получим системную информацию, но на этот раз с помощью языка WQL.

 

Листинг 2

Применение языка WQL для получения системной информации:



namespace ConsoleApplication1;



interface

uses

  System.Management;

type

  ConsoleApp = class

  public

    class method Main;

  end;



implementation



//Получаем информацию о системе с использованием WMI

class method ConsoleApp.Main;

begin



            var co:=new ConnectionOptions();



            var ms:=new System.Management.ManagementScope('127.0.0.1', co);



            var oq:=new System.Management.ObjectQuery('SELECT * FROM Win32_OperatingSystem');



            var query1:=new ManagementObjectSearcher(ms, oq);



             var  queryCollection1:ManagementObjectCollection:=query1.Get();



            for each  mo:ManagementObject in queryCollection1 do begin

                Console.WriteLine('Name : ' + mo['name'].ToString);

                Console.WriteLine('Version : ' + mo['version'].ToString);

                Console.WriteLine('Manufacturer : ' + mo['Manufacturer'].ToString);

                Console.WriteLine('Computer Name : ' + mo['csname'].ToString);

                Console.WriteLine('Windows Directory : ' + mo['WindowsDirectory'].ToString);

           end;



            oq:=new System.Management.ObjectQuery('SELECT * FROM Win32_ComputerSystem');

            query1:=new ManagementObjectSearcher(ms, oq);

            queryCollection1:=query1.Get();



            for each  mo:ManagementObject in queryCollection1 do begin



                Console.WriteLine(mo['systemtype'].ToString);

                Console.WriteLine('Total Physical Memory : ' + mo['totalphysicalmemory'].ToString);

            end;



            oq:=new System.Management.ObjectQuery('SELECT * FROM Win32_bios');

            query1:=new ManagementObjectSearcher(ms, oq);

            queryCollection1:=query1.Get();



            for each  mo:ManagementObject in queryCollection1 do begin



                Console.WriteLine('BIOS VERSION: '+mo['version'].ToString);



            end;



  Console.ReadLine;

end;

 

end.



В этом примере использован класс System.Management.ManagementScope.

В официальном руководстве сухо сказано, что он «представляет область (пространство имен) для управляющих операций» (http://msdn.microsoft.com/ru-ru/library/system.management.managementscope.aspx). Значит, в атрибутах объекта данного класса мы должны указать, к какому источнику информации хотим подключиться.

В WMI принцип организации доступа к информации сильно напоминает работу с базой данных. Запрос на получение нужной информации используется в классе System.Management.ObjectQuery, название которого говорит само за себя. Данные о требуемом источнике системной информации и о запросе объединяются вместе в промежуточном классе ManagementObjectSearcher. Экземпляр этого класса и осуществляет необходимый нам запрос через метод Get().На таком принципе построены все три запроса примера.

Следующий пример демонстрирует использование возможностей класса Win32_LogicalDisk. Здесь мы получаем уже несколько строк в ответе, так что воспользуемся оператором for each.



Листинг 3

Получение информации о дисках:



namespace ConsoleApplication1;



interface

uses

  System.Management;

type

  ConsoleApp = class

  public

    class method Main;

    class method PrintDisksStat();

  end;



implementation



//Получаем информацию о дисках

class method ConsoleApp.Main;

begin



PrintDisksStat();

System.Console.ReadLine;



end;

class method ConsoleApp.PrintDisksStat();

begin



// Формулируем запрос

var DiskQuery:=new System.Management.ObjectQuery('select FreeSpace, FileSystem, Size, Name, VolumeName, VolumeSerialNumber from Win32_LogicalDisk where DriveType = 3');



// Создаем "искатель" информации

var DiskSearcher:=new ManagementObjectSearcher(DiskQuery);



//Получаем ответ

var DiskCollection:=DiskSearcher.Get();



for each DiskInfo:ManagementObject in DiskCollection do begin

begin



    Console.WriteLine('-----------------------------------------');



    Console.WriteLine('Имя диска: ' + DiskInfo['Name'].ToString);

    Console.WriteLine('Размер диска: ' + DiskInfo['Size'].ToString);

    Console.WriteLine('Название тома: ' + DiskInfo['VolumeName'].ToString);

    Console.WriteLine('Файловая система: ' + DiskInfo['FileSystem'].ToString);

    Console.WriteLine('Свободное место: ' + DiskInfo['FreeSpace'].ToString);

    Console.WriteLine('Серийный номер тома: ' + DiskInfo['VolumeSerialNumber'].ToString);



end;

end;

end;



end.



Последний пример демонстрирует применение WMI для извлечения данных о пользователях и группах локальной системы. В нем применяется класс SelectQuery, еще более упрощающий использование запроса типа SELECT.



Листинг 4

Извлечение информации о пользователях и группах:

namespace ConsoleApplication1;

interface

uses

 System.Management;

type

  ConsoleApp = class

  public

    class method Main;

    class method GetUsers();

    class method GetGroups();

  end;



implementation



//Перечисляем пользователей и группы, применив WMI.NET



class method ConsoleApp.Main;

begin



  Console.WriteLine('GetUsers');Console.WriteLine('');

  GetUsers();                   Console.WriteLine('');

  Console.WriteLine('GetGroups');Console.WriteLine('');

  GetGroups();

  Console.ReadLine;



end;



class method ConsoleApp.GetUsers();

begin



        var sQuery:=new SelectQuery('Win32_UserAccount');

                       

            try

                var mSearcher:=new ManagementObjectSearcher(sQuery);



               for each mObject:ManagementObject in mSearcher.Get() do begin



                    Console.WriteLine(mObject['Name']);



                end;



            except on ex:Exception do begin

               Console.WriteLine(ex.ToString());

                end;

            end;



end;



class method ConsoleApp.GetGroups();

begin



        var sQuery:=new SelectQuery('Win32_Group');

            try

                var mSearcher:=new ManagementObjectSearcher(sQuery);

               for each mObject:ManagementObject in mSearcher.Get() do begin

                    Console.WriteLine(mObject['Name']);

                end;



            except on ex:Exception do begin

               Console.WriteLine(ex.ToString());

                end;

            end;



end;

end.



* * *

В этой статье мы рассмотрели отдельный спектр задач -- извлечение системной информации из локальной машины. Но сам интерфейс WMI предполагает функции управления как для локальной машины, так и для группы компьютеров.

WMI.NET -- удобный вариант программного доступа к компьютерным системам на базе Windows XP/Vista/ Server 2003/Server 2008. Технология WMI отличается своей универсальностью, относительной простотой и интегрируемостью.