Константин Леонтьев
Узнай секреты WMI: события и провайдеры
Часть II: ключ к управлению системой и приложениями
Технология управления системами через WMI позволяет решать ваши задачи гораздо эффективнее, если вы знаете потенциальные возможности WMI-провайдеров.
В предыдущей части статьи [1] мы подробно рассмотрели способы, которые предоставляет WMI системным администраторам для отслеживания и реакции на системные события. Из всех основных возможностей WMI нам осталось рассмотреть только специфику работы с различными провайдерами. Как вы помните из предыдущей статьи [2], WMI на нижнем уровне имеет модульную расширяемую архитектуру. Такая архитектура позволяет разработчикам добавлять к единому пространству классов WMI новые классы, отвечающие за мониторинг и управление их программного обеспечения. Такие модули в WMI имеют название провайдеров и обычно оформлены в виде DLL-библиотеки, взаимодействующей с WMI через COM+.
Замечу, что есть ряд провайдеров WMI, которые являются посредниками между WMI и другими широко распространенными системами управления. К таким провайдерам в частности относятся: WMI SNMP Provider и WMI Performance provider. Конечно же, в задачу системного администратора не входит разработка провайдеров WMI – это удел программистов, однако весьма полезно иметь представление об основных провайдерах и их функциях.
В операционной системе Windows XP существует более 20 различных провайдеров WMI, каждый из которых решает свой собственный узкий набор задач. Кроме того, устанавливая драйверы, а также системное и прикладное программное обеспечение, вы можете обнаружить, что их разработчики включили в состав своего продукта дополнительные WMI-провайдеры и классы. Из наиболее широко известных программных продуктов, устанавливающих свои WMI-провайдеры, можно отметить следующие: Intel ProSet II, Citrix Metaframe и Presentation Server, Symantec Antivirus, Dell Open Manage, IBM DB2, HP Open View, Altiris Software Virtualization Solution, а также большинство продуктов и сервисов Microsoft. Замечу, что это далеко не полный список, а лишь то, что наиболее часто встречается в корпоративных сетях.
Поскольку все провайдеры нацелены на предоставление различных функций и решение различных задач, то всё описание и примеры будут строиться не от одной общей задачи, как это было в предыдущей части, а от функций провайдера.
Обработка даты и времени в сценариях WMI
Разберём простой пример по обработке даты и времени в сценариях WMI. Многие провайдеры WMI возвращают обратившейся к ним программе различные характеристики операционной системы и приложений, которые содержат даты и время. Эти данные представлены в специальном формате и нуждаются в предварительной обработке, прежде чем принять удобный для чиения вид.
До выхода Windows XP эта задача оставалась на совести вызывающей программы и требовала от администратора написания подпрограммы преобразования форматов. Несмотря на то что алгоритм этой подпрограммы довольно прост – это требовало дополнительных усилий. Пример такой подпрограммы представлен в листинге 1. Если взглянуть внимательно, то эта подпрограмма всего лишь разбирает дату и время, которые вернула система WMI, на составляющие и представляет в более удобном для чтения виде.
Листинг 1. Работа с датой и временем в WMI-сценариях. Работает на всех версиях ОС
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objOS = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")
For Each strOS in objOS
dtmInstallDate = strOS.InstallDate
Wscript.Echo WMIDateStringToDate(dtmInstallDate)
Next
Function WMIDateStringToDate(dtmInstallDate)
WMIDateStringToDate = CDate(Mid(dtmInstallDate, 5, 2) & "/" & Mid(dtmInstallDate, 7, 2) & "/" & Left(dtmInstallDate, 4) & " " & Mid (dtmInstallDate, 9, 2) & ":" & Mid(dtmInstallDate, 11, 2) & ":" & Mid(dtmInstallDate, 13, 2))
End Function
Возникает вопрос, почему дата и время в WMI представлены столь странным образом. Ответ на самом деле прост. Вспомните, что одним из важнейших элементов WMI является язык WQL. Для удобства обработки даты и времени в WMI с помощью языка WQL (внутренней сортировки и группировки) все даты представлены так, что в самых старших разрядах идет год, затем месяц, потом – день, потом часы, минуты и секунды. Соответственно для того, чтобы отсортировать массив данных, полученных из WMI по дате времени, не нужно делать никаких дополнительных усилий.
Некоторые усилия потребуются при отображении этих данных пользователю или сохранении их в отчете. С выходом Windows XP эта задача стала решаться еще легче. В наборе объектов для сценариев WMI появился специальный класс объекта SWbemDateTime. Он отвечает за представление даты и времени в удобном для чтения виде. То есть фактически проделывает ту же работу, что и функция WMIDateStringToDate из листинга 1. Пример использования этого класса дан в листинге 2.
Листинг 2. Использование объекта SWbemDateTime. Работает только на Windows XP и новее.
Set dtmInstallDate = CreateObject("WbemScripting.SWbemDateTime")
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objOS = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")
For Each strOS in objOS
dtmInstallDate.Value = strOS.InstallDate
Wscript.Echo dtmInstallDate.GetVarDate
Next
В дополнение к этим новым возможностям в самом репозитории WMI появились классы, представляющие локальное время и часовой пояс не во внутреннем формате WMI, а в удобном для пользователя виде. Эти классы: Win32_LocalTime и Win32_TimeZone – удобное дополнение для работы с датами и временем. Кроме того, класс Win32_LocalTime рекомендуется использовать для отслеживания интервалов времени с помошью обработчиков событий WMI, которым была посвящена предыдущая часть статьи. Обратите внимане, что минимальный интервал времени, который позволяет отслеживать класс Win32_LocalTime, равен 1 секунде.
Сканирование хостов сети и провайдер Ping
Провайдер Ping предоставляет в репозиторий WMI всего один класс Win32_PingStatus. Они позволяют из сценариев WMI посылать ICMP ECHO-запросы в сеть. Попросту пинговать хосты сети. К сожалению, этот провайдер поддерживается только в Windows XP и Windows Server 2003.
Если вам нужно написать сценарий WMI, который подключается к удаленной машине (как это делать, мы обсуждали в предыдущей статье [2]), то перед подключением хорошо бы проверить – доступна ли эта машина. Если машина по сети не доступна (выключена или отсоединена от сети), то подключение к WMI не состоится и в ваш сценарий будет возвращена ошибка. Сама по себе ошибка не представляет большой проблемы, но перед тем как WMI вернет ее вам, пройдет довольно большой тайм-аут (около 30-60 секунд).
Таким образом, если вы запустите сценарий, который должен будет подключиться к 100 машинам по сети и 25 из них будут недоступны, то время выполнения сценария займёт от 15 до 30 минут.
Если мы сможем перед попыткой подключения к удаленной машине быстро проверить, доступна ли она, то это значительно сократит время ожидания. Вот как раз эту задачу и позволяет эффективно решать Ping. Вам следует не забывать, что проверка доступности хоста по ICMP эхо-запросу может быть неудачной и из-за применения в сети на маршруте следования пакета фильтрующих маршрутизаторов или firewall.
В операционных системах Windows 2000, а также Windows NT 4.0 и Windows 98 эту проблему можно было решить только одним способом: запускать из сценария консольную команду ping и разбирать то, что эта утилита вернула на STDOUT, или анализировать код возврата утилиты PING. Пример представлен в листинге 3. Способ, конечно, не плохой, но не универсальный. Как известно, на локализованных версиях Windows ответы команды ping выводятся на локальном языке. Поэтому для каждой языковой версии ОС пришлось бы писать свой разборщик вывода – согласитесь, что это не удобно. С другой стороны анализ кода возврата команды PING не позволяет понять причину ошибки при отправке ICMP-пакета.
Листинг 3. Старый способ, разбирающий вывод на STDOUT команды ping
strComputer = "www.ya.ru"
Set objShell = CreateObject("WScript.Shell")
Set objScriptExec = objShell.Exec("ping -n 1 -w 700 –f –l 8 " & strComputer)
strPingResults = LCase(objScriptExec.StdOut.ReadAll)
If InStr(strPingResults, "reply from") Then
If InStr(strPingResults, "destination net unreachable") Then
WScript.Echo strComputer & " не отвечает на ping."
Else
WScript.Echo strComputer & " отвечает на ping."
End If
Else
WScript.Echo strComputer & " не отвечает на ping."
End If
Положение существенно поменялось с выходом Windows XP и Windows Server 2003 – теперь нет необходимости вызывать консольную команду ping. В нашем вооружении появился класс Win32_PingStatus. Запрос к этому классу позволяет выполнить это процедуру гораздо быстрее и проще. Этот способ не зависит от локализации операционной системы и предоставляет подробный отчет о статусе посланного ICMP-пакета и ответа на него.
Помимо мониторинга доступности хоста по сети, незаменимый класс Win32_PingStatus позволяет решать и множество других задач. В приведенном примере (см. листинг 4) мы определяем MTU (Maximum Transmission Unit) трассы от нашего хоста к хосту удаленному. Для тех, кто не знаком с понятием MTU стека TCP/IP, я поясню: MTU – это максимальный размер пакета, который может быть передан по маршруту (трассе) от одного хоста до другого, не будучи фрагментирован (разрезан на части для последующей сборки) ни одним промежуточным маршрутизатором.
Отмечу, что этот сценарий может быть весьма полезен в задачах оптимизации производительности сети и диагностике проблем.
Листинг 4. Определение максимального размера фрейма (MTU) трассы
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
strDestAddress = "www.ya.ru"
If WScript.Arguments.Count > 0 Then
strDestAddress = WScript.Arguments(0)
End If
WScript.Echo "Посылаем ICMP-пакеты хосту: " & strDestAddress & " различного размера..."
varMaxPacket = 0
For varBuffSize = 8 to 1472 step 8
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_PingStatus where Address='" & strDestAddress & "' and BufferSize=" & varBuffSize & " and NoFragmentation=true and TimeOut=700" ,,48)
For Each objItem in colItems
Select Case objItem.StatusCode
Case 0
WScript.Echo "Ответ на ping-запрос за " & objItem.ResponseTime & " миллисекунд, TTL = " & objItem.ResponseTimeToLive & ", размер пакета ответа " & objItem.ReplySize
Case 11001
WScript.Echo "Слишком маленький буфер" & ". Buffer Size is: " & varBuffSize
Case 11002
WScript.Echo "Конечная сеть не доступна" & ". Buffer Size is: " & varBuffSize
Case 11003
WScript.Echo "Конечный хост не доступен" & ". Buffer Size is: " & varBuffSize
Case 11004
WScript.Echo "Протокол не доступен" & ". Buffer Size is: " & varBuffSize
Case 11005
WScript.Echo "Конечный порт не доступен" & ". Buffer Size is: " & varBuffSize
Case 11006
WScript.Echo "Недостаточно ресурсов" & ". Buffer Size is: " & varBuffSize
Case 11007
WScript.Echo "Неверная опция IP" & ". Buffer Size is: " & varBuffSize
Case 11008
WScript.Echo "Аппаратная ошибка" & ". Buffer Size is: " & varBuffSize
Case 11009
If varMaxPacket = 0 Then varMaxPacket = varBuffSize - 8
WScript.Echo "Пакет превышает предельный размер трассы" & ". Buffer Size is: " & varBuffSize
Case 11010
WScript.Echo "Превышен интервал ожидания" & ". Buffer Size is: " & varBuffSize
varBuffSize = varBuffSize - 8
Case 11011
WScript.Echo "Неверный запрос" & ". Buffer Size is: " & varBuffSize
Case 11012
WScript.Echo "Неверный маршрут" & ". Buffer Size is: " & varBuffSize
Case 11013
WScript.Echo "Достигнут максимальный TimeToLive" & ". Buffer Size is: " & varBuffSize
Case 11014
WScript.Echo "Достигнут максимальный TimeToLive при сборке" & ". Buffer Size is: " & varBuffSize
Case 11015
WScript.Echo "Ошибка параметра" & ". Buffer Size is: " & varBuffSize
Case 11016
WScript.Echo "Требование снизить скорость передачи" & ". Buffer Size is: " & varBuffSize
Case 11017
WScript.Echo "Переполнение опции IP" & ". Buffer Size is: " & varBuffSize
Case 11018
WScript.Echo "Неверное назначение" & ". Buffer Size is: " & varBuffSize
Case 11032
WScript.Echo "Установление соединения по IPSEC" & ". Buffer Size is: " & varBuffSize
Case 11050
WScript.Echo "Общий сбой" & ". Buffer Size is: " & varBuffSize
End Select
Next
Next
WScript.Echo "Удалось определить MTU трассы: " & CStr(varMaxPacket + 28)
Алгоритм работы этого сценария прост: мы посылаем от нашего хоста до указанного целевого хоста пакеты, с каждым шагом увеличивая их размер на 8 байт, установив специальный IP-флаг, запрещающий фрагментировать пакет. При этом мы следим за результатом, и как только нам вернется диагностический пакет, сообщающий о том, что размер нашего исходного пакета больше допустимого, мы запоминаем размер последнего успешно прошедшего по трассе пакета.
Обработка системных журналов
Следующий провайдер WMI, который может оказаться вам полезеным, – это провайдер системных журналов Windows. Классы, которые предоставляет в наше пользование этот провайдер, имеют названия: Win32_NTLogEvent, Win32_NTEventLogFile, Win32_NTLogEventLog, Win32_NTLogEventUser, Win32_NTLogEventComputer. Для нас наибольший интерес представляют первые два.
Win32_NTLogEvent позволяет нам отслеживать события появления в системных журналах аудита новых записей. Для этого используется синхронная техника внутренних событий WMI.
Листинг 5. Отслеживание событий в системных журналах аудита
strComputer = "."
Set objWMIService = GetObject("winmgmts:{impersonationlevel=impersonate,(security)}!\\" & strComputer & "\root\CIMV2")
Set objEvents = objWMIService.ExecNotificationQuery("SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA 'Win32_NTLogEvent'")
Wscript.Echo "Ожидаем записи в системные журналы событий ..."
Do While(True)
Set objReceivedEvent = objEvents.NextEvent
Select Case
CInt(objReceivedEvent.TargetInstance.EventType)
Case 1
strType = "Ошибка"
case 2
strType = "Предупреждение"
case 3
strType = "Информация"
case 4
strType = "Успешный аудит"
case 5
strType = "Аудит отказа"
End Select
WScript.Echo "----- Новое Событие -----"
Wscript.Echo "Event ID: " & objReceivedEvent.TargetInstance.EventCode & " Значимость: " & strType & " Log: " & objReceivedEvent.TargetInstance.LogFile
WScript.Echo "Сообщение: " & objReceivedEvent.TargetInstance.Message
Loop
Как видно из примера, код WQL-запроса достаточно простой, поэтому, я полагаю, детально пояснять его не нужно. Обращу внимание лишь на одно существенное обстоятельство: при работе с журналами необходимо использовать привилегию Security. В противном случае многие из запросов будут отклонены системой безопасности Windows.
Следующий пример, приведенный на листинге 6, показывает, как произвести очистку журнала приложений (хотя это может быть любой системный журнал аудита), используя метод ClearEventlog класса Win32_NTEventlogFile. Помимо того, что нам необходимо указать привилегию Security, нам также необходимо открыть конкретный экземпляр объекта класса Win32_NTEventlogFile соответствующего журналу приложений.
Листинг 6. Очистка системного журнала приложений (Application Event Log)
strComputer = "."
Set objWMIService = GetObject("winmgmts:{impersonationlevel=impersonate,(security)}!\\" & strComputer & "\root\CIMV2")
Set objNTEventLog = objWMIService.Get("Win32_NTEventlogFile.Name='C:\WINDOWS\system32\config\AppEvent.Evt'")
objNTEventLog.ClearEventlog("c:\app.evt")
Обратите внимание на единственный аргумент метода ClearEventlog: «c:\app.evt». Этот аргумент задает файл, в который при очистке журнала будет сохранено старое содержимое журнала.
Работа с реестром из WMI и провайдер StdRegProv
Одним из самых полезных провайдеров WMI является провайдер работы с реестром. В отличие от множества других провайдеров все его классы определены не в пространстве имен root\CIMv2, а в пространстве имен root\default.
В примере, приведенном в листинге 7, можно увидеть все основные приемы, необходимые для работы с реестром через WMI. В их число входит создание и удаление ключей и значений реестра, а также запись данных в значения реестра и отслеживание событий по изменению ключей и значений реестра. Провайдер StdRegProv предоставляет системе WMI набор внешних источников событий для отслеживания изменений в реестре, что существенно повышает эффективность и скорость отслеживания этих событий.
Листинг 7. Работа с реестром через WMI
Sub REG_OnObjectReady(objObject, objAsyncContext)
Wscript.Echo "Изменение в реестре: " & objObject.GetObjectText_()
End Sub
'--------------------------------------------------------
strComputer = "."
Const HKEY_LOCAL_MACHINE = &H80000002
strKeyName = "SOFTWARE\aRegKey"
strValName = "MyValue"
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\DEFAULT")
Set objReg = objWMIService.Get("StdRegProv")
objReg.CreateKey HKEY_LOCAL_MACHINE, strKeyName
objReg.SetStringValue HKEY_LOCAL_MACHINE, strKeyName, strValName, "test0"
Set MySink = WScript.CreateObject( _
"WbemScripting.SWbemSink","REG_")
objWMIservice.ExecNotificationQueryAsync MySink, "SELECT * FROM RegistryValueChangeEvent WHERE " & "Hive = 'HKEY_LOCAL_MACHINE'" &_" AND KeyPath = ‘" & Join(Split(strKeyName, "\"), "\\") & "'" & " AND ValueName = '" & strValName &"'"
WScript.Echo "Ожидаем события..."
i = 0
While (i < 20)
Wscript.Sleep(1000)
i = i + 1
objReg.SetStringValue HKEY_LOCAL_MACHINE, strKeyName, strValName, «test» & i
Wend
MySink.Cancel
objReg.DeleteKey HKEY_LOCAL_MACHINE, strKeyName
Разберем пример, приведенный в листинге 7, подробнее. Мы используем асинхронную технику обработки внешних (extrinsic) событий WMI для класса RegistryValueChangeEvent.
В самом начале (сразу после подключения к репозиторию WMI и классу StdRegProv) мы создаем ключ, изменение которого мы будем в последующем отслеживать. Далее мы регистрируем процедуру – обработчик событий (Event Sink) под названием REG_OnObjectReady. Объявляем мы ее с использованием метода CreateObject для класса WbemScripting.SWbemSink. Далее мы вызываем метод асинхронной обработки событий WMI ExecNotificationQueryAsync. Этот метод подписывает наш сценарий (вернее его процедуру REG_OnObjectReady) на получение событий об изменении интересующего нас значения реестра. В данном примере это значение HKEY_LOCAL_MACHINE\SOFTWARE\aRegKey\MyValue. После того как обработчик зарегистрирован, мы начинаем ожидать события изменения этого ключа в цикле while, попутно делая раз в секунду (1000 миллисекунд) изменение этого самого ключа с помощью другого метода WMI: SetStringValue. Как только пройдет 20 секунд, и мы 20 раз изменим указанный выше ключ, цикл завершается, и в самом конце сценария мы отменяем подписку на события WMI вызовом метода Cancel объекта MySink, а также удаляем созданный ранее ключ реестра.
Работа с Active Directory через WMI Directory Service provider
Еще один полезный и интересный провайдер WMI – это провайдер для работы со службой каталогов Microsoft Active Directory. Все классы этого провайдера определены в пространстве имен root\deirctory\ldap. Сразу хочу обратить внимание, что существует альтернативное средство для работы с Active Directory из сценариев и приложений – это ADSI (Active Directory Services Interfaces). Объектная библиотека ADSI более проста и удобна в использовании, чем провайдер WMI Directory Services, тем более что он является надстройкой над всё тем же ADSI.
Зачем же тогда нужен этот провайдер?! – спросите вы. Все довольно просто – поскольку WMI универсальное средство мониторинга и управления системой Windows и ее компонентами, то есть необходимость интегрировать все средства управления системой через WMI. Кроме того, поскольку некоторые программные продукты по своей архитектуре могут использовать только WMI, то задача управления Active Directory должна быть решена и через WMI в том числе.
В листинге 8 приведен пример простого сценария WMI, который модифицирует поле displayname указанного пользователя Active Directory.
Листинг 8. Изменение свойств пользователя в Active Directory через WMI
strComputer = "."
strUserID = "MyNew_WMI_User"
Set objWMIService = GetObject("Winmgmts:\\" & strComputer & "\root\directory\ldap")
Set objValSet = CreateObject("wbemscripting.swbemnamedvalueset")
objValSet.add "__PUT_EXT_PROPERTIES", array("ds_displayname")
objValSet.add "__PUT_EXTENSIONS", true
objValSet.add "__PUT_EXT_CLIENT_REQUEST", true
Set objEnum = objWMIService.ExecQuery("select * from ds_user where ds_cn = '" & strUserID & "'", "WQL", 32)
For each objUser in objEnum
objUser.ds_DisplayName = "Обновленноое поле DisplayName"
objUser.put_ 1, objValSet
Next
WScript.Echo "Свойства прользователя Active Directory обновлены"
При изменении свойств объектов Active Directory через WMI есть одна существенная особенность – необходимо явно определять, какие из атрибутов объекта вы хотите модифицировать. Для этого их названия нужно перечислить в специальном объекте класса swbemnamedvalueset. В остальном взаимодействие с классами провайдера службы каталогов практически не отличается от работы с другими классами WMI.
Работа со счетчиками производительности
Следующий интересный провайдер – провайдер доступа к счетчикам производительности. Эти же самые счетчики вы можете увидеть, когда используете утилиту System Monitor (Performance Monitor). Этот провайдер предоставляет две группы классов, олицетворяющих счетчики производительности системы. К первой группе относятся классы, представляющие ненормированные системные показатели. Эта группа классов имеет общую часть в их названии – Win32_PerfRawData_, и наследуют все свои свойства от класса Win32_PerfRawData. Ко второй группе относятся классы, предоставляющие нормированные и форматированные данные. В их названии также имеется общая часть: Win32_PerfFormattedData_, а их свойства выведены из класса Win32_PerfFormattedData.
Пример работы с ненормированными счетчиками производительности смотрите в листинге 9.
Листинг 9. Использование неформатированных счетчиков(более быстрый доступ к данным)
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_PerfRawData_PerfOS_Processor",,48)
For Each objItem in colItems
Wscript.Echo "-----------------------------------"
Wscript.Echo "Win32_PerfRawData_PerfOS_Processor instance"
Wscript.Echo "-----------------------------------"
Wscript.Echo "C1TransitionsPersec: " & objItem.C1TransitionsPersec
Wscript.Echo "C2TransitionsPersec: " & objItem.C2TransitionsPersec
Wscript.Echo "C3TransitionsPersec: " & objItem.C3TransitionsPersec
Wscript.Echo "DPCRate: " & objItem.DPCRate
Wscript.Echo "DPCsQueuedPersec: " & objItem.DPCsQueuedPersec
Wscript.Echo "Frequency_Object: " & objItem.Frequency_Object
Wscript.Echo "Frequency_PerfTime: " & objItem.Frequency_PerfTime
Wscript.Echo "Frequency_Sys100NS: " & objItem.Frequency_Sys100NS
Wscript.Echo "InterruptsPersec: " & objItem.InterruptsPersec
Wscript.Echo "Name: " & objItem.Name
Wscript.Echo "PercentC1Time: " & objItem.PercentC1Time
Wscript.Echo "PercentC2Time: " & objItem.PercentC2Time
Wscript.Echo "PercentC3Time: " & objItem.PercentC3Time
Wscript.Echo "PercentDPCTime: " & objItem.PercentDPCTime
Wscript.Echo "PercentIdleTime: " & objItem.PercentIdleTime
Wscript.Echo "PercentInterruptTime: " & objItem.PercentInterruptTime
Wscript.Echo "PercentPrivilegedTime: " & objItem.PercentPrivilegedTime
Wscript.Echo "PercentProcessorTime: " & objItem.PercentProcessorTime
Wscript.Echo "PercentUserTime: " & objItem.PercentUserTime
Wscript.Echo "Timestamp_Object: " & objItem.Timestamp_Object
Wscript.Echo "Timestamp_PerfTime: " & objItem.Timestamp_PerfTime
Wscript.Echo "Timestamp_Sys100NS: " & objItem.Timestamp_Sys100NS
Next
В этом примере сценарий выводит показания счетчиков производительности для процессора. Для того чтобы понять, чем отличаются классы нормированных счетчиков производительности от ненормированных, я привел в листинге 10 почти тот же пример, но использующий класс с нормированными счетчиками производительности.
Листинг 10. Использование форматированных и нормированных счетчиков (все значения соответствуют System Monitor)
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor",,48)
For Each objItem in colItems
Wscript.Echo "-----------------------------------"
Wscript.Echo "Win32_PerfFormattedData_PerfOS_Processor instance"
Wscript.Echo "-----------------------------------"
Wscript.Echo "C1TransitionsPersec: " & objItem.C1TransitionsPersec
Wscript.Echo "C2TransitionsPersec: " & objItem.C2TransitionsPersec
Wscript.Echo "C3TransitionsPersec: " & objItem.C3TransitionsPersec
Wscript.Echo "DPCRate: " & objItem.DPCRate
Wscript.Echo "DPCsQueuedPersec: " & objItem.DPCsQueuedPersec
Wscript.Echo "Frequency_Object: " & objItem.Frequency_Object
Wscript.Echo "Frequency_PerfTime: " & objItem.Frequency_PerfTime
Wscript.Echo "Frequency_Sys100NS: " & objItem.Frequency_Sys100NS
Wscript.Echo "InterruptsPersec: " & objItem.InterruptsPersec
Wscript.Echo "Name: " & objItem.Name
Wscript.Echo "PercentC1Time: " & objItem.PercentC1Time
Wscript.Echo "PercentC2Time: " & objItem.PercentC2Time
Wscript.Echo "PercentC3Time: " & objItem.PercentC3Time
Wscript.Echo "PercentDPCTime: " & objItem.PercentDPCTime
Wscript.Echo "PercentIdleTime: " & objItem.PercentIdleTime
Wscript.Echo "PercentInterruptTime: " & objItem.PercentInterruptTime
Wscript.Echo "PercentPrivilegedTime: " & objItem.PercentPrivilegedTime
Wscript.Echo "PercentProcessorTime: " & objItem.PercentProcessorTime
Wscript.Echo "PercentUserTime: " & objItem.PercentUserTime
Wscript.Echo "Timestamp_Object: " & objItem.Timestamp_Object
Wscript.Echo "Timestamp_PerfTime: " & objItem.Timestamp_PerfTime
Wscript.Echo "Timestamp_Sys100NS: " & objItem.Timestamp_Sys100NS
Next
Видите – сам по себе исходный код сценария в листинге 10 отличается от примера в листинге 9 только одной строкой. Эта строка – WQL-запрос: «SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor». В сущности, отличается только имя класса, набор его свойств в точности совпадает, однако сами значения свойств будут отличаться. Для каждого свойства существует специальная формула перевода из ненормированного значения в нормированное. Узнать эту формулу можно из файла Winperf.h.
WMI SNMP-провайдер
Подробно рассмотреть здесь провайдер WMI SNMP не получится, тем не менее упомянуть об этом провайдере стоит. Этот провайдер фактически является мостом между SNMP-совместимыми устройствами и системой WMI. Те, кто неплохо знаком с SNMP, понимают, что в основе WMI и SNMP лежат похожие решения по хранению и представлению информации. И WMI и SMNP поддерживают события (в терминологии SNMP это Trap-сообщения) и расширение базы данных (репозитория): в терминологии WMI это MOF-файлы, а в терминологии SNMP это базы MIB (Management Information Base).
В итоге при использовании SNMP-провайдера WMI администратор получает в пространстве имен rootsnmp представление всех необходимых устройств, поддерживающих протокол SNMP. Присылаемые SNMP-устройствами Trap-сообщения преобразуются в события WMI, которые можно также отслеживать. Для добавления информации из баз данных в формате SNMP MIB в репозиторий WMI существует специальная утилита smi2smir.exe.
При инсталляции ОС Windows по умолчанию провайдер SNMP WMI не устанавливается – его необходимо устанавливать через установку и удаление системных компонентов консоли Add/Remove Programs.
Затем необходимо произвести настройку SNMP-окружения. В эту задачу входит определение в свойствах пространств имен раздела rootsnmp так называемых SNMP-community для чтения, записи и оповещений, и импортировать в репозиторий WMI MIB-файлы. Некоторую дополнительную информацию по этой теме можно прочитать в библиотеке MSDN [4].
После того как SNMP-окружение настроено для этого провайдера, можно начинать работать с SNMP-совместимыми устройствами из сценариев WMI. Пример WQL-запроса для чтения свойств SNMP-совместимых устройств выглядит примерно так:
SELECT * FROM SNMP_DEVICE_ADDRESS WHERE SNMP_PROPERTY_NAME > 100
Таким образом, провайдер SNMP позволяет интегрировать любые системы и устройства, поддерживающие SNMP, с технологией WMI.
Устраняем ошибки в WMI
В данном разделе мы рассмотрим вопрос диагностики и устранения ошибок в WMI. Помимо штатного резервного копирования и восстановления, выполнение которого доступно через консоль wmimgmt.msc. Существует еще ряд средств диагностики и восстановления WMI. Для того чтобы разобраться, как они работают, нужно вспомнить, что все элементы репозитория WMI могут быть описаны на языке MOFфайлов. Таким образом, используя компилятор MOF-файлов mofcomp.exe, вы можете заново воссоздать весь репозиторий WMI – главное для этого иметь эти самые исходные MOF-файлы. При компиляции некоторые MOF-файлы могут быть помечены как компоненты автоматического восстановления – это означает, что при обнаружении серьезной ошибки в базе данных репозитория WMI запущенный процесс автоматического восстановления самостоятельно скомпилирует и импортирует в репозиторий такие MOF-файлы. Для того чтобы пометить MOF-файлы как компонент автоматического восстановления при его компиляции, нужно добавить опцию – AUTORECOVER. Таким образом, команда компиляции MOF файла должна выглядеть так:
mofcomp –AUTORECOVER <moffilename>
Очевидно, что эти файлы должны быть доступны локально, когда процесс автоматического восстановления будет запущен, поэтому при компиляции с этим ключом MOF-файлы копируются в папку %systemroot%\system32\wbem.
Относительно недавно (10 марта 2006 года) вышла обновленная версия 1.1 сценария WMIDiag.vbs. Этот сценарий разработан специалистами Microsoft для дополнительной диагностики WMI. Он обязательно должен запускаться локально на той машине, на которой следует провести диагностику. Он поддерживает множество ключей командной строки для управления режимом своей работы. В частности его можно работать в «тихом режиме» (без вывода диагностических сообщений на экран – они будут записываться в файл, в системный журнал и/или отправляться по электронной почте) или запускаться как задание Microsoft SMS 2003.
С его помощью можно осуществлять множество разных тестов по проверке работоспособности WMI: проверку службы и COM-объектов WMI, чтение и запись в репозиторий, проверку целостности репозитория и определения классов и пространств имен, а также параметров реестра и других системных служб и компонентов, влияющих на работу WMI. Пожалуй, самым ценным в этом сценарии является то, что помимо диагностики и констатации проблем он выдает рекомендации по исправлению неисправностей. В будущих версиях планируется сделать режим автоматического исправления некоторых типичных проблем, которые он обнаруживает.
Подробное описание этого сценария (утилиты) с примерами и иллюстрациями можно найти по ссылке [5].
Вместо заключения
В цикле статей о технологии WMI я постарался рассказать вам о всех важных и практически применимых сторонах этого поистине универсального инструмента. Надеюсь, вы оцените его полезность.
Ссылки и литература:
- Леонтьев К. Узнай секреты WMI: события и провайдеры. Часть I: дополнительные возможности. – Журнал «Системный администратор», №3, март 2006 г. – 6-13 с. (http://www.samag.ru/cgi-bin/go.pl?q=articles;n=03.2006;a=05).
- Леонтьев К. Вы все еще не используете WMI? Часть I. – Журнал «Системный администратор», №1, январь 2006 г. – 4-11 с. (http://www.samag.ru/cgi-bin/go.pl?q=articles;n=01.2006;a=02);
- Леонтьев К. Вы все еще не используете WMI? Часть II: пишем сценарии. – Журнал «Системный администратор», №2, февраль 2006 г. – 6-14 с. (http://www.samag.ru/cgi-bin/go.pl?q=articles;n=02.2006;a=02).
- 3. Windows Management Instrumentation – http://msdn.microsoft.com/library/en-us/dnanchor/html/anch_wmi.asp.
- Setting up the WMI SNMP Environment – http://msdn.microsoft.com/library/en-us/wmisdk/wmi/setting_up_the_wmi_snmp_environment.asp?frame=true.
- WMIDiag – http://www.microsoft.com/technet/scriptcenter/topics/help/wmidiag.mspx.