A harmadik típusú események, amelyeket a PowerShell képes kezelni és reagálni rájuk, a WMI események. Ilyen eseményekkel a WMI objektumok létrejöttére, megszűnésére és változására lehet reagálni. Ilyen lehet például az IP-címzéssel, videó beállításokkal, megosztások és processzek megszűnésével vagy létrejöttével, és szolgáltatások leállásával vagy indításával kapcsolatot események.
A WMI események alapját egy lekérdezés adja, ami kiszűri a lehetséges több ezer WMI objektum közül azokat, amelyek valamilyen jellegű változására kíváncsiak vagyunk. Ennek a lekérdezésnek az általános szerkezete:
SELECT <Properties> FROM <EventClass> WITHIN <másodperc> WHERE TargetInstance ISA '<WmiClass>' AND '<OtherCriteria>'…
A fenti kifejezésben a
lehetséges EventClass kategóriák a következők lehetnek:
__InstanceCreationEvent – akkor következik be, ha egy WMI osztály egy
példánya létrejön
__InstanceDeletionEvent – akkor következik be, ha egy WMI osztály egy
példánya megszűnik
__InstanceModificationEvent – akkor következik be, ha egy WMI osztály egy
példányának valamely tulajdonsága megváltozik
__InstanceOperationEvent – akkor következik be, ha a fentiek közül
bármelyik bekövetkezik
(Az eseményosztályok
nevében fontos a két aláhúzás az elején!)
Ezek alapján első
nekifutásra összeraktam egy olyan lekérdezést, ami a szolgáltatások körében
bekövetkező bármilyen változásra reagál:
[9] PS C:\> $wmiquery = "select * from
__InstanceModificationEvent within 1 whe
re TargetInstance ISA 'Win32_Service'"
Ezzel regisztrálom is a
PowerShell eseményfigyelőt, méghozzá olyan tevékenységgel, hogy adja át az
általa érzékelt eseménnyel kapcsolatos paramétereket egy globális változóba, és
jelezze a képernyőn, hogy valami történt:
[42] PS C:\> Register-WmiEvent -Query $wmiquery
-Action {$global:wmievent = $ev
entargs; write-host "Esemény történt!"}
Ezután leállítom az egyik
szolgáltatást, nézzük, mi történik, illetve mi lesz a globális $wmievent változóm tartalma:
Esemény történt!
[46] PS C:\> $wmievent
NewEvent Context
-------- -------
System.Management.ManagementBaseObject {}
[47] PS C:\> $wmievent.NewEvent
__GENUS
: 2
__CLASS
: __InstanceModificationEvent
__SUPERCLASS
: __InstanceOperationEvent
__DYNASTY
: __SystemClass
__RELPATH
:
__PROPERTY_COUNT
: 4
__DERIVATION
: {__InstanceOperationEvent, __Event, __IndicationRelated,
__SystemClass}
__SERVER
: DC
__NAMESPACE
: //./root/CIMV2
__PATH
:
PreviousInstance
: System.Management.ManagementBaseObject
SECURITY_DESCRIPTOR :
TargetInstance
: System.Management.ManagementBaseObject
TIME_CREATED
: 129116550251633750
Ennek a $wmievent objektumnak minket leginkább érdeklő
tulajdonságai a TargetInstance, ami azt adja meg, hogy a változás után mi lett
az eseményt kiváltó WMI példány, és a PreviousInstance, ami azt adja meg, hogy mi volt a változás előtti
WMI példány. Ezen két objektum tulajdonságainak összevetésével ki lehet
mutatni, hogy pontosan mi is változott:
[48] PS C:\> $wmievent.NewEvent.TargetInstance
__GENUS : 2
__CLASS : Win32_Service
__SUPERCLASS : Win32_BaseService
__DYNASTY : CIM_ManagedSystemElement
__RELPATH :
Win32_Service.Name="msiserver"
__PROPERTY_COUNT : 25
__DERIVATION : {Win32_BaseService, CIM_Service,
CIM_LogicalElement,
CIM_ManagedSystemElement}
__SERVER : DC
__NAMESPACE : root\CIMV2
__PATH :
\\DC\root\CIMV2:Win32_Service.Name="msiserver"
AcceptPause : False
AcceptStop : False
Caption : Windows Installer
CheckPoint : 0
CreationClassName : Win32_Service
Description : Adds, modifies, and removes
applications provided as
a Windows Installer
(*.msi) package. If this servic
e is disabled, any
services that explicitly depend o
n it will fail to
start.
DesktopInteract : False
DisplayName : Windows Installer
ErrorControl : Normal
ExitCode : 0
InstallDate :
Name : msiserver
PathName :
C:\Windows\system32\msiexec.exe /V
ProcessId : 0
ServiceSpecificExitCode : 0
ServiceType : Own Process
Started : False
StartMode : Manual
StartName : LocalSystem
State : Stopped
Status : OK
SystemCreationClassName : Win32_ComputerSystem
SystemName : DC
TagId : 0
WaitHint : 0
[49] PS C:\>
$wmievent.NewEvent.PreviousInstance
__GENUS : 2
__CLASS : Win32_Service
__SUPERCLASS : Win32_BaseService
__DYNASTY : CIM_ManagedSystemElement
__RELPATH :
Win32_Service.Name="msiserver"
__PROPERTY_COUNT : 25
__DERIVATION : {Win32_BaseService, CIM_Service,
CIM_LogicalElement,
CIM_ManagedSystemElement}
__SERVER : DC
__NAMESPACE : root\CIMV2
__PATH :
\\DC\root\CIMV2:Win32_Service.Name="msiserver"
AcceptPause : False
AcceptStop : True
Caption : Windows Installer
CheckPoint : 0
CreationClassName : Win32_Service
Description : Adds, modifies, and removes
applications provided as
a Windows Installer
(*.msi) package. If this servic
e is disabled, any
services that explicitly depend o
n it will fail to
start.
DesktopInteract : False
DisplayName : Windows Installer
ErrorControl : Normal
ExitCode : 0
InstallDate :
Name : msiserver
PathName :
C:\Windows\system32\msiexec.exe /V
ProcessId : 1632
ServiceSpecificExitCode : 0
ServiceType : Own Process
Started : True
StartMode : Manual
StartName : LocalSystem
State : Running
Status : OK
SystemCreationClassName : Win32_ComputerSystem
SystemName : DC
TagId : 0
WaitHint : 0
Sajnos ezt így szemre
áttekinteni elég nehéz, ezért készítettem egy objektumtulajdonság
összehasonlító Compare-ObjectProps függvényt. Ez paraméterként két objektumot vár,
meg lehet adni összehasonlító üzemmódot (eq: csak az egyforma tulajdonságokat jeleníti meg, ne: eltérő tulajdonságokat jeleníti meg, all: minden tulajdonságot megjelenít), és Include paraméterként meg lehet adni, hogy mik azok a
tulajdonságok, amiket mindenképpen szeretnénk látni:
function Compare-Objectprops ($o1,$o2,$mode = "all",[string[]] $include)
{
$props = @($o1 | Get-Member -MemberType Properties
| % {$_.name})
$o2 | Get-Member -MemberType Properties
|
% {$_.name} | ?{$props -notcontains
$_} | %{$props += $_}
$mat = @{}
$props | %{$mat.$_ = @($o1.$_,$o2.$_)}
foreach($key in $mat.keys)
{
if($include -contains $key)
{
New-Object -TypeName psobject -Property
@{
name = $key;
Object1 = $mat.$key[0];
Object2 = $mat.$key[1]}
}
else
{
switch($mode)
{
"eq" {if($mat.$key[0] -eq $mat.$key[1]){
New-Object -TypeName
psobject -Property @{
name = $key;
Object1 = $mat.$key[0];
Object2 = $mat.$key[1]}
break}}
"ne" {if($mat.$key[0] -ne $mat.$key[1]){
New-Object -TypeName
psobject -Property @{
name = $key;
Object1 = $mat.$key[0];
Object2 = $mat.$key[1]}
break}}
"all" {New-Object -TypeName psobject -Property
@{
name = $key;
Object1 = $mat.$key[0];
Object2 = $mat.$key[1]}}
}
}
}
}
Nézzük, ezzel mit láthatunk:
[54] PS C:\> Compare-Objectprops
$wmievent.NewEvent.PreviousInstance $wmievent.
NewEvent.TargetInstance -mode ne -include
displayname
name Object2 Object1
---- ------- -------
DisplayName Windows Installer Windows Installer
AcceptStop False True
State Stopped Running
ProcessId 0 3140
Started False True
__DERIVATION {Win32_BaseService, CI...
{Win32_BaseService, CI...
Látható, hogy a Windows
Installer szolgáltatást
állítottam le, ez okozta az eseményt, hiszen a korábbi állapot (Object1 oszlop) volt a „Running”, most meg „Stopped”.
Az előbb látott objektumok (TargetInstance és PreviousInstance) a WMI eseménylekérdezésben is felhasználható. Azaz ha én csak olyan jellegű szolgáltatás-változásokra vagyok kíváncsi, amikor a szolgáltatás leállt, és arra nem vagyok kíváncsi, amikor egy szolgáltatás elindult, akkor a lekérdezést így lehet pontosítani:
[62] PS C:\> $wmiquery = "select * from __InstanceModificationEvent within 1 wh
ere TargetInstance ISA 'Win32_Service' AND targetinstance.State = 'Stopped'"
[63] PS C:\> Register-WmiEvent -Query $wmiquery -Action {$global:wmievent = $ev
entargs; write-host "Esemény történt!"}
WARNING: column "Command" does not fit into the display and was removed.
Id Name State HasMoreData Location
-- ---- ----- ----------- --------
5 c2fbcf0d-af2... NotStarted False
[64] PS C:\> Esemény történt!
Compare-Objectprops $wmievent.NewEvent.PreviousInstance $wmievent.NewEvent.Targ
etInstance -mode ne -include displayname | ft name, object1, object2
name Object1 Object2
---- ------- -------
DisplayName Windows Installer Windows Installer
AcceptStop True False
State Running Stopped
Status Degraded OK
ProcessId 3608 0
Started True False
__DERIVATION {Win32_BaseService, CI... {Win32_BaseService, CI...
A fenti példa úgy született, hogy töröltem a korábbi eseményfigyelést, és a módosított WMI lekérdezés létrehozása és az eseményfigyelés regisztrálása után elindítottam a korábban leállított Windows Installer szolgáltatást. Erre nem történt semmi, ellenben amikor újra leállítottam, akkor megkaptam a fenti eseményjelzést.