Администрирование с помощью WMI

Содержание

Что такое WMI

Windows Management Instrumentation (WMI) в дословном переводе - это инструментарий управления Windows. Если говорить более развернуто, то WMI - это одна из базовых технологий для централизованного управления и слежения за работой различных частей компьютерной инфраструктуры под управлением платформы Windows. Технология WMI - это расширенная и адаптированная под Windows реализация стандарта WBEM, принятого многими компаниями, в основе которого лежит идея создания универсального интерфейса мониторинга и управления различными системами и компонентами распределенной информационной среды предприятия с использованием объектно-ориентированных идеологий и протоколов HTML и XML.

В основе структуры данных в WBEM лежит Common Information Model (CIM), реализующая объектно-ориентированный подход к представлению компонентов системы. CIM является расширяемой моделью, что позволяет программам, системам и драйверам добавлять в нее свои классы, объекты, методы и свойства.

WMI, основанный на CIM, также является открытой унифицированной системой интерфейсов доступа к любым параметрам операционной системы, устройствам и приложениям, которые функционируют в ней.

Важной особенностью WMI является то, что хранящиеся в нем объекты соответствуют динамическим ресурсам, то есть параметры этих ресурсов постоянно меняются, поэтому параметры таких объектов не хранятся постоянно, а создаются по запросу потребителя данных. Хранилище свойств объектов WMI называется репозиторием и расположено в системной папке операционной системы Windows:

%SystemRoot%\System32\WBEM\Repository\FS

Классы, события и безопасность WMI

Так как WMI построен по объектно-ориентированному принципу, то все данные операционной системы представлены в виде объектов и их свойств и методов.

Все классы группируются в пространства имен, которые иерархически упорядочены и логически связаны друг с другом по определенной технологии или области управления. В WMI имеется одно корневое пространство имен Root, которое в свою очередь имеет 4 подпространства: CIMv2, Default, Secutiry и WMI.

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

Свойства классов используются для однозначной идентификации экземпляра класса и для описания состояния используемого ресурса. Обычно все свойства классов доступны только для чтения, хотя некоторые из них можно модифицировать определенным методом. Методы классов позволяют выполнить действия над управляемым ресурсом.

Каждому экземпляру класса можно обратиться по полному пути, который имеет следующую структуру:

[\\ComputerName\NameSpace][:ClassName][.KeyProperty1=Value1][,KeyProperty2=Value2]…]
где
  ComputerName - имя компьютера
  NameSpace - название пространства имен
  ClassName - имя класса
  KeyProperty1=Value1, KeyProperty2=Value2 - свойства объекта и значения, по
    которым он идентифицируется.

Пример обращения к процессу с именем "Calc.exe", который запущен на локальной машине:

\\.\CIMv2:Win32_Process.Name="Calc.exe"

Экземпляры классов могут генерировать события, к которым можно подписываться. При наступлении события WMI автоматически создает экземпляр того класса, которому соответствует это событие. Такой механизм удобно использовать для выполнения определенной команды при наступлении определенного события, то есть следить за состоянием объектов операционной системы.

Общая безопасность в WMI реализуется на уровне операционной системы, а дополнительная политика безопасности основана на уровнях пространств имен и протокола DCOM. То есть если пользователь не имеет права делать какое-то действие через операционную систему, он не сможет это сделать и через WMI. Если же пользователю дано какое-то право в операционной системе, то это еще не означает, что это право будет и в WMI, так как в WMI действуют дополнительные параметры безопасности на уровне пространств имен.

Каждый объект операционной системы имеет свое описание безопасности (SD) со своим списком доступа (ACL), в котором перечислены идентификаторы пользователей (SID) и их привилегии. Каждое пространство имен может иметь собственное SD со своим ACL, где пользователям могут быть назначены разрешения на чтение данных, выполнение методов, запись классов и данных и другие. Данные о дополнительных разрешениях хранятся в репозитории WMI. Отдельные классы из пространств имен не имеют собственных описаний безопасности, они наследуют их от своего пространства имен.

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

Для доступа к инфраструктуре WMI используется протокол DCOM, через который пользователь подключается к WMI. Чтобы определить, какие права будут у подключившегося пользователя, используется механизмы олицетворения и аутентификации протокола DCOM.

Уровни олицетворения могут принимать следующие значения:

Anonymous Анонимный WMI-объект не может получить информацию о пользователе - доступ по такому типу не предоставляется
Identify Идентификация WMI-объект запрашивает маркер доступа пользователя - доступ предоставляется только локально
Impersonate Олицетворение WMI-объект имеет такие же права, какие имеет пользователь - рекомендуемый уровень для выполнения команд на удаленном компьютере
Delegate Делегирование WMI-объект может обратиться от имени пользователя к другому WMI-объекту - нерекомендуемый уровень, так как команды можно выполнять удаленно через цепочку из нескольких компьютеров

Уровни аутентификации (подлинности) могут принимать следующие значения:

None Отсутствует Проверка подлинности отсутствует
Default По умолчанию Стандартные настройки безопасности, которые задаются компьютером-целью команды
Connect Подключение Проверка только во время подключения к компьютеру-цели команды, проверка в ходе работы отсутствует
Call Вызов Проверка подлинности при каждом запросе к компьютеру-цели команды, заголовки пакетов подписываются, но содержимое не шифруется
Pkt Пакет Проверка подлинности всех пакетов к компьютеру-цели команды, заголовки пакетов подписываются, но содержимое не шифруется
PktIntegrity Целостность пакета Проверка подлинности и целостности всех пакетов к компьютеру-цели команды, заголовки пакетов подписываются, но содержимое не шифруется
PktPrivacy Секретность пакета Проверка подлинности и целостности всех пакетов к компьютеру-цели команды, заголовки и содержимое пакетов подписываются и шифруются

Средства работы с WMI

wmimgmt.msc - оснастка консоли управления MMC для настройки WMI на локальном компьютере.

wmimgmt.png
Оснастка консоли управления MMC для настройки WMI

winmgmt.exe - консольная утилита управления WMI локального компьютера.

winmgmt.png
Консольная утилита управления WMI

wbemtest.exe - графическая утилита для взаимодействия со структурой WMI на локальном или удаленном компьютере.

wbemtest.png
Графическая утилита для взаимодействия со структурой WMI

wmic.exe - консольная утилита для взаимодействия со структурой WMI на локальном компьютере.

wmic.png
Консольная утилита для взаимодействия со структурой WMI

mofcomp.exe - компилятор MOF-файлов для расширения структуры WMI, управления библиотекой классов WMI и восстановления репозитория.

mofcomp.png
Компилятор MOF-файлов для расширения структуры WMI

Язык запросов WMI

Для обращения к объектам WMI используется специфический язык запросов WMI Query Language (WQL), который является одним из разновидностей SQL. Основное его отличие от ANSI SQL - это невозможность изменения данных, то есть с помощью WQL возможна лишь выборка данных с помощью команды SELECT. Помимо ограничений на работу с объектами, WQL не поддерживает такие операторы как DISTINCT, JOIN, ORDER, GROUP, математические функции. Конструкции IS и NOT IS применяются только в сочетании с константой NULL.

Запросы WQL обычно применяются в скриптах, но их также можно протестировать в программе Wbemtest и в консольной утилите Wmic (утилита wmic не требует написания ключевого слова SELECT и полей выборки)

Общий синтаксис запроса WQL выглядит так:

SELECT свойства FROM имя_класса WHERE свойство оператор значение

Например:

' Выбрать все значения класса Win32_Product и вывести все его свойства
SELECT * FROM Win32_Product
' Выбрать все значения класса Win32_Product и вывести свойство Version
SELECT Version FROM Win32_Product
' Выбрать значения класса Win32_Product, где свойство Description равно
' "Microsoft Office", и вывести свойство Version
SELECT Version FROM Win32_Product WHERE Description = "Microsoft Office"

Как видно из примеров, оператор FROM - это источник (класс), коллекцию экземпляров которого нужно получить, а оператор WHERE - это фильтр в запросе.

Использование WMI в сценариях

Подключение к WMI

В скриптах для подключения к WMI используются два метода: с использованием локатора (SWbemLocator) и с использованием моникера (WinMgmts). Метод локатора позволяет установить соединие с пространством имен от имени определенной учетной записи. Метод моникера разрешает подключаться к WMI только от имени текущей учетной записи.

Подключение методом локатора

Использование этого метода необходимо, когда в сценарии нужно явно задать имя и пароль учетной записи для подключения к WMI. Объект SWbemLocator создается так:

Set mSWbemLocator = CreateObject("WbemScripting.SWbemLocator")

Подключение к репозиторию WMI производится с помощью метода ConnectServer:

mSWbemServices = mSWbemLocator.ConnectServer([ServerName], [NameSpace], [User], _
  [Password], [Locate], [Authority], [SecurityFlags], [WbemNamedValueSet])
где
  ServerName - имя компьютера (если не указано, то локальный компьютер),
  NameSpace - пространство имен (если не указано, то пространство по умолчанию),
  User - имя пользователя в формате Домен\УчетнаяЗапись (если не указано, то текущий
    пользователь),
  Password - пароль указанного пользователя,
  Locate - код локализации (если не указано, то текущий язык),
  Authority - имя домена, если он не указан в параметре User (если не указано, то
    текущий домен),
  SecurityFlags - время ожидания подключения,
  WbemNamedValueSet - контекстная информация для провайдера, который используется
    для запроса.

Безопасность объекта указывается с помощью свойства Security_, в котором указывается уровень олицетворения и привилегии.

Пример использования локатора:

' Создание объекта
Set mSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
' Задание уровня аутентификации (6 - секретность пакетов)
mSWbemLocator.Security_.AuthenticationLevel = 6
' Задание уровня олицетворения (3 - олицетворение)
mSWbemLocator.Security_.ImpersonationLevel = 3
' Добавление привелегии (разрешение завершать работу)
mSWbemLocator.Security_.Privileges.AddAsString("SeShutdownPrivilege")
' Подключение к репозиторию
Set mSWbemServices = mSWbemLocator.ConnectServer(".", "Root\CIMv2",,,,, 128)

Подключение методом моникера

Моникер - это строка, задающая путь к классу WMI, экземпляр которого должен быть создан. Моникер состоит из обязательного префикса "winmgmts:", необязательных настроек безопасности, необязательного пути к требуемому классу:

Set mSWbemServices = GetObject("winmgmts:[{SecurityOptions}!]\\[Server]\[NameSpace]")

Пример использования моникера:

' Подключение к пространству имен по умолчанию локального компьютера
Set mSWbemServices0 = GetObject("winmgmts:")

' Подключение к указанному пространству имен удаленного компьютера
' с указанием метода олицетворения
Set mSWbemServices1 = GetObject("winmgmts:{impersonationLevel=Impersonate}!" & _
  "\\MyComputer\Root\CIMv2")

' Подключение к указанному объекту локального компьютера
' с указанием метода олицетворения и привилегий
Set mSWbemServices2 = GetObject("winmgmts:" & _
  "{impersonationLevel=Impersonate, (Shutdown, RemoteShutdown)}!" & _
  "\\.\Root\CIMv2:Win32Process.Handle=4")

' Подключение к указанному объекту локального компьютера
Set mSWbemServices3 = GetObject("winmgmts:\\.\Root\CIMv2:Win32Process.Handle=4")

Использование объекта репозитория

В результате подключения к WMI получается объект SWbemServices, который обладает определенными свойствами и методами. Наиболее часто используемые из них - это Get, ExecQuery, ExecMethod.

Метод Get используется для возвращения определения класса или экземпляра управляемого ресурса:

Set mObject = Get([ObjectPath],[Flags],[WbemNamedValueSet])
где
  ObjectPath - путь к объекту WMI,
  Flags - опции,
  WbemNamedValueSet - контекстная информация для провайдера.

Пример использования метода Get:

' Подключение к пространству имен
Set mSWbemServices = GetObject("winmgmts:\\.\Root\CIMv2")
' Получение экземпляра класса с заданным свойством
Set mProcess = mSWbemServices.Get("Win32_Process.Handle=4")

Метод ExecQuery используется для выполнения запросов на языке WQL:

Set mObject = ExecQuery(Query,[QueryLanguage],[Flags],[WbemNamedValueSet])
где
  Query - текст запроса,
  QueryLanguage - язык запроса (всегда равен "WQL")
  Flags - опции,
  WbemNamedValueSet - контекстная информация для провайдера.

Пример использования метода ExecQuery:

' Подключение к пространству имен
Set mSWbemServices = GetObject("winmgmts:\\.\Root\CIMv2")
' Получение всех экземпляров класса с заданным свойством
Set mProcesses = mSWbemServices.ExecQuery("SELECT * FROM Win32_Process WHERE Handle = 4")

Метод ExecMethod используется для выполнения метода указанного объекта:

Set mObject = ExecMethod(ObjectPath, MethodName,[InParams],[Flags],[WbemNamedValueSet])
где
  ObjectPath - путь к объекту WMI,
  MethodName - имя метода,
  InParams - входные параметры для метода,
  Flags - опции (всегда равно нулю),
  WbemNamedValueSet - контекстная информация для провайдера.

Пример использования метода ExecMethod:

' Подключение к пространству имен
Set mSWbemServices = GetObject("winmgmts:\\.\Root\CIMv2")
' Получение указателя на класс
Set mProcess = mSWbemServices.Get("Win32_Process")
' Создание коллекции входных параметров для метода
Set mInParams = mProcess.Methods_("Create").InParameters.SpawnInstance_
mInParams.CommandLine = "notepad.exe"
' Выполнение метода
Set mOutParams = mSWbemServices.ExexMethod("Win32_Process", "Create", mInParams)

Указанные выше методы работают в синхронном и полусинхронном режиме, то есть программа или сценарий не выполняет следующую команду или запрос до тех пор, пока не получит ответ от текущего запущенного метода.

Асинхронное использование объектов репозитория

Аналогично синхронным методам WMI позволяет выполнять команды асинхронно, то есть не дожидаться результатов выполнения очередного запроса и продолжать работу сценария или программы. Названия таких асинхронных методов имеют окончание "Async", а работа с ними почти не отличается от обычных методов, но должны быть использованы два обязательных параметра: ссылка на специальный объект "слив событий" и контекстная информация объекта.

Объект "слива событий" (от английского "sink" - раковина) создается следующим образом:

Set mSink = WScript.CreateObject("WbemScripting.SWbemSink", "Sink_")
где
  Sink_ - префикс для функций.

Наиболее часто используемые события, обрабатываемые таким "сливом" асинхронных методов, - это OnObjectReady и OnCompleted. Как можно догадаться из названий событий, первое происходит, когда возвращается очередной объект, порожденный асинхронным запросом. Второе происходит после полного завершения асихронного метода. Событие OnObjectReady выдает на выход объект, который был запрошен асихронной операцией, а событие OnCompleted - код ошибки или 0.

Пример использования асинхронного метода:

' Подключение к пространству имен
Set mSWbemServices = GetObject("winmgmts:\\.\Root\CIMv2")
' Создание объекта "слива событий"
Set mSink = WScript.CreateObject("WbemScripting.SWbemSink", "Sink_")
' Флаг завершения асинхронного метода
mCompleted = False
' Вызов асинхрнонного запроса
mSWbemServices.ExecQueryAsync mSink, "SELECT * FROM Win32_Process"
' Зацикливание скрипта до окончание запроса (здесь можно выполнять любые другие операции)
' Как только асинхронный метод вернет какое-нибудь событие, то будет вызвана
' соотвествующая процедура, которая описана ниже, а работа основного скрипта на время
' прервется
While Not mCompleted
    WScript.Sleep 1000
Wend
' Процедура обработки события возврата очередного объекта
Sub Sink_OnObjectReady(mWbemObject, mWbemAsyncContext)
    WScript.Echo mWbemObject.Name
End Sub
' Процедура обработки события завершения запроса
Sub Sink_OnCompleted(mResult, mWbemErrorObject, mWbemAsyncContext)
    If mResult = 0 Then
        WScript.Echo "Запрос успешно завершен"
    Else
        WScript.Echo "Запрос завершен с ошибкой"
    End If
    mCompleted = True
End Sub

Работа с объектами и коллекциями объектов, полученных в результате запросов

Рассмотренные выше методы возвращают объекты и коллекции объектов, которые обладают своими методами и свойствами. Информацию о всех свойствах и методах, поддерживаемых конкретным объектом, можно получить с помощью такого скрипта:

' Объект mObject получен методом Get
' Получение свойств и их значений
For Each mCurrentProperty in mObject.Properties_
    Wscript.Echo mCurrentProperty.Name & ": " & mCurrentProperty.Value
Next
' Получение методов
For Each mCurrentMethod in mObject.Methods_
    Wscript.Echo mCurrentMethod.Name
Next

Коллекция объектов всегда обладает общими для всех экземпляров свойствами, наиболее часто используемые свойства - это Count и Item.

Count - это свойство коллекции объекта, которое содержит количество элементов коллекции.

Item(mObjectPath) - это метод, который возвращает один объект коллекции, соответствующий указанному пути.

Как уже выяснилось, объект имеет свои методы и свойства, которые соответствуют классу данного экземпляра, но помимо классовых свойств и методов всем объектам присущи универсальные, которые оканчиваются на символ подчеркивания, чтобы отличать их от классовых. Наиболее часто используемые универсальные методы - это ExecMethod_ и Put_.

ExecMethod_(mMethod, mWbemInParamsm, mFlags, mWbemNamedValueSet) - это метод для исполнения классового метода у используемого объекта.

Put_(mFlags, mWbemNamedValueSet) - это метод для записи измененных свойств объекта в репозиторий WMI и в реальный объект.

Пример использования метода Put_ - изменение метки диска:

' Подключение к пространству имен
Set mSWbemServices = GetObject("winmgmts:\\.\Root\CIMv2")
' Получение объекта логического диска
Set mDisks = mSWbemServices.ExecQuery("SELECT * FROM Win32_LogicalDisk WHERE DeviceID = 'C:'")
' Перебор коллекции возвращенных объектов
For Each mDisk in mDisks
    ' Смена метки диска
    oDisk.VolumeName = "System"
    ' Запись изменений
    oDisk.Put_
Next

Примеры сценариев на VBScript

Пример использование класса CIM_DataFile для переименования файлов:

' Целевой компьютер
mComputer = "."
' Целевая папка
mFolderPath = "C:\Temp"
' Подключение к пространству имен целевого компьютера
Set mSWbemServices = GetObject("winmgmts:\\" & mComputer & "\Root\CIMv2")
' Получение колекции файлов целевой папки
Set mFileList = mSWbemServices.ExecQuery ("ASSOCIATORS OF {Win32_Directory.Name='" _
  & mFolderPath & "'} WHERE ResultClass = CIM_DataFile")
' Обработка коллекции файлов
For Each mCurrentFile In mFileList
    ' Формирование нового имени файла
    mNewName = mCurrentFile.Drive & mCurrentFile.Path & mCurrentFile.FileName _
      & "." & mCurrentFile.Extension & ".old"
    ' Переименование файла
    errResult = mCurrentFile.Rename(mNewName)
    ' Формирование отчета о переименовании
    if errResult = 0 then
        mResultText = mResultText & "File " & mCurrentFile.Name & " renamed to " _
          & mNewName & vbCrLf
    else
        mResultText = mResultText & "Error at renaming " & mCurrentFile.Name & _
          " file" & vbCrLf
        errResult = 0
    end if
Next
' Вывод отчета о переименовании
Wscript.Echo(mResultText)

Аналогично приведенному примеру можно совершать и другие действия с файлами, так как класс CIM_DataFile поддерживает методы: копирование, удаление, переименование, NTFS-сжатие, смена разрешений, смена владельца.

Пример использования классов оборудования компьютера для получения информации о количестве портов USB 2.0 и используемых USB-устройствах:

iCounter = 0
' Целевой компьютер
mComputer = "."
' Подключение к пространству имен целевого компьютера
Set mSWbemServices = GetObject("winmgmts:\\" & mComputer & "\Root\CIMv2")
' Получение колекции USB-контроллеров
Set mControllerList = mSWbemServices.ExecQuery("Select * From Win32_USBController")
' Обработка USB-контроллеров
For Each mCurrentController in mControllerList
    If Instr(mCurrentController.Name, "Enhanced") Then
        iCounter = iCounter + 1
    End If
Next
' Формирование отчета о USB-контроллерах
mResultText = "USB 2.0 Ports count: " & iCounter & vbCrLf & vbCrLf
' Получение колекции USB-устройств
Set mDeviceList = mSWbemServices.ExecQuery ("Select * From Win32_USBControllerDevice")
' Обработка USB-устройств
For Each mCurrentDevice in mDeviceList
    mDeviceName = mCurrentDevice.Dependent
    mDeviceName = Replace(mDeviceName, Chr(34), "")
    mDeviceNames = Split(mDeviceName, "=")
    mDeviceName = mDeviceNames(1)
    ' Получение свойств каждого устройства по его идентификатору
    Set mUSBDeviceList = mSWbemServices.ExecQuery("Select * From Win32_PnPEntity " _
      & "Where DeviceID = '" & mDeviceName & "'")
    ' Обработка свойств устройства
    For Each mCurrentUSBDevice in mUSBDeviceList
        ' Формирование отчета о USB-устройствах
        mResultText = mResultText & mCurrentUSBDevice.Description & vbCrLf
    Next    
Next
' Вывод результата
Wscript.Echo(mResultText)

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

' Целевой компьютер
mComputer = "."
' Задание констант кодов типов доступа к текстовому файлу
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8 
' Создание объекта оболочки и получение текущей директории
Set oShell = CreateObject("wscript.shell")
sWorkDirectory = oShell.CurrentDirectory
' Создание объекта файловой системы и файла
Set oFSO = CreateObject ("Scripting.FileSystemObject")
Set mResultFile = oFSO.OpenTextFile(sWorkDirectory & "\PrinterList.txt", ForWriting, True, 0)
' Подключение к пространству имен целевого компьютера
Set mSWbemServices = GetObject("winmgmts:\\" & mComputer & "\Root\CIMv2")
' Получение колекции локальных принтеров
Set mPrinterList = mSWbemServices.ExecQuery("SELECT * FROM Win32_Printer WHERE Local = True")
' Запись заголовка в файл
mResultFile.WriteLine("Name;Comment;Location;ShareName;DriverName;PortName;")
' Обработка каждого принтера
For Each mCurrentPrinter in mPrinterList
    mResultFile.WriteLine(mCurrentPrinter.Name & ";" & mCurrentPrinter.Comment & ";" & _
      mCurrentPrinter.Location & ";" & mCurrentPrinter.ShareName & ";" & _
      mCurrentPrinter.DriverName & ";" & mCurrentPrinter.PortName & ";")
Next
' Закрытие файла
mResultFile.Close

Пример использования класса свойств сетевого адаптера для изменения конфигурации сетевой карты - перевода с DHCP на статическую конфигурацию:

' Целевой компьютер
mComputer = "."
' Новые сетевые параметры задаются конкретными значениями
' Аналогичные параметры задаются значением "The same"
' Пустые парамеры задаются значением ""
mNewIPAddress = "The same"
mNewSubnetMask = "The same"
mNewDNSServer = "The same"
mNewDefaultIPGateway = "The same"
mNewWINSPrimaryServer = "The same"
mNewWINSSecondaryServer = "The same"
' Рабочие массивы
Dim mDNSServerList()
Dim mDefaultIPGatewayList()
Dim mGatewayMetricList()
Dim mNewDNSServerList()
Dim mNewDefaultIPGatewayList()
Dim mNewGatewayMetricList()
' Подключение к пространству имен целевого компьютера
Set mSWbemServices = GetObject("winmgmts:\\" & mComputer & "\Root\CIMv2")
' Получение коллекции адаптеров с указанным IP-адресом
Set mAdapterList = mSWbemServices.ExecQuery ("Select * From Win32_NetworkAdapter")
' Получение MAC-адреса адаптера локального адаптера
For Each mCurrentAdapter In mAdapterList
    If InStr(LCase(mCurrentAdapter.NetConnectionID), "локальн") > 0 _
      Or InStr(LCase(mCurrentAdapter.NetConnectionID), "local") > 0 Then
        mMACAddress = mCurrentAdapter.MACAddress
        mCaption = mCurrentAdapter.Caption
        Exit For
    End If
Next
' Получение коллекции параметров адаптера с указанным MAC-адресом
Set mAdapterConfigList = mSWbemServices.ExecQuery _
  ("Select * From Win32_NetworkAdapterConfiguration WHERE MACAddress = '" _
  & mMACAddress & "'")
' Получение текущих параметров сетевого адаптера с указанным MAC-адресом
For Each mCurrentAdapterConfig In mAdapterConfigList
    ' IP-адрес
    If IsNull(mCurrentAdapterConfig.IPAddress) = False Then
        For Each mCurrentIPAddress In mCurrentAdapterConfig.IPAddress
            mIPAddress = mCurrentIPAddress
            Exit For
        Next
    End If
    If mNewIPAddress = "The same" Then mNewIPAddress = mIPAddress
    mNewIPAddressList = Array(mNewIPAddress)
    ' Маска подсети
    If IsNull(mCurrentAdapterConfig.IPSubnet) = False Then
        For Each mCurrentIPSubnet In mCurrentAdapterConfig.IPSubnet
            mSubnetMask = mCurrentIPSubnet
            Exit For
        Next
    End If
    If mNewSubnetMask = "The same" Then mNewSubnetMask = mSubnetMask
    mNewSubnetMaskList = Array(mNewSubnetMask)
    ' DNS сервера
    If IsNull(mCurrentAdapterConfig.DNSServerSearchOrder) = False Then
        iCounter = 0
        For Each mCurrentDNSServer In mCurrentAdapterConfig.DNSServerSearchOrder
            Redim Preserve mDNSServerList(iCounter)
            mDNSServerList(iCounter) = mCurrentDNSServer
            iCounter = iCounter + 1
        Next
    End If
    If mNewDNSServer = "The same" Then
        For iCounter = 0 To UBound(mDNSServerList)
            Redim Preserve mNewDNSServerList(iCounter)
            mNewDNSServerList(iCounter) = mDNSServerList(iCounter)
        Next
    Else
        For iCounter = 0 To UBound(Split(mNewDNSServer,";"))
            Redim Preserve mNewDNSServerList(iCounter)
            mNewDNSServerList(iCounter) = Split(mNewDNSServer,";")(iCounter)
        Next
    End If
    ' Шлюзы
    If IsNull(mCurrentAdapterConfig.DefaultIPGateway) = False Then
        iCounter = 0
        For Each mCurrentDefaultIPGateway In mCurrentAdapterConfig.DefaultIPGateway
            Redim Preserve mDefaultIPGatewayList(iCounter)
            mDefaultIPGatewayList(iCounter) = mCurrentDefaultIPGateway
            Redim Preserve mGatewayMetricList(iCounter)
            mGatewayMetricList(iCounter) = iCounter + 1
            iCounter = iCounter + 1
        Next
    End If
    If mNewDefaultIPGateway = "The same" Then
        For iCounter = 0 To UBound(mDefaultIPGatewayList)
            Redim Preserve mNewDefaultIPGatewayList(iCounter)
            mNewDefaultIPGatewayList(iCounter) = mDefaultIPGatewayList(iCounter)
            Redim Preserve mNewGatewayMetricList(iCounter)
            mNewGatewayMetricList(iCounter) = iCounter + 1
        Next
    Else
        For iCounter = 0 To UBound(Split(mNewDefaultIPGateway,";"))
            Redim Preserve mNewDefaultIPGatewayList(iCounter)
            mNewDefaultIPGatewayList(iCounter) = Split(mNewDefaultIPGateway,";")(iCounter)
            Redim Preserve mNewGatewayMetricList(iCounter)
            mNewGatewayMetricList(iCounter) = iCounter + 1
        Next
    End If
    ' WINS сервера
    If IsNull(mCurrentAdapterConfig.WINSPrimaryServer) = False Then
        mWINSPrimaryServer = mCurrentAdapterConfig.WINSPrimaryServer
    End If
    If mNewWINSPrimaryServer = "The same" Then
        If IsNull(mCurrentAdapterConfig.WINSPrimaryServer) = True Then
            mNewWINSPrimaryServer = ""
        Else
            mNewWINSPrimaryServer = mWINSPrimaryServer
        End If
    End If
    If IsNull(mCurrentAdapterConfig.WINSSecondaryServer) = False Then
        mWinsSecondaryServer = mCurrentAdapterConfig.WINSSecondaryServer
    End If
    If mNewWinsSecondaryServer = "The same" Then
        If IsNull(mCurrentAdapterConfig.WINSSecondaryServer) = True Then
            mNewWinsSecondaryServer = ""
        Else
            mNewWinsSecondaryServer = mWINSSecondaryServer
        End If
    End If
    Exit For
Next
' Формирование сообщения по текущей и по будущей конфигурациям сетевого адаптера
mInfoMessage = "Network adapter: " & mCaption & vbCrLf _
  & "MAC address: " & mMACAddress & vbCrLf _
  & "Current configuration:" & vbCrLf _
  & vbTab & "IP address: " & mIPAddress & vbCrLf _
  & vbTab & "Subnet mask: " & mSubnetMask & vbCrLf _
  & vbTab & "Default Gateway: " & Join(mDefaultIPGatewayList,";") & vbCrLf _
  & vbTab & "DNS servers: " & Join(mDNSServerList,";") & vbCrLf _
  & vbTab & "WINS Primary Server: " & mWINSPrimaryServer & vbCrLf _
  & vbTab & "WINS Secondary Server: " & mWINSSecondaryServer & vbCrLf _
  & "New configuration:" & vbCrLf _
  & vbTab & "IP address: " & mNewIPAddress & vbCrLf _
  & vbTab & "Subnet mask: " & mNewSubnetMask & vbCrLf _
  & vbTab & "Default Gateway: " & Join(mNewDefaultIPGatewayList,";") & vbCrLf _
  & vbTab & "DNS servers: " & Join(mNewDNSServerList,";") & vbCrLf _
  & vbTab & "WINS Primary Server: " & mNewWINSPrimaryServer & vbCrLf _
  & vbTab & "WINS Secondary Server: " & mNewWINSSecondaryServer & vbCrLf _
  & vbCrLf & "Please confirm the changes" & mNewWINSSecondaryServer & vbCrLf
' Окно подтверждения изменения настроек сетевого параметра
mChangeFlag = MsgBox(mInfoMessage, vbOKCancel, "Network card settings change")
If mChangeFlag = vbOK Then
    ' Установка нового IP адреса
    For Each mCurrentAdapterConfig in mAdapterConfigList
        errEnable = mCurrentAdapterConfig.EnableStatic _
          (mNewIPAddressList, mNewSubnetMaskList)
        errGateways = mCurrentAdapterConfig.SetGateways _
          (mNewDefaultIPGatewayList, mNewGatewayMetricList)
        errWINS = mCurrentAdapterConfig.SetWINSServer _
          (mNewWINSPrimaryServer, mNewWinsSecondaryServer)
        errDNS = mCurrentAdapterConfig.SetDNSServerSearchOrder _
          (mNewDNSServerList)
        Exit For
    Next
    ' Pезультат операции
    mInfoMessage = "Operation result:" & vbCrLf _
      & "IP address error code: " & errEnable & vbCrLf _
      & "Gateway error code: " & errGateways & vbCrLf _
      & "DNS error code: " & errDNS & vbCrLf _
      & "WINS error code: " & errWINS & vbCrLf
Else
    mInfoMessage = "The operation is canceled"
End If
Wscript.Echo(mInfoMessage)

Использование WMI в программах

Ресурсы WMI доступны не только через скрипты, к ним можно обращаться из других языков программирования и даже из программ.

Существует два способа обращения к WMI через Visual Basic.NET.

Первый способ берет свое начало из скриптов VBS. Он использует обращение к инстументу winmgmts, как это делалось в методе моникера:

oComputerSystem = GetObject("winmgmts:[Options!]WMINameSpace).ExecQuery(WQLQuery)

Пример запроса модели комьютера (консольное приложение)

Module TestModule
    Sub Main()
        ' Объявление переменных
        Dim oWMIObject As Object
        Dim oComputerSystem As Object
        Try
            ' Подключение к WMI
            oWMIObject = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
            ' Выполнение запроса
            oComputerSystem = oWMIObject.ExecQuery("Select * from Win32_ComputerSystem")
            For Each oConfigutation As Object In oComputerSystem
                ' Вывод результатов в консоль
                Console.Write(oConfigutation.Model)
            Next
        Catch ex As Exception
            Console.Write("Ошибка запроса к WMI")
        End Try
End Module

Второй способ является более правильным с точки зрения Visual Studio. Он использует классSystem.Managementдля запросов к WMI, в котором указываются пространство WMI, параметры подключения и WQL запрос:

' Задание параметров подключения
mOptions = New Management.ConnectionOptions([Options])
' Задания WMI пространства имен
mScope = New Management.ManagementScope(WMINameSpace, mOptions)
' Задание WQL запроса
mQuery = New Management.ObjectQuery(WQLQuery)
' Создание объекта поиска по WMI с указанными параметрами
mSearcher = New Management.ManagementObjectSearcher(mScope, mQuery)
' Выполнение запроса
mQueryCollection = mSearcher.Get()

Использование полученных объектов аналогично использованию в скриптах.

Пример запроса сервисов локального комьютера (консольное приложение):

Module TestModule
    Sub Main()
        ' Объявление переменных
        Dim mOptions As Management.ConnectionOptions
        Dim mScope As Management.ManagementScope
        Dim mQuery As Management.ObjectQuery
        Dim mSearcher As Management.ManagementObjectSearcher
        Dim mQueryCollection As Management.ManagementObjectCollection
        ' Задание параметров подключения
        mOptions = New Management.ConnectionOptions
        ' Задания WMI пространства имен
        mScope = New Management.ManagementScope("\\.\root\cimv2", mOptions)
        ' Задание WQL запроса
        mQuery = New Management.ObjectQuery("SELECT * FROM Win32_Service")
        ' Создание объекта поиска по WMI с указанными параметрами
        mSearcher = New Management.ManagementObjectSearcher(mScope, mQuery)
        Try
            ' Выполнение запроса
            mQueryCollection = mSearcher.Get()
            ' Вывод результатов в консоль
            For Each mObject As Management.ManagementObject In mQueryCollection
                Console.WriteLine(mObject.Item("DisplayName").ToString)
            Next
        Catch ex As Exception
            Console.Write("Ошибка запроса к WMI")
        End Try
    End Sub
End Module

Пример программы на VB.NET

В качестве примера прораммы использования WMI в Visual Basic.Net представлено консольное приложение управления сервисом печати компьютера. Приложение запрашивает модель компьютера и выводит результат в консоль. После чего запрашивает состояние сервиса печати и, если он остановлен, предлагает запустить его.

Приложение разделено на две части: класс, который компилируется в динамическую библиотеку DLL, и программа, которая собирается в исполняемый файл EXE.

Листинг файла WMIClass.vb:

Public Class WMIClass

' Функция получения модели копьютера
#Region "GetModel 1.0"
    Public Function GetModel(Optional ByVal IPAddress As String = ".") As String
        Dim mTempValue As String = Nothing
        Try
            Dim oComputerSystem = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
              IPAddress & "\root\cimv2").ExecQuery("Select * from Win32_ComputerSystem")
            For Each oConfigutation As Object In oComputerSystem
                mTempValue = oConfigutation.Model
            Next
        Catch ex As Exception

        End Try
        Return mTempValue
    End Function
#End Region

' Функция получения состояния сервиса компьютера
#Region "GetServiceState 1.0"
    Public Function GetServiceState(Optional ByVal IPAddress As String = ".", _
      Optional ByVal ServiceName As String = "winmgmt") As Boolean
        Dim mOptions As Management.ConnectionOptions
        Dim mScope As Management.ManagementScope
        Dim mQuery As Management.ObjectQuery
        Dim mSearcher As Management.ManagementObjectSearcher
        mOptions = New Management.ConnectionOptions
        mScope = New Management.ManagementScope("\\" & IPAddress & "\root\cimv2", mOptions)
        mQuery = New Management.ObjectQuery("SELECT * FROM Win32_Service " & _
          "WHERE DisplayName = '" & ServiceName & "'")
        mSearcher = New Management.ManagementObjectSearcher(mScope, mQuery)
        Try
            Dim mQueryCollection As Management.ManagementObjectCollection = mSearcher.Get()
            For Each mObject As Management.ManagementObject In mQueryCollection
                If mObject("State") = "Running" Then
                    Return True
                Else
                    Return False
                End If
            Next
            Return False
        Catch ex As Exception
            Return False
        End Try
    End Function

    Public Function GetServiceStateFull(Optional ByVal IPAddress As String = ".", _
      Optional ByVal ServiceName As String = "winmgmt") As String
        Dim mOptions As Management.ConnectionOptions
        Dim mScope As Management.ManagementScope
        Dim mQuery As Management.ObjectQuery
        Dim mSearcher As Management.ManagementObjectSearcher
        mOptions = New Management.ConnectionOptions
        mScope = New Management.ManagementScope("\\" & IPAddress & "\root\cimv2", mOptions)
        mQuery = New Management.ObjectQuery("SELECT * FROM Win32_Service " & 
          "WHERE DisplayName = '" & ServiceName & "'")
        mSearcher = New Management.ManagementObjectSearcher(mScope, mQuery)
        Try
            Dim mQueryCollection As Management.ManagementObjectCollection = mSearcher.Get()
            For Each mObject As Management.ManagementObject In mQueryCollection
                Return mObject("State")
            Next
            Return "No data"
        Catch ex As Exception
            Return "No data"
        End Try
    End Function
#End Region

' Процедура управления сервисом компьютера
#Region "Manage Service 1.0"
    Public Sub ManageService(Optional ByVal IPAddress As String = ".", _
      Optional ByVal ServiceName As String = "winmgmt", _
      Optional ByVal Action As String = "StartService")
        Dim mOptions As Management.ConnectionOptions
        Dim mScope As Management.ManagementScope
        Dim mQuery As Management.ObjectQuery
        Dim mSearcher As Management.ManagementObjectSearcher
        Dim mQueryCollection As Management.ManagementObjectCollection
        mOptions = New Management.ConnectionOptions
        mScope = New Management.ManagementScope("\\" & IPAddress & "\root\cimv2", mOptions)
        mQuery = New Management.ObjectQuery("SELECT * FROM Win32_Service " & _
          "WHERE DisplayName = '" & ServiceName & "'")
        mSearcher = New Management.ManagementObjectSearcher(mScope, mQuery)
        Try
            mQueryCollection = mSearcher.Get()
            For Each mObject As Management.ManagementObject In mQueryCollection
                mObject.InvokeMethod(Action, Nothing)
            Next
        Catch ex As Exception

        End Try
    End Sub
#End Region

End Class

Листинг файла TestModule.vb:

Module TestModule
    ' Создание экземпляра класса WMIClass
    Private mWMIClass_Instance As New WMIClass

    Sub Main()
        Dim mKeyNumber As Integer
        ' Получение модели компьютера и результата в консоль
        Console.WriteLine("Модель компьютера: " & mWMIClass_Instance.GetModel())
        ' Проверка состояния сервиса "Диспетчер печати"
        If mWMIClass_Instance.GetServiceState(, "Диспетчер печати") = True Then
            Console.WriteLine("Служба ""Диспетчер печати"" запущена")
        Else
            Console.WriteLine("Служба ""Диспетчер печати"" остановлена")
            Console.Write("Запустить службу ""Диспетчер печати""? Y/N: ")
            ' Чтение символа с клавиатуры
            mKeyNumber = Console.Read
            If mKeyNumber = 89 Or mKeyNumber = 121 Then
                Console.WriteLine("Запуск службы ""Диспетчер печати""...")
                ' Попытка запуска сервиса "Диспетчер печати"
                mWMIClass_Instance.ManageService(, "Диспетчер печати", "StartService")
                ' Ожидание 5 секунда
                Threading.Thread.Sleep(5000)
                ' Проверка состояния сервиса "Диспетчер печати"
                If mWMIClass_Instance.GetServiceState(, "Диспетчер печати") = True Then
                    Console.WriteLine("Служба ""Диспетчер печати"" успешно запущена")
                Else
                    Console.WriteLine("Запуск службы ""Диспетчер печати"" не удался")
                End If
            End If

        End If
        Console.WriteLine("Нажмите любую клавишу для продолжения")
        ' Ожидание нажатия любой клавиши
        Console.ReadKey()
    End Sub
End Module

Использование специальных средств для написания запросов

Для того, чтобы облегчить написание скриптов и программ, существуют специальные утилиты, которые помогают просмотреть структуру пространства WMI и показавают примеры использования всех классов. Наиболее распространенные утилиты - это Scriptomatic и WMI Code Creator.

Scriptomatic

Инструмент Scriptomatic предствляет из себя HTA-приложение, которое генерирует код, использующий WMI, на VBSScript, JScript, Perl и Python. Сам по себе WMI может оказаться трудным для изучения, поэтому рекомендуется использовать Scriptomatic для освоения классов WMI, а также для быстрого создания шаблонов обращения к ресерсум WMI. Scriptomatic позволяет выбрать интересующий объект WMI, а затем генерирует код на указанном языке программирования. Полученный код можно выполнить непосредственно в оболочке программы, а результаты вывести в консоль, текстовый файл, HTML, Excel или XML. Инструмент доступен на сайте Microsoft по этой ссылке.

wmiscriptomatic_01.png
WMI Scriptomatic - Инициализация
wmiscriptomatic_02.png
WMI Scriptomatic - Win32_OpepatingSystem

WMI Code Creator

Программа WMI Code Creator представляет из себя генератор кода, который использует WMI для получения информации и для осуществления задач упраления компьютерами. Программа может помочь научиться использовать WMI-скрипты и WMI-приложения для управления как локальным, так и удаленным компьютером. Инструмент доступен на сайте Microsoft по этой ссылке.

Используя WMI Code Creator можно найти любую информацию о компьютере: имя и версия операционной системы, свободное место на диске, состояние сервисов и так далее. Можно выполнить метод из WMI класса для осуществления управления компьютером: создать или удалить сервис, запустить или закрыть программы, назначить разрешения на папку или файл и многое другое. Этот инструмент так же позволяет просматривать доступное WMI-пространство и WMI-классы, чтобы найти нужную для программирования инстанцию с ее описанием, свойствами, методами и примером использования.

wmicodecreator_01.png
WMI Code Creator - Query
wmicodecreator_02.png
WMI Code Creator - Method
wmicodecreator_03.png
WMI Code Creator - Event
wmicodecreator_04.png
WMI Code Creator - Namespace

Заключение

Итак, Windows Management Instrumentation - это мощный инструмент для администрирования операционных систем семейства Windows с помощью скриптов. С помощью WMI можно управлять устройствами, учетными записями, сервисами, процессами, сетевыми интерфейсами и другими программами, которые расширяют базовую структуру WMI своими классами.

Помимо скриптов WMI может применяться и в полноценных программах, то есть программисты могут внедрять запросы к WMI в исполняемый код, завязывая свою программу с работой WMI, благодаря чему программа становится проще и легче, но зависимой от правильности работы Windows Management Instrumentation.

Интересно, что новая командная оболочка Windows PowerShell связана с WMI как технической точки зрения, так и с точки зрения создания запросов - утилита Wmic.exe функционирует в некотором смысле аналогичным образом. В Windows PowerShell поддержка WMI, представлена в точно таком же согласованном объектном виде, как и другие возможности данной оболочки, поэтому при изучении этой оболочки применение WMI не становится такой сложной задачей, как это было в VBScript - не нужно изучать синтаксис и механизмы языка, отличного от языка скрипта.

Более подробно о Windows PowerShell можно будет прочитать в следующих выпусках статей сайта www.SysEngineering.ru.
Виталий Бочкарев

Внешние ссылки

Секция внешних ссылок, то есть ссылок на другие сайты, к которым данный ресурс не имеет никакого отношения. Данные ссылки размещены для удобства пользователей и не означают, что владелец сайта SysEngineering.ru одобряет содержание сайтов, приведенных ниже. Кроме этого, владелец сайта SysEngineering.ru не несет никакой ответственности за доступность этих ресурсов и за их контент.

zip.png Средства для создания скриптов

 

Вверх