Глава 15. Управление с помощью Windows Management Instrumentation
Содержание
В данной главе вы рассмотрите следующие рецепты:
-
Изучение WMI в Windows
-
Изучение пространств имён WMI
-
Изучение классов WMI
-
Получение локальных и удалённых объектов WMI
-
Применение методов WMI
-
Управление событиями WMI
-
Реализацию постоянной обработки событий WMI
Windows Management Instrumentation (WMI, Инструментарий управления Windows) это компонент Windows, который вы можете применять в помощь управления системами Windows. WMI это частная реализация Microsoft имеющегося стандарта Web-Based Enterprise Management (WBEM, Основанного на веб управления корпорацией). WBEM это открытый стандарт, обнародованный Distributed Management Task Force (DMTF), которая имеет целью унификацию необходимого управления для распределённых вычислительных сред с применением стандартных технологий Интернет.
Помимо WMI для Windows, существуют и иные реализации WBEM, включая OpenWBEM. Дополнительно про DMTF и WBEM вы можете прочесть в https://www.dmtf.org/about/faq/wbem_faq, ознакомиться с OpenWBEM в http://openwbem.sourceforge.net/.
Впервые Microsoft представил WMI в качестве дополнительного компонента для Windows NT 4. Затем они интегрировали WMI в качестве существенного
компонента своего клиента Windows, начиная с Windows XP и далее и в Windows Server начиная с версии Windows Server 2000. Впоследствии несколько
специализированных команд внутри группы Windows активно применяли WMI. Например, как хранилище, так и сетевые стеки внутри Windows применяют
WMI. Многие командлеты, например, Get-NetAdapter
, непосредственно основаны на WMI.
Имевшиеся стандарты WBEM изначально определяли что все компоненты WMI взаимодействуют при помощи HTTP. Для улучшения производительности вместо этого реализовал взаимодействие компонентов WMI с использованием Common Object Model (COM), которая на тот момент времени была популярной технологией. WMI сам по себе остаётся реализованным на COM. Для доступа к функциональным возможностям WMI PowerShell пользуется .NET.
Windows PowerShell 1.0 поставлялся с неким множеством командлетов, которые могли применять доступ к WMI. Это были базовые командлеты, которые работали во всех последующих версиях Windows PowerShell. Однако для этих командлетов не существует никакой непосредственной поддержки в PowerShell 7. Вы можете активировать более старые сценарии на основе командлетов WMI при помощи удалённого исполнения PowerShell, если вы действительно в них нуждаетесь.
Начиная с V3 PowerShell Microsoft проделал значительную работу с WMI, приведшую в результате к некому новому модулю,
CimCmdlets
. Имелось несколько веских причин как для нового модуля, так и для связанных с ним обновлений
некоторых внутренних компонентов WMI в помощь разработчикам. В этой главе для доступа к к функциональным возможностям WMI вы пользуетесь модулем
CimCmdlets
. Почему соответствующая команда приняла решения собирать новые командлеты вы можете прочесть
в посте блога в https://devblogs.microsoft.com/powershell/introduction-to-cim-cmdlets/. Если у вас имеются сценарии, которые пользуются более
старыми командлетами WMI, рассмотрите возможность обновления их на применение вместо этого более позднего модуля
CimCmdlets
. Эти новые командлеты быстрее, что всегда даёт приятные преимущества.
WMI это сложный предмет. Прежде чем мы рассмотрим CimCmdlets
и что мы с ним можем делать, полезно
разобраться с собственно архитектурой WMI внутри Windows. Сама архитектура WMI одна и та же в Windows 10 и Windows Server 2022. Наша следующая
схема отображает концептуальную архитектуру WMI:
Будучи профессионалом в ИТ для доступа к WMI вы пользуетесь модулем командлетов
CimCmdlets
. Эти командлеты применяют .NET
через транспортный протокол для взаимодействия с
ядром WMI и диспетчером объекта
CIM в неком локальном или удалённом хосте. Имеющиеся транспортные протоколы включают в своём составе DCOM и WSMan. Центральные
компоненты WMI, в частности Диспетчер объекта CIM (CIMOM - CIM Object Manager), это компоненты COM, которые вы можете обнаружить в каждом
хосте Windows.
Сам CIMOM хранит информацию в репозитории WMI, порой именуемом как
Common Information Model
(CIM) или База данных
CIM. Эта база, по- существу, некое подмножество базы данных ANSI- SQL. Соответствующие командлеты CIM позволяют вам выполнять
доступ к имеющимся внутри этой базы данных сведениям. Такая база данных CIM организует имеющиеся сведения в пространствах имён классов .NET,
также носящих название пространств имён для организации классов. Тем не менее, классы .NET содержат и собственно название пространства имён в
качестве части названия самого класса. Например, вы можете создать при помощи класса .NET вы можете создать некое новое сообщение электронной
почты, System.Net.Mail.Mailmessage
, где собственно пространством имён выступает
System.Net.Mail
. Тем самым, само пространство имён содержится в значении полного названия класса. При
помощи WMI названия пространств имён и названия классов разделяются и поддерживаются в имеющихся командлетах CIM при помощи различных
параметров.
Классы WMI содержат экземпляры данных, которые хранят соответствующие сведения об управлении. Например, пространство имён
Root\CimV2
содержит класс Win32_Share
. Всякий экземпляр внутри
этого класса представляет один из совместных ресурсов SMB внутри вашего хоста. При помощи PowerShell вы можете обычным образом применять
имеющиеся командлеты SMB для управления совместными ресурсами SMB. Существуют полезные сведения, содержащиеся в прочих классах WMI для которых
не имеется никакой поддержки командлетами.
Когда вы выполняете выборку экземпляров, скажем, соответствующего класса Win32_Shar
, .NET получает
необходимые сведения об экземпляре и возвращает их в некой оболочке .NET объекта. Строго говоря, какой- то экземпляр объекта WMI это некий
экземпляр специализированного класса .NET с возвращаемыми в WMI данными. По этой причине вы воспринимаете объекты WMI применяющими те же самые
методы, которые вы используете с прочими объектами .NET.
Многие классы WMI обладают методами, которые вы можете активировать, и которые способны выполнять некоторые операции либо в каком- то заданном
экземпляре WMI, или статически основанном на этом классе. Наш класс Win32_Share
, например, обладает
статическим методом Create()
, который вы можете применять для создания какого- то нового совместного
ресурса. Каждый экземпляр этого класса обладает динамическим методом Delete()
, который удаляет
соответствующий совместный ресурс SMB.
Некой важной архитектурной функциональной возможностью WMI выступает поставщик
WMI. Поставщик WMI, это некое добавление к WMI, которое реализует классы WMI внутри некого заданного хоста. Такой поставщик WMI,
например, реализует сотни классов WMI, включая Win32_Share
и
Win32_Bios
. Некий поставщик к тому же реализует методы класса и события класса. К примеру, соответствующий
поставщик Win32 отвечает за выполнение как указанного метода Delete()
для удаления совместного ресурса SMB
и обозначенного метода Create()
для создания некого нового совместного ресурса SMB.
В промышленном решении, скорее всего, для управления совместными ресурсами SMB вы будете использовать командлеты SMB и маловероятно что вы воспользуетесь напрямую WMI. Поскольку общие ресурсы должны быть хорошо знакомы, они представляют собой отличный пример, который поможет вам лучше разобраться с WMI и рецепты этой главы пользуются этим классом.
WMI и поставщики WMI предлагают богатую систему событий. Классы WMI и поставщиков WMI могут реализовывать события, на которые вы способны подписываться. Когда происходит соответствующее событие, имеющаяся система событий уведомляет вас, и вы можете предпринимать некое действие для обработки такого произошедшего события. Например, вы можете выполнить регистрацию для какого- то события WMI, которое происходит когда изменяет имеющееся членство в некой группе AD. Когда такое случается, обработка событий WMI позволяет вам предпринимать какие- то действия, например, отправить электронное письмо администратору безопасности, информируя его об изменении такого членства в группе. WMI также реализует постоянную обработку событий. Эта функциональная возможность позволяет вам настраивать WMI для отлавливания и обработки событий без исполнения какого бы то ни было активного сеанса PowerShell. Постоянные события способны также переживать перезапуск своего хоста, что чрезвычайно действенно в средах с отключением электропитания.
Совет | |
---|---|
Существует множество подробностей относительно WMI, которые можно уместить в этой главе. Для получения дополнительных сведений относительно WMI и того как вы можете взаимодействовать с ним, проконсультируйтесь с книгой Ричарда Сиддэвея PowerShell и WMI (© Manning, Aug 2012). Книга Ричарда углубляется в отличные подробности относительно WMI, однако все примеры кода пользуются более старыми командлетами WMI. Вы должны быть способны перевести эти примеры на применение командлетов CIM. Ключевую ценность этой книги составляет собственно обсуждение функциональные возможности WMI и того как они работают. Эти базовые функциональные возможности WMI не претерпели значительных изменений с даты публикации этой книги. |
Windows устанавливает WMI в процессе установки самой ОС. Такой процесс установки помещает большинство компонентов WMI, включая репозиторий,
инструменты и необходимых поставщиков, в папку C:\Windows\System32\WBEM
.
Внутри запущенного хоста Windows WMI исполняется в качестве службы, службы winmgmt
(winmgmt.exe
). Windows запускает эту службу внутри процесса совместных служб
(svchost.exe
). В своих более ранних версиях WMI в Windows, WMI загружал всех необходимых поставщиков WMI
в такую службу winmgmt
. Подобная функциональность единого поставщика может вызывать отказ службы WMI
целиком. Позднее, в Windows XP и последующих версиях, Microsoft улучшил WMI загрузкой поставщиков в отдельном процессе,
WmiPrvSE.exe
.
В данном рецепте вы изучите имеющееся содержимое в папке WBEM, саму службу WMI и компоненты времени исполнения WMI.
Этот рецепт пользуется SRV1
, Присоединённым к домену хостом. Вы уже установили в этом хосте
PowerShell 7 и VS Code.
-
Просматриваем содержимое папки WBEM
$WBEMFOLDER = "$Env:windir\system32\wbem" Get-ChildItem -Path $WBEMFOLDER | Select-Object -First 20
-
Просматриваем папку репозитория WMI
Get-ChildItem -Path $WBEMFOLDER\Repository
-
Просматриваем подробности своей службы WMI
Get-Service -Name Winmgmt | Format-List -Property *
-
Получаем подробности процесса
$S = tasklist.exe /svc /fi "SERVICES eq winmgmt" | Select-Object -Last 1 $P = [int] ($S.Substring(30,4)) Get-Process -Id $P
-
Изучаем загружаемые нашей службой WMI DLL
Get-Process -Id $P | Select-Object -ExpandProperty modules | Where-Object ModuleName -match 'wmi' | Format-Table -Property FileName, Description, FileVersion
-
Выявляем поставщиков WMI
Get-ChildItem -Path $WBEMFOLDER\*.dll | Select-Object -ExpandProperty Versioninfo | Where-Object FileDescription -match 'prov' | Format-Table -Property Internalname, FileDescription, ProductVersion
-
Изучаем процесс
WmiPrvSE
Get-Process -Name WmiPrvSE
-
Обнаруживаем журнал событий WMI
$Log = Get-WinEvent -ListLog *wmi* $Log
-
Просматриваем типы имеющихся событий в выявленном журнале WMI
$Events = Get-WinEvent -LogName $Log.LogName $Events | Group-Object -Property LevelDisplayName
-
Изучаем записи своего журнала событий WMI
$Events | Select-Object -First 5 | Format-Table -Wrap
-
Просматриваем исполняемые программы в папке WBEM
$Files = Get-ChildItem -Path $WBEMFOLDER\*.exe "{0,15} {1,-40}" -f 'File Name','Description' Foreach ($File in $Files){ $Name = $File.Name $Desc = ($File | Select-Object -ExpandProperty VersionInfo).FileDescription "{0,15} {1,-40}" -f $Name,$Desc }
-
Изучаем свой модуль
CimCmdlets
Get-Module -Name CimCmdlets | Select-Object -ExcludeProperty Exported* Format-List -Property *
-
Находим в этом модуле
CimCmdlets
командлетыGet-Command -Module CimCmdlets
-
Изучаем возвращаемый из
Get-CimInstance
тип .NETGet-CimInstance -ClassName Win32_Share | Get-Member
Сама служба WMI и относящиеся к ней файлы пребывает в папке установки Windows, папке System32\WBEM
.
На Шаге 1 вы просматриваете часть имеющегося содержимого этой папки со следующим выводом:
WMI хранит свой репозиторий CIM в отдельной папке. На Шаге 2 вы изучаете те файлы, которые составляют саму базу данных с таким выводом:
На Шаге 3 вы пользуетесь Get-Service
для изучения своей
службы WMI с подобным приводимому ниже выводом:
На Шаге 4 вы изучаете тот процесс Windows, который запускает службу WMI с подобным отображаемому далее выводу:
На Шаге 5 вы рассматриваете DLL, загружаемые самим процессом службы WMI со следующим выводом:
Каждый поставщик WMI это DLL, которым может воспользоваться WMI. На Шаге 6 вы рассматриваете поставщиков
WMI в SRV1
с подобным приводимому ниже выводом:
На Шаге 7 вы изучаете процесс WmiPrvSE
с отображённым
далее выводом:
Как и прочие службы Windows, WMI регистрирует события в некотором журнале событий, который способен помогать в устранении неисправностей. На Шаге 8 вы рассматриваете все относящиеся к WMI события с таким выводом:
На Шаге 9 вы получаете имеющиеся события из этого журнала для просмотра различных уровней регистраций со следующим выводом:
На Шаге 10 вы просматриваете самые первые пять записей журнала событий WMI в
SRV1
. Вот как выглядит получаемый вывод:
На Шаге 11 вы просматриваете все исполняемые программы в своей папке WBEM с подобным приводимому ниже выводом:
В PowerShell 7 (и опционально в Windows PowerShell) вы получаете доступ к функциональным возможностям WMI при помощи командлетов из
модуля CimCmdlets
. Вы устанавливаете этот модуль как часть установки PowerShell 7. Программа установки
Windows устанавливает некую версию этого модуля при установке вами самой ОС хоста. На Шаге 12 вы
изучаете имеющиеся свойства этого модуля с таким выводом:
На Шаге 13 вы пользуетесь Get-Command
для выявления имеющихся в
модуле CimCmdlets
командлетов, что выглядит следующим образом:
На Шаге 14 вы изучаете имеющиеся свойства некого объекта, возвращаемого из WMI после применения
команды Get-CimInstance
. Вывод с этого шага выглядит так:
На Шаге 1 вы просматриваете самые первые 20 файлов/ папок в своей папке WBEM. Имеется гораздо больше файлов, чем вы видите на этом рисунке. Здесь включены те файлы DLL, которые доступны в вашей системе доступными для поставщиков WMI.
На Шаге 7 вы просматриваете свой процесс WmiPrvSE
. Этот
процесс содержит поставщиков WMI. В зависимости от тех действий, которые в настоящий момент сделал WMI, вы можете видеть ноль, один или более
вхождений этого процесса в своих хостах.
На Шаге 9 и на Шаге 10 вы выявляете и изучаете свой журнал событий WMI
системы. В SRV1
вы можете наблюдать и записи журнала событий Information
,
и Error
. Как вы можете наблюдать на Шаге 10, записи
Information
в основном указывают что WMI загрузил и активировал определённого поставщика. В большинстве
случаев наблюдаемые вами сообщения событий Error
являются проходящими или слабыми.
На Шаге 14 вы рассматриваете данные, возвращаемые Get-CimInstance
.
Как вы можете видеть из получаемого вывода, этот командлет возвращает те данные, которые получаются из класса WMI. Эти данные обёрнуты в неком
объекте .NET, который имеет класс Microsoft.Management.Infrastructure.CimInstance
с указывающим на значение
пути к соответствующему классу WMI суффиксом, в данном случае классу Win32_Share
из пространства имён
ROOT/CIMV2
. Этот возвращаемый объект и его содержимое отличается от того, что возвращается
Get-WMIObject
. Это может вызывать некую проблему если вы обновляете сценарии Windows PowerShell, которые
изначально пользовались более старыми командлетами WMI.
Командлеты CIM PowerShell позволяют вам производить выборку, обновление и удаление сведений из имеющейся базы данных и подписываться и обрабатывать события WMI. Имеющаяся база данных CIM организует свои сведения в наборы классов внутри некого иерархического множества пространств имён. Пространство имён, по существу, это некий контейнер, содержащий классы WMI и пространства имён WMI.
Названием корневого пространства имён WMI выступает ROOT
, хотя, как вы можете заметить, WMI не слишком
согласован в отношении применения заглавных букв. Пространство имён может содержать классы, а также дополнительные дочерние пространства имён.
К примеру, само корневого пространства имён обладает дочерним пространством имён, CIMV2
, которое ссылается
на ROOT\CIMV2
. Это пространство имён также обладает дочерними пространствами имён.
Всякое пространство имён в установленной базе данных CIM, включая ROOT
, обладает специальным
классом системы с названием __NAMESPACE
. Этот класс содержит соответствующие названия дочерних пространств
внутри текущих пространств имён. Таким образом, в нашем пространстве имён ROOT
, имеющийся класс
__NAMESPACE
содержит некий экземпляр для его дочернего пространства имён
CIMV2
. Поскольку этот класс имеется внутри каждого пространства имён, именно это упрощает обнаружение
всех имеющихся пространств имён в вашей системе.
Внутри каждой конкретной системы имеется множество пространств имён и классов в рамках WMI. Эти конкретные пространства имён и классы зависят
от тех приложений и свойств Windows которые вы запускаете в неком хосте. Кроме того, не все пространства имён или классы полезны. Собственно
пространство имён ROOT\CimV2
реализуемый соответствующим поставщиком WMI Win32, содержит классы WMI,
которые полезны профессионалам ИТ. Другие классы или пространства имён могут также содержать полезные классы, однако большинство прочих имеющихся
обычно полезны лишь для разработчиков, реализующих компоненты WMI или поставщиков WMI.
Другим менее широко применяемым пространством имён выступает ROOT\directory\LDAP
, который содержит
относящиеся к Active Directory классы. В то время как вы выполняете большинство функций управления AD при помощи командлетов AD, имеются
функциональные возможности этого пространства имён, в особенности обработки событий, которые не доступны при помощи имеющихся командлетов AD и
ккоторые вы можете найти полезными.
Этот рецепт пользуется SRV1
, присоединённым к домену хостом. В этом хосте вы имеете установленными
PowerShell 7 и VS Code.
-
Просматриваем классы WMI в своём корневом пространстве имён
Get-CimClass -Namespace 'ROOT' | Select-Object -First 10
-
Просматриваем в
ROOT
класс__NAMESPACE
Get-CimInstance -Namespace 'ROOT' -ClassName __NAMESPACE | Sort-Object -Property Name
-
Получаем и пересчитываем классы в
ROOT\CIMV2
$Classes = Get-CimClass -Namespace 'ROOT\CIMV2' "There are $($Classes.Count) classes in ROOT\CIMV2"
-
Выявляем все имеющиеся пространства имён в
SRV1
Function Get-WMINamespaceEnum { [CmdletBinding()] Param($NS) Write-Output $NS Get-CimInstance "__Namespace" -Namespace $NS @EAHT | ForEach-Object { Get-WMINamespaceEnum "$ns\$($_.name)" } } # End of function $Namespaces = Get-WMINamespaceEnum 'ROOT' | Sort-Object "There are $($Namespaces.Count) WMI namespaces on SRV1"
-
Просматриваем первые 25 пространств имён
SRV1
$Namespaces | Select-Object -First 25
-
Создаём блок сценария для подсчёта пространств имён и классов
$SB = { Function Get-WMINamespaceEnum { [CmdletBinding()] Param( $NS ) Write-Output $NS $EAHT = @{ErrorAction = 'SilentlyContinue'} Get-CimInstance "__Namespace" -Namespace $NS @EAHT | ForEach-Object { Get-WMINamespaceEnum "$NS\$($_.Name)" } } # End of function $Namespaces = Get-WMINamespaceEnum 'ROOT' | Sort-Object $WMIClasses = @() Foreach ($Namespace in $Namespaces) { $WMIClasses += Get-CimClass -Namespace $Namespace } "There are $($Namespaces.Count) WMI namespaces on $(hostname)" "There are $($WMIClasses.Count) classes on $(hostname)" }
-
Выполняем этот юлок сценария локально в
SRV1
Invoke-Command -ComputerName SRV1 -ScriptBlock $SB
-
Выполняем тот же блок сценария в
SRV2
> Invoke-Command -ComputerName SRV2 -ScriptBlock $SB
-
Выполняем это блок сценария в
DC1
Invoke-Command -ComputerName DC1 -ScriptBlock $SB
На Шаге 1
SRV1
На Шаге 2
SRV1
На Шаге 3
SRV1
На Шаге 4 вы определяете и затем применяете функцию для выявления всех имеющихся пространств имён в WMI в этом хосте, причём отсортированных в алфавитном порядке. Вот как выглядит вывод на этом шагу:
На Шаге 5 вы просматриваете первые 25 названий пространств имён с подобным приводимому ниже выводом:
На Шаге 6 вы создаёте блок сценария, который подсчитывает пространства имён и классы WMI. Этот шаг
не вырабатывает никакого консольного вывода. На Шаге 7 вы выполняем эту функцию для
SRV1
с подобным следующему выводом:
На Шаге 8 вы выполняете этот блок сценария в SRV2
с
таким выводом:
На заключительном шаге, Шаге 9 вы исполняете этот блок кода в контроллере домена,
DC1
. Вывод с этого шага выглядит следующим образом:
На Шаге 2 вы определяете имеющиеся дочерние пространства имён в корневых пространствах имён.
Каждый экземпляр содержит некую строку со значением названия дочернего пространства имён. Самой первой записью является
AccessLogging
. Таким образом, значением названия пространств имён этого дочернего пространства
имён выступает ROOT\AccessLogging
.
На Шаге 3 вы перечисляете имеющиеся в ROOT\CIMV2
классы.
Как упоминалось ранее, не все эти классы полезны для профессионалов ИТ, хотя многие являются таковыми. Вы можете применять механизм поиска
для нахождения классов могут быть полезными.
На Шаге 4 вы определяете рекурсивную функцию. Когда вы вызываете эту функцию, определяя пространство
имён ROOT
, эта функция выполняет выборку названий дочерних пространств имён из соответствующего класса
__NAMESPACE
в корневом пространстве имён. Затем для каждого дочернего пространства имён в корне эта
функция вызывает сама себя с названием дочернего пространства имён. В конечном счёте эта функция возвращает значения названий каждого пространства
имён в WMI. Затем вы сортируете их в алфавитном порядке по названию пространств имён. Обратите внимание, что вы можете отсортировать вывод
GET-WMINamespaceEnum
без определения свойства - вы сортируете имеющееся содержимое тех строк, которые
возвращаются их этой функции.
На Шаге 5 вы просматриваете некоторые имеющиеся пространства имён в WMI из
SRV1
. Двумя важными пространствами имён выступают ROOT\CIMV2
ROOT\directory\LDAP
. Первый содержит классы предоставляются поставщиком WMI Win32, содержащим подробности
относительно программного обеспечения и оборудования в вашей системе, включая BIOS, ОС, файлы и многое иное.
На Шаге 6 вы определяете рекурсивную функцию которая перенумеровывает все имеющиеся пространства имён WMI. Эта функция начинает с имеющегося корневого пространства имён WMI (или любого пространства имён, с которым вы вызываете эту функцию) и получаете все имеющиеся дочерние пространства имён. Для каждого из них эта функция возвращает значения дочерних пространств имён и так далее. Для каждого из пространств имён эта функция пересчитывает значение числа классов в каждом пространстве имён.
Шаг 7, Шаг 8 и Шаг 9 запускают эту функцию (определённую на Шаге 6) удалённо. Эти шаги перечисляют и отображают счётчик значений пространств имён и классов во всех трёх системах. По этой причине вы должны ожидать, что значение числа классов и пространств имён разнятся.
WMI класс определяет управляемый WMI объект. Все классы WMI обитают в рамках пространства имён и содержит участников, которые включают в
свой состав свойства, методы и события. Неким образцом класса выступает Win32_Share
, который вы
обнаруживаете в пространстве имён ROOT\CIMV2
. Этот класс определяет некий совместный ресурс SMB в
хосте Windows. В рамках WMI соответствующий поставщик Win32 реализует этот класс (совместно со множеством прочих классов ОС и относящихся к
хосту).
Как уже упоминалось, вы обычно пользуетесь соответствующими командлетами SMB для управления совместными ресурсами SMB (как это обсуждалось в Главе 10, Управление совместными данными, включая рецепт Создание совместных ресурсов SMB и их безопасность). Точно также большую часть действий по управлению AD вы выполняете при помощи командлетов AD вместо того чтобы выполнять доступ к этим сведениям через WMI. Тем не менее, вы можете выполнять с WMI такие вещи, как обработку событий, что может оказаться очень полезным для всех профессионалов ИТ.
Класс WMI содержит одно или более свойств, которые являются атрибутами некого вхождения класса WMI. Классы могут также включать в свой состав
методы, которые действуют в неком вхождении WMI. Например, класс Win32_Share
содержит свойство
Name
, которое содержит значение названия совместного ресурса для этого разделяемого ресурса. Каждое
свойство WMI обладает неким типом данных, например, integer или string. Наш класс Win32_Share
также
обладает методом Create()
для создания нового совместного ресурса SMB и метода
Delete()
для удаления конкретного совместного ресурса. Некий метод WMI может быть
динамическим (основанном на экземпляре) или
статическим (относящемуся к классу). Метод Delete()
класса Win32_Share
это динамический метод, который вы применяете для удаления конкретного совместного
ресурса SMB. Метод Create()
это статический метод, который может выполнять этот класс для создания
нового совместного ресурса SMB.
В этом рецепте вы применяете командлеты CIM для выявления сведений относительно классов и того что он может содержать. Вначале вы изучаете
класс внутри соответствующего пространства имён ROOT\CIMV2
. Вы также изучаете класс в пространстве имён
не по умолчанию и выявляете те объекты, которые содержатся в классе.
Данный рецепт применяет SRV1
, присоединённый к домену хост. В этом хосте у вас имеются установленными
PowerShell 7 и VS Code.
-
Просматриваем свой класс
Win32_Share
Get-CimClass -ClassName Win32_Share
-
Просматриваем свойства класса
Win32_Share
Get-CimClass -ClassName Win32_Share | Select-Object -ExpandProperty CimClassProperties | Sort-Object -Property Name | Format-Table -Property Name, CimType
-
Получаем методы класса
Win32_Share
Get-CimClass -ClassName Win32_Share | Select-Object -ExpandProperty CimClassMethods
-
Получаем классы некого не предопределённого по умолчанию пространства имён
Get-CimClass -Namespace root\directory\LDAP | Where-Object CimClassName -match '^ds_group'
-
Просматриваем имеющиеся экземпляры класса
ds_group
Get-CimInstance -Namespace root\directory\LDAP -Classname 'DS_Group' | Format-Table -Property DS_name, DS_Member
На Шаге 1 вы просматриваете конкретный класс, класс Win32_Share
,
с подобным приводимому ниже выводом:
На Шаге 2 вы просматриваете имеющиеся свойства класса Win32_Share
.
Вывод с этого шага выглядит так:
На Шаге 3 вы применяете командлет Get-CimClass
для просмотра тех
методов, которые вам доступны в классе Win32_Share
с подобным следующему выводом:
На Шаге 4 вы получаете относящиеся к группе классы в пространстве имён
ROOT\directory\LDAP
.Этот шаг возвращает только те классы, которые обладают названием
ds_group
. Как вы можете видеть, это соответствует нескольким имеющимся классом в этом пространстве имён
следующим образом:
На Шаге 5 вы получаете экземпляры соответствующего класса WMI ds_group
.
Отображаемый здесь вывод содержит и название соответствующей группы AD и имеющихся в настоящий момент участников каждой из групп AD. Вывод
с этого шага выглядит подобно такому:
На Шаге 3 вы просматриваете имеющиеся в классе Win32_Share
методы при помощи Get-CimClass
. Так как вы не определили некое пространство имён, этот командлет WMI
предполагает что вы заинтересованы в пространстве имён ROOT\CIV2
. Обратите внимание, что на этом шаге
метод Create()
обладает двумя важными спецификаторами: конструктором и состоянием. Спецификатор
конструктора сообщает, что вы пользуетесь именно статическим методом Create()
для построения нового
экземпляра данного класса (и некого нового совместного ресурса). Точно так же вы пользуетесь методом
Delete()
для удаления некого экземпляра данного класса.
На Шаге 5 вы просматриваете первые пять экземпляров в классе ds_group
.
Этот класс содержит некий экземпляр для каждой группы в домене Reskit.Org
. Он содержит дополнительные
сведения для каждой группы, возвращаемые при применении командлета Get-ADGroup
.
В рецепте Исследование классов WMI вы выявляете что WMI предоставляет большое
число (более 100) пространства имён каждого хоста совместно с тысячами классов WMI. Для возврата соответствующих экземпляров класса WMI либо
в локальном, либо в удалённом хосте вы пользуетесь командлетом Get-CimInstance
, как вы можете увидеть в
этом рецепте. Этот командлет возвращает соответствующие экземпляры WMI для некого определённого класса WMI, обёрнутого в некий объект .NET.
При помощи WMI у вас имеются три способа, которыми вы способны применять Get-CimInstance
:
-
Самый первый способ состоит в применении самого командлета для возврата всех вхождений классов и возвращает все свойства класса.
-
Второй способ состоит в применении параметра
-Filter
для определения некого фильтра WMI. Такой фильтр указывает соответствующей командеGet-CimInstance
для возвращения некоторых, а не всех экземпляров желаемого класса. -
Третий метод применяет некий запрос WMI при помощи WMI Query Language (WQL). Запрос WQL, по существу, некий оператор SQL, который указывает WMI для возвращения некоторых (не всех) свойств некоторых (не всех) вхождений конкретного предписанного класса WMI.
Когда вы применяете WMI внутри соответствующей сетевой среды, предписывая некий фильтр или полный запрос WMI может снизить общее число передаваемых по проводу данных и улучшает производительность.
Как и в предыдущем рецепте, для выборки экземпляров класса WMI вы применяете командлет Get-CimInstance
при помощи каждого из трёх подходов.
В этом рецепте вы пользуетесь SRV1
, присоединённом к домену хостом. В этом хосте у вас установлены
PowerShell 7 и VS Code.
-
Применяем
Get-CimInstance
в установленном по умолчанию пространстве имёнGet-CimInstance -ClassName Win32_Share
-
Получение объектов WMI из не установленного по умолчанию пространства имён
$GCIMHT1 = @{ Namespace = 'ROOT\directory\LDAP' ClassName = 'ds_group' } Get-CimInstance @GCIMHT1 | Sort-Object -Property Name | Select-Object -First 10 | Format-Table -Property DS_name, DS_distinguishedName
-
Применяем некий фильтр WMI
$Filter = "ds_Name LIKE '%operator%' " Get-CimInstance @GCIMHT1 -Filter $Filter | Format-Table -Property DS_Name
-
Применяем запрос WMI
$Q = @" SELECT * from ds_group WHERE ds_Name like '%operator%' "@ Get-CimInstance -Query $q -Namespace 'root\directory\LDAP' | Format-Table DS_Name
-
Получаем объект WMI из некой удалённой системы (
DC1
)Get-CimInstance -CimSession DC1 -ClassName Win32_ComputerSystem | Format-Table -AutoSize
На Шаге 1 для возврата всех имеющихся экземпляров Win32_Share
из SRV1
вы пользуетесь Get-CimInstance
с таким выводом:
На Шаге 2 для выборки экземпляров класса не установленного по умолчанию пространства имён, которое
вы именуете в явном виде, вы применяете Get-CimInstance
и получаете такой вывод:
На Шаге 3 вы пользуетесь фильтром WMI, определяемом параметром -Filter
для того же командлета Get-CimInstance
. Вот как выглядит вывод:
На Шаге 4 вы применяете полный запрос WMI, который содержит значения пространства имён/ класса, для которых вы желаете выполнить выборку и подробности каких свойств и из каких экземпляров надлежит возвращать, подобно следующему:
На Шаге 5 вы осуществляете выборку объекта WMI из удалённого хоста, DC1
.
Тот класс, для которого выполнена выборка на данном шаге, Win32_ComputerSystem
, содержит подробности
этого хоста, такие как имя хоста, название домена, общий объём физической памяти, как вы это можете наблюдать в идущем следом выводе:
На Шаге 4 вы создаёте запрос WMI. Этот запрос возвращает все свойства в любом экземпляре соответствующего класса, название которого содержит символы "operator", применяя синтаксис символов подстановки WMI. Этот запрос возвращает все свойства в соответствующих группах, которые содержат операторов печати и операторов серверов, как вы можете видеть из получаемого на этом шаге вывода.
На Шаге 5 вы возвращаете подробности из своего хоста
DC1
. Для возврата единственного вхождения класса Win32_ComputerSystem
вы применяете Get-CimInstance
. Этот вывод показывает, что хост DC1
обладает 4ГБ оперативной памяти. Если вы применяете для этого хоста виртуализацию, вы можете наблюдать различные значения, в зависимости от того как
вы настроили эту ВМ.
Во многих объектно- ориентированных языках программирования метод это некое действие, которому может подвергаться какой- то объект. WMI
также производить методы класса. Например, класс Win32_Share
обладает методом
Delete()
для удаления заданного совместного ресурса SMB. Этот класс также обладает соответствующим
статическим методом Create()
, который создаёт новый разделяемый ресурс SMB.
Во многих случаях методы WMI дублируют то, что вы можете совершать при помощи прочих командлетов PowerShell. Например, вы можете
воспользоваться командлетом New-SMBShare cmdlet
для создания нового совместного ресурса вместо применения
статического метода Create()
из его класса Win32_Share
.
Как уже упоминалось ранее, методы WMI содержат методы экземпляров и статические методы. Динамические методы, или методы экземпляра работают в
неком конкретном экземпляре - например, удаляют конкретный совместный ресурс SMB. Классы также производят статические методы и им нет нужды
ссылаться на какие- то имеющиеся экземпляры класса. Скажем, вы можете применять статический метод Create()
для создания нового совместного ресурса SMB(и нового вхождения в его класс Win32_Share
).
В этом рецепте вы применяете SRV1
, присоединённый к домену хостом. В этом хосте у вас установлены
PowerShell 7 и VS Code.
-
Обозреваем в
SRV1
методы классаWin32_Share
Get-CimClass -ClassName Win32_Share | Select-Object -ExpandProperty CimClassMethods
-
Рассматриваем свойства класса
Win32_Share
Get-CimClass -ClassName Win32_Share | Select-Object -ExpandProperty CimClassProperties | Format-Table -Property Name, CimType
-
Применяя статический метод
Create()
создаём новый совместный ресурс SMB$NSHT = @{ Name = 'TestShare1' Path = 'C:\Foo' Description = 'Test Share' Type = [uint32] 0 # disk } Invoke-CimMethod -ClassName Win32_Share -MethodName Create -Arguments $NSHT
-
Просматриваем новый совместный ресурс SMB
Get-SMBShare -Name 'TestShare1'
-
Просматриваем новый совместный ресурс SMB при помощи
Get-CimInstance
Get-CimInstance -Class Win32_Share -Filter "Name = 'TestShare1'"
-
Удаляем этот совместный ресурс
Get-CimInstance -Class Win32_Share -Filter "Name = 'TestShare1'" | Invoke-CimMethod -MethodName Delete
На Шаге 1 для выборки и отображения всех методов, предоставляемых классом
Win32_Share
вы пользуетесь Get-CimClass
. Это производит такой
вывод:
На Шаге 2 вы применяете Get-CimClass
для получения свойств
каждого экземпляра из класса Win32_Share
, воспроизводя следующий вывод:
На Шаге 3 для активации меода класса Win32_Share
,
Create()
, и создания в SRV1
нового совместного ресурса SMB вы
применяете Invoke-CimMethod
и он выдаёт:
На Шаге 4 для получения сведений об имеющемся совместном ресурсе SMB для созданного нами на предыдущем
шаге разделяемого ресурса вы польльзуетесь Get-SMBShare
на выходе производящем следующее:
На Шаге 5 для просмотра подробностей этого совместного ресурса через WMI вы воспользовались
Get-CimInstance
. Этот шаг производит такой вывод:
На заключительном шаге данного рецепта, Шаге 6 , вы применяете Invoke-CimMethod
для удаления определённого совместного ресурса (созданного вами на Шаге3).
На Шаге3, применяя командлет Invoke-CimMethod
, вы создаёте
новый совместный ресурс. Этот командлет получает хэш- таблицу, содержащую необходимые свойства и значения свойств для такого нового совместного
ресурса. Данный командлет возвращает некий объект, содержащий свойство ReturnCode
. Код возврата
0
сообщает об успехе - в нашем случае, WMI создал этот новый совместный ресурс. Для прочих значений
кодов возврата вам следует проконсультироваться с соответствующей документацией. Для класса Win32_Share
вы можете найти дополнительные сведения в документации из Интернета по адресу https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/create-method-in-class-win32-share. Эта страница показывает
значения кодов возврата, которые вырабатывает метод Create()
и на что указывают эти коды возврата.
Например, код возврата 8
указывал бы что вы попытались создать совместный ресурс с уже существующим именем.
Когда вы планируете применять WMI в промышленных сценариях, рассмотрите возможность проверки для ненулевых кодов возврата и аккуратной
обработки общих ошибок.
На Шаге 6 вы применяете метод WMI, Delete()
, для удаления ранее
созданного совместного ресурса SMB. Вы удаляете этот разделяемый ресурс для начала воспользовавшись Get-CimInstance
с неким фильтром WMI с целью выборки подлежащих удалению совместных ресурсов. Затем вы через конвейер передаёте эти объекты совместных ресурсов в
командлет Invoke-CimMethod
и активируете соответствующий метод Delete()
для этого экземпляра, передаваемого через указанный конвейер. Такой предпринимаемый на Шаге 6
подход это общеупотребительный способ удаления экземпляров класса WMI такого класса и, коли уж на то пошло, любого класса WMI.
Ключевой функциональной возможностью WMI выступает обработка его событий. Существуют тысячи событий, которые могут произойти внутри системы Windows, способный оказаться представляющими внимание. Например, вы можете пожелать знать когда некто добавляет нового участника в группу AD с высокими полномочиями, такую как Enterprise Admins. Вы можете сообщить WMI уведомлять вас при возникновении такого события и затем предпринимать какое- то соответствующее действие. Скажем, вы можете просто распечатать некий обновлённый список участников группы когда происходят изменения участников группы. Вы также можете проверять некий перечень пользователей, которые должны быть участниками такой группы и предпринимать какое- то действие если такой добавляемый пользователь не обладает авторизацией.
События обрабатываются как самим WMI так и поставщиками WMI. WMI сам по себе может сигнализировать об каком- то событии, когда в классе CIM
будет обнаружено изменение - то есть, в случае любого нового, обновлённого или удалённого экземпляра класса. Вы также имеете возможность выявлять
изменения класса целиком или пространств имён. WMI именует эти события присущими
(intrinsic) событиями. Одно из распространённых присущих событий может происходить когда вы (или Windows) запускает какой- то новый процесс
и, выполнив это, WMI добавляет новый экземпляр в свой класс Win32_Process
(содержащийся в пространстве
имён ROOT/CIMV2
).
События также реализуют и поставщики WMI. Они носят название привносимых (extrinsic) событий WMI. Соответствующий поставщик WMI AD, к примеру, реализует некое событие, которое загорается всякий раз, когда изменяется некое членство в группе AD. Поставщик Реестра Windows также производит некое привносимое событие, которое раскрывает изменение его реестра, например, какой- то новый ключ реестра или обновлённое значение реестра.
Для того чтобы воспользоваться управлением событием WMI сначала вы создаёте какую- то подписку на событие. Такая подписка на событие сообщает WMI какое именно событие вы собираетесь отслеживать. Кроме того, вы можете определять некий обработчик, который сообщает WMI что вы желаете выполнять в случае возникновения такого события. Скажем, при запуске нового процесса вы можете пожелать отображать подробности такого события. Когда изменяется некое участие в группе AD, вы можете пожелать проверить и убедиться что если некие участники группы не авторизованы, следует сообщить об этом факте или возможно даже удалить недопустимого участника группы.
Замечание | |
---|---|
Для получения дополнительных сведений о том как вы можете принимать события WMI обратитесь к https://docs.microsoft.com//windows/win32/wmisdk/receiving-a-wmi-event. Для получения информации относительно типов получаемых событий смотрите https://docs.microsoft.com/windows/win32/wmisdk/determining-the-type-of-event-to-receive. |
Имеются два типа обработки событий, которые вы можете применять. В этом рецепте вы создаёте и обрабатываете временные события WMI, которые работают в рамках сеанса PowerShell. Когда вы закрываете сеанс, WMI прекращает отслеживать все те события, которые вы зарегистрировали для такого сеанса. В следующем рецепте Реализация постоянной обработки событий WMI вы взглянете на создание не зависящих от своего текущего сеанса PowerShell подписок на события.
Когда вы зарегистрировали некое временное событие, вы можете снабдить WMI неким блоком сценария, который вы бы желали для выполнения со стороны WMI при возникновении данного события. WMI выполняет этот блок сценария в фоновом режиме, внутри некого задания PowerShell.
Когда вы регистрируете какое- то событие WMI, PowerShell создаёт это задание, в котором он исполняет соответствующее действие сценария. Как
и для всех заданий PowerShell, вы пользуетесь Receive-Job
для просмотра любого производимого его
сценарием вывода. Когда ваш блок сценария содержит операторы Write-Host
, PowerShell отправляет весь вывод
непосредственно в вашу консоль (а не в своё задание фонового режима).Вы также можете выполнить регистрацию для некого события WMI без
предписания какого бы то ни было блока действий. В таком случае WMI ставит такие события в очередь и для выборки подробностей подобного события
вы можете применять Get-WinEvent
.
Если WMI определяет некое событие, он вырабатывает запись события, которая содержит все подробности о таком событии. Такие записи событий могут оказаться полезными для вас в снабжении дополнительными подробностями относительно данного события, однако они не выступают полным моментальным снимком этого события. Вы можете зарегистрировать событие WMI об изменении членства в какой-то группе AD и получать такие подробности как сведения о новом участнике. Однако эта запись события не содержит подробностей относительно того пользователя, который изменил данное участие в группе, или значение IP адреса того хоста, который применялся для введения в действие соответствующего не авторизованного изменения.
Данный рецепт применяет SRV1
, присоединённый к домену хост. В этом хосте у вас имеются установленными
PowerShell 7 и VS Code.
-
Регистрируем некое присущее событие
$Query1 = "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'" $CEHT = @{ Query = $Query1 SourceIdentifier = 'NewProcessEvent' } Register-CimIndicationEvent @CEHT
-
Для включения этого события запускаем Notepad
notepad.exe
-
Получаем событие своего нового процесса
$Event = Get-Event -SourceIdentifier 'NewProcessEvent' | Select-Object -Last 1
-
Отображаем подробности этого события
$Event.SourceEventArgs.NewEvent.TargetInstance
-
Удаляем регистрацию этого события
Unregister-Event -SourceIdentifier 'NewProcessEvent'
-
Регистрируем некий запрос события на основе поставщика своего реестра
New-Item -Path 'HKLM:\SOFTWARE\Packt' | Out-Null $Query2 = "SELECT * FROM RegistryValueChangeEvent WHERE Hive='HKEY_LOCAL_MACHINE' AND KeyPath='SOFTWARE\\Packt' AND ValueName='MOLTUAE'" $Action2 = { Write-Host -Object "Registry Value Change Event Occurred" $Global:RegEvent = $Event } Register-CimIndicationEvent -Query $Query2 -Action $Action2 -Source RegChange
-
Создаём новый ключ реестра и устанавливаем значение элемента
$Q2HT = [ordered] @{ Type = 'DWord' Name = 'MOLTUAE' Path = 'HKLM:\Software\Packt' Value = 42 } Set-ItemProperty @Q2HT Get-ItemProperty -Path HKLM:\SOFTWARE\Packt
-
Удаляем регистрацию этого события
Unregister-Event -SourceIdentifier 'RegChange'
-
Изучаем подробности данного события
$RegEvent.SourceEventArgs.NewEvent
-
Создаём запрос WQL события
$Group = 'Enterprise Admins' $Query1 = @" Select * From __InstanceModificationEvent Within 5 Where TargetInstance ISA 'ds_group' AND TargetInstance.ds_name = '$Group' "@
-
Создаём временную регистрацию события WMI
$Event = @{ Namespace = 'ROOT\directory\LDAP' SourceID = 'DSGroupChange' Query = $Query1 Action = { $Global:ADEvent = $Event Write-Host 'We have a group change' } } Register-CimIndicationEvent @Event
-
В группу Enterprise Admins добавляем какого- то пользователя.
Add-ADGroupMember -Identity 'Enterprise Admins' -Members Malcolm
-
Просматриваем своего вновь добавленного пользователя
$ADEvent.SourceEventArgs.NewEvent.TargetInstance | Format-Table -Property DS_sAMAccountName,DS_Member
-
Удаляем регистрацию своего события
Unregister-Event -SourceIdentifier 'DSGroupChange'
На Шаге 1 вы регистрируете некое присущее событие, которое происходит всякий раз, когда Windows
запускает какой- то процесс. Данная регистрация не содержит блока действий. На Шаге 2 вы запускаете
Notepad.exe
для включения данного события. На Шаге 3 для выборки
подробностей этого события вы пользуетесь Get-Event
. Эти три шага не производят консольный вывод.
На Шаге 4 вы просматриваете подробности события запуска своего процесса с подобным следующему выводом:
На Шаге 5 вы удаляете регистрацию для своего события запуска процесса. Этот шаг ничего не выводит. На Шаге 6 вы регистрируете новую подписку на событие при помощи запроса WMI, который имеет целью вашего поставщика WMI с подобным такому выводом:
По завершению регистрации этого события, на Шаге 7 , вы создаёте новый ключ реестра и устанавливаете значение ключа реестра для проверки подписки на это созданное событие. Вот как выглядит вывод для этого шага:
На Шаге 8 вы удаляете регистрация события реестра чтобы избежать дополнительной обработки события и вывода события. На Шаге 9 вы изучаете получаемый вывод, выработанный WMI на основании изменений реестра, которые вы осуществили на Шаге 7. Подробности этого события выглядят следующим образом:
На Шаге 10 вы создаёте запрос WQL, который перехватывает изменения для вашей группы AD Enterprise Admins, что не вырабатывает никакого вывода. На Шаге 11 вы пользуетесь этим запросом для создания временного события WMI, которое зажигается когда изменяется участие в соответствующей группе. Вот как выглядит этот вывод:
Для проверки события изменения своего каталога, на Шаге 12 , вы добавляете в свою группу AD Enterprise Admins нового пользователя, вырабатывая такой вывод:
На Шаге 13 вы изучаете подробности своего события, выработанного на нашем предыдущем шаге в выводом, подобным приводимому ниже:
На заключительном шаге данного рецепта, на Шаге 14, вы удаляете регистрацию для изменения участия в соответствующей групе AD. Этот шаг не производит никакого вывода.
На Шаге 7 вы проверяете обработку события своего реестра, которое содержит блок сценария действий,
который вы бы желали исполнить PowerShell при возникновении данного события. Так как тот блок сценария, который вы определили
на Шаге 6, содержит оператор Write-Host
, вы наблюдаете
получаемый вывод в своей консоли PowerShell.
На Шаге 9 вы изучаете вырабатываемые WMI подробности при возникновении события WMI изменения реестра.
Как и для прочих событий, подробности данного события опускают потенциально критически важные сведения. Например, это событие не сообщает вам
какой именно пользователь выполнил это изменение или произвёл новое значение соответствующего значения реестра. Вы можете изучить журнал событий
Безопасности Windows для обнаружения регистрации в данной системе соответствующего пользователя (и тем самым, того пользователя который внёс
данное изменение). К тому же вы можете воспользоваться Get-ItemProperty
для определения самого нового
значения для свойства этого ключа реестра.
На Шаге 14 вы в явном виде удаляете свою регистрацию для события изменения AD. В качестве альтернативы, вам придётся закрыть ваш текущий сеанс PowerShell, удаляя подписки его событий.
В нашем рецепте Управление событиями WMI вы применяли возможности PowerShell обработки событий WMI. Эти обработчики событий были активными только на протяжении активности соответствующего сеанса PowerShell и пока пользователь зарегистрирован в это хосте. В том рецепте вы создали некую подписку на событие и обрабатывали соответствующие события пока ваша система вырабатывала их. Такая временная обработка событий является великолепным инструментом устранения неисправностей пока вы зарегистрированы и выполняете PowerShell.
WMI к тому же предоставляет постоянную обработку событий. Вы настраиваете WMI на подписку и обработку событий по мере их появления не применяя активного и открытого сеанса. При постоянной обработке событий вы настраиваете WMI на подписку для конкретного события, например, добавление нового участника в группу с наивысшими полномочиями, такую как Enterprise Admins. Вы также настраиваете WMI на выполнение предварительно определяемого действия при возникновении такого события, например создание отчёта или отправку сообщения электронной почтой для отчёта о таком событии если/ когда оно происходит.
WMI в Windows определяет несколько различных типов постоянных потребителей сообщений, которых вы можете применять для настройки некого постоянного события:
-
Active Script Consumer: Вы пользуетесь им для запуска конкретного сценария VBS.
-
Log File Consumer: Этот обработчик записывает подробности событий в файлы журнала событий.
-
NT Event Log Consumer: Этот потребитель записывает подробности событий в Журнал событий Windows.
-
SMTP Event Consumer: Вы можете применять этого потребителя для отправки SMTP сообщения электронной почты при возникновении некого события.
-
Command Line Consumer: при помощи данного поставщика вы можете запускать программу, такую как PowerShell, и передавать название файла сценария. При возникновении соответствующего события, данный сценарий имеет доступ к подробностям этого события и способен достаточно выполнять из того, что вы способны делать в PowerShell.
Microsoft разработал поставщика Active Script во времена сценариев Visual Basic и VBS. К сожалению, этот поставщик не поддерживает сценарии
PowerShell. Постоянный обработчик событий WMI командной строки, с другой стороны, даёт вам возможность исполнять любые программы, которые вы
пожелаете когда соответствующий обработчик события определяет возникновение события. В данном рецепте вы запрашиваете WMI запустить
pwsh.exe
и исполнить определённый файл сценария при загорании соответствующего события.
Управление постоянным обработчиком событий аналогично тем временным событиям WMI, которые изучались в нашем рецепте Управление событиями WMI. Вы сообщаете WMI какое событие перехватывать и что делать при возникновении такого события. Вы добавляете некое возникновение класса WMI в три класса WMI, как вы обнаружите в этом рецепте для реализации постоянного обработчика события следующим образом:
-
Определяете некий фильтр события. Такой фильтр события определяет то конкретное событие, которое должен обрабатывать WMI. Вы делаете это добавляя новый экземпляр в тот конкретный класс события, который вы бы хотели выявлять WMI. Этот фильтр события по существу тот же самый, что и в нашем предыдущем рецепте, Управление событиями WMI.
-
Определяете потребителя события. На этом шаге вы определяете то действие, которое вы бы хотели предпринять со стороны WMI при возникновении соответствующего события.
-
Связываете полученные фиотр события и потребителя события. При помощи данного шага вы добавляете новое вхождение в связываемом классе события. Данное вхождение направляет WMI на выполнение некого действия (активацию соответствующего потребителя события) всякий раз, когда WMI выявляет что случилось конкретное событие (предписанное в его фильтре события).
Поставщик WMI AD реализует широкий диапазон относящихся к AD событий, на которые вы имеете возможность подписываться. Пространства имён WMI
обычно содержат конкретные классы событий, которые можно выявлять при каких бы то ни было изменениях в таком пространстве имён. Пространство
имён ROOT/Directory/LDAP
обладает системным классом с названием
__InstanceModificationEvent
. Для постоянного обработчика события вы добавляете некое вхождение в этот
класс.
Замечание | |
---|---|
Уместно небольшое предостережение. При работе с постоянной обработкой событий WMI вам следует быть крайне внимательным. Рекомендуется разобраться с тем, как вы удаляете те объекты, которые относятся к соответствующему постоянному обработчику события. Обратите внимание, что пока вы не удалите эти записи в явном виде, WMI продолжит отслеживать ваш хост на предмет таких событий, что может приводить к излишнему потреблений ресурсов. |
Данный рецепт также демонстрирует полезный подход: создание функций PowerShell для отображения необходимой подписки на событие и последующее полное удаление такой подписки. Наконец, будьте внимательны при изменении времени обновления фильтра события (определяемого в самом фильтре события WMI). Уменьшение времени обновления соответствующего события способно потреблять дополнительно ЦПК и оперативную память. В большинстве случаев, частота обновления раз в секунду или даже каждые 5 секунд, возможно, непомерно перекрывает потребности. Для большинства событий более чем уместна проверка каждые 10 секунд.
В данном рецепте применяется присоединённый к домену хост SRV1
. В этом хосте у вас установлены
PowerShell 7 и VS Code.
Также проверьте что ваш пользователь Malcolm не выступает участником группы AD Enterprise Admins.
-
Создаём перечень допустимых пользователей для своей группы AD Enterprise Admins
$OKUsersFile = 'C:\Foo\OKUsers.Txt' $OKUsers = @' Administrator JerryG '@ $OKUsers | Out-File -FilePath $OKUsersFile
-
Определяем вспомогательные функции для получения/ удаления постоянных событий
Function Get-WMIPE { '*** Event Filters Defined ***' Get-CimInstance -Namespace root\subscription -ClassName __EventFilter | Where-Object Name -eq "EventFilter1" | Format-Table Name, Query '***Consumer Defined ***' $NS = 'ROOT\subscription' $CN = 'CommandLineEventConsumer' Get-CimInstance -Namespace $ns -Classname $CN | Where-Object {$_.name -eq "EventConsumer1"} | Format-Table Name, Commandlinetemplate '***Bindings Defined ***' Get-CimInstance -Namespace root\subscription -ClassName __FilterToConsumerBinding | Where-Object -FilterScript {$_.Filter.Name -eq "EventFilter1"} | Format-Table Filter, Consumer } Function Remove-WMIPE { Get-CimInstance -Namespace root\subscription __EventFilter | Where-Object Name -eq "EventFilter1" | Remove-CimInstance Get-CimInstance -Namespace root\subscription CommandLineEventConsumer | Where-Object Name -eq 'EventConsumer1' | Remove-CimInstance Get-CimInstance -Namespace root\subscription __FilterToConsumerBinding | Where-Object -FilterScript {$_.Filter.Name -eq 'EventFilter1'} | Remove-CimInstance }
-
Создаём запрос фильтра события
$Group = 'Enterprise Admins' $Query = @" SELECT * From __InstanceModificationEvent Within 10 WHERE TargetInstance ISA 'ds_group' AND TargetInstance.ds_name = '$Group' "@
-
Создаём фильтр необходимого события
$Param = @{ QueryLanguage = 'WQL' Query = $Query Name = "EventFilter1" EventNameSpace = "root/directory/LDAP" } $IHT = @{ ClassName = '__EventFilter' Namespace = 'root/subscription' Property = $Param } $InstanceFilter = New-CimInstance @IHT
-
Создаём сценарий
Monitor.ps1
, исполняемый при возникновении соответствующего события WMI$MONITOR = @' $LogFile = 'C:\Foo\Grouplog.Txt' $Group = 'Enterprise Admins' "On: [$(Get-Date)] Group [$Group] was changed" | Out-File -Force $LogFile -Append -Encoding Ascii $ADGM = Get-ADGroupMember -Identity $Group # Display who's in the group "Group Membership" $ADGM | Format-Table Name, DistinguishedName | Out-File -Force $LogFile -Append -Encoding Ascii $OKUsers = Get-Content -Path C:\Foo\OKUsers.txt # Look at who is not authorized foreach ($User in $ADGM) { if ($User.SamAccountName -notin $OKUsers) { "Unauthorized user [$($User.SamAccountName)] added to $Group" | Out-File -Force $LogFile -Append -Encoding Ascii } } "**********************************`n`n" | Out-File -Force $LogFile -Append -Encoding Ascii '@ $MONITOR | Out-File -Path C:\Foo\Monitor.ps1
-
Создаём потребителя события WMI
# The consumer runs PowerShell 7 to execute C:\Foo\Monitor.ps1 $CLT = 'Pwsh.exe -File C:\Foo\Monitor.ps1' $Param =[ordered] @{ Name = 'EventConsumer1' CommandLineTemplate = $CLT } $ECHT = @{ Namespace = 'root/subscription' ClassName = "CommandLineEventConsumer" Property = $param } $InstanceConsumer = New-CimInstance @ECHT
-
Связываем созданные фильтр и потребителя
$Param = @{ Filter = [ref]$InstanceFilter Consumer = [ref]$InstanceConsumer } $IBHT = @{ Namespace = 'root/subscription' ClassName = '__FilterToConsumerBinding' Property = $Param } $InstanceBinding = New-CimInstance @IBHT
-
Просматриваем подробности регистрации своего события
Get-WMIPE
-
Добавляем пользователя в свою группу Enterprise Admins
Add-ADGroupMember -Identity 'Enterprise admins' -Members Malcolm
-
Просматриваем файл
Grouplog.txt
Get-Content -Path C:\Foo\Grouplog.txt
-
Прибираемся
Remove-WMIPE # invoke this function you defined above $RGMHT = @{ Identity = 'Enterprise admins' Member = 'Malcolm' Confirm = $false } Remove-ADGroupMember @RGMHT Get-WMIPE # ensure you have removed the event handling
На Шаге 1 вы создаёте текстовый файл, содержащий два sAMAccountName
пользователей, который вы определили как тех, сто должен быть участником вашей группы Enterprise Admins. На Шаге 2
вы создаёте две вспомогательные функции, Get-WMIPE
и Remove-WMIPE
,
для просмотра и удаления соответствующих экземпляров класса WMI, который обрабатывает данное событие.
На Шаге 3 вы создаёте запрос фильтра события, который, на Шаге 4,
вы добавляете в WMI. Эти шаги не производят никакого вывода.
Когда происходит отслеживаемое постоянно событие WMI и изменяется соответствующее участие в группе, вы хотите исполнить определённый
сценарий PowerShell. На Шаге 5 вы создаёте файл C:\Foo\Monitor.ps1
,
что не производит никакого консольного вывода.
На Шаге 6 вы создаёте нового потребителя события, сообщая WMI о необходимости исполнения сценария наблюдения для выявления такого события. Затем, на Шаге 7 вы связываете созданного потребителя события и соответствующий фильтр события для завершения настройки постоянного обработчика события. Эти два шага не производят никакого вывода.
На Шаге 8 вы пользуетесь своей функцией Get-WMIPE
, которую вы
определили на Шаге 2 для просмотра подробностей фильтра рассматриваемого события. Вот как выглядит вывод
для этого шага:
На Шаге 9 вы проверяете настроенную постоянную обработку события,добавляя нового пользователя (Malcolm) в
свою группу Enterprise Admins. Данный шаг не производит консольного вывода, поскольку вы не добавили в Monitor.ps1
никаких операторов Write-Host
.
На Шаге 10 вы просматриваете свой файл Grouplog.txt
с подобным
приводимому ниже выводом:
На заключительном шаге этого рецепта, на Шаге 11, вы прибираетесь и вызываете свою созданную
на Шаге 2 функцию Remove-WMIPE
для удаления из WMI подробностей
своего события. В самом конце данного шага вы исполняете свою функцию Get-WMIPE
чтобы убедиться что вы
удалили все экземпляры класса подписки своего события. Вот как выглядит вывод на этом шаге:
На Шаге 5 вы создаёте сценарий, который вы бы хотели исполнять WMI всякий раз, когда изменяется
членство в вашей группе Enterprise Admins. Этот сценарий записывает подробности в текстовый файл
(Grouplog.txt
), содержащий значение времени когда произошло данное событие, своего нового участника
и содержит ли эта группа теперь каких- то пользователей без авторизации. Вы можете дополнить Monitor.ps1
на отправку электронного письма в почтовый ящик администрации или просто удалять такого пользователя без авторизации. Вы также можете
заглянуть в свой журнал событий Безопасности Windows чтобы отыскать самого последнего зарегистрировавшегося в этом сервере пользователя.
На Шаге 10 вы просматриваете вырабатываемый сценарием Monitor.ps1
вывод. Обратите внимание, что для вашего постоянного обработчика события может потребоваться несколько секунд чтобы выполнить этот
сценарий.
В данном рецепте вы создали две вспомогательные функции, Get-WMIPE
и
Remove-WMIPE
, для просмотра и удаления подробностей своего постоянного обработчика события. Вы также
можете вызывать эти функции в самом конце данного рецепта чт вы не оставили это постоянное событие целиком или частично настроенным.