PowerShell订阅事件监控


声明:本文来自《亚克西~》的网易博客,感谢原作者的整理。

在日常工作中,相信有的朋友会遇到以下类似的问题情境。比如我们希望用脚本监视某一个服务是否正常运行,如果服务突然停止了的话,脚本可以在很短时间内发现这一情况并尝试启动服务。又比如,我们希望用脚本监视某一个文件夹下文件的创建、修改和删除事件,并把相关情况记录下来,供管理员日后查看。这样的情况还有很多,总结起来就是我们希望使用脚本对某一类事件进行监视,然后当触发特定条件后,脚本就会采取相应的措施。在之前的VBScript时代,脚本专家已经在TechNet上为我们准备好了一些示例代码,我们可以很方便的查阅和使用。

而当历史的车轮来到PowerShell 1.0 时代时,我们发现v1版本的PowerShell中没有提供相关的cmdlet可以帮助我们简单的实现事件监视这一任务。最终我们不得不同时维护着古老的VBScript脚本以及崭新的PowerShell脚本。这一情况在v2版本的PowerShell中已经发生了变化,PowerShell开发团队为我们加入了相关的cmdlet来支持事件监视。我们还是可以使用老办法“Get-Command *event -CommandType cmdlet”来查看相关的cmdlet(Get-WinEvent除外):

PS> Get-Command -Noun *event
CommandType Name                        ModuleName
----------- ----                        ----------
Cmdlet      Get-Event                   Microsoft.PowerShell.Utility
Cmdlet      Get-WinEvent                Microsoft.PowerShell.Diagnostics
Cmdlet      New-Event                   Microsoft.PowerShell.Utility
Cmdlet      New-WinEvent                Microsoft.PowerShell.Diagnostics
Cmdlet      Register-CimIndicationEvent CimCmdlets
Cmdlet      Register-EngineEvent        Microsoft.PowerShell.Utility
Cmdlet      Register-ObjectEvent        Microsoft.PowerShell.Utility
Cmdlet      Register-WmiEvent           Microsoft.PowerShell.Management
Cmdlet      Remove-Event                Microsoft.PowerShell.Utility
Cmdlet      Unregister-Event            Microsoft.PowerShell.Utility
Cmdlet      Wait-Event                  Microsoft.PowerShell.Utility

接下来我们就来说说如何在PowerShell V2中使用事件监视。
首先我们需要使用动词部分为Register的cmdlet来订阅相关事件。大家可以从上图中看到动词部分为Register的cmdlet共有三个,分别是Register-EngineEventRegister-ObjectEventRegister-WMIEvent。它们负责订阅不同对象产生的事件,Register-EngineEvent订阅由PowerShell产生的事件,Register-ObjectEvent订阅由.NET对象产生的事件,Register-WMIEvent则订阅由WMI产生的事件。在订阅完成后,相关对象所产生的事件都被加入到事件队列中。我们可以使用Get-Event来查看。最后,如果我们不需要再进行事件监视的时候则需要使用Unregister-Event cmdle来取消对事件的订阅。此时所有已经产生的事件还是存在于事件队列之中,需要使用Remove-Event来删除。接下来让我们来看看如何订阅这三种不同类型的事件。

订阅PowerShell产生的事件

通过刚才的介绍,我们已经知道可以使用Register-EngineEvent来订阅PowerShell产生的事件,下面就来看看具体的代码:

Register-EngineEvent -SourceIdentifier ([System.Management.Automation.PSEngineEvent]::Exiting) -Action {
Out-File c:\PowerShell\a.txt -InputObject (Get-History)}

以上代码的作用是在PowerShell退出时,将本次会话中使用的命令导出到文本文件中。这里一共用到了两个参数,下面就来说说这两个参数的作用。首先是SourceIdentifier,参数类型是字符串,用来表示唯一的事件源。在上面的代码中([System.Management.Automation.PSEngineEvent]::Exiting)代表的就是PowerShell结束运行的事件,实际上它就是PowerShell.Exiting字符串。而Action参数则是事件发生后所要执行的操作,它的类型是ScriptBlock,我们可以将相关代码包含在花括号中作为其参数值。

在上面的代码中,我利用Out-File cmdlet将Get-History cmdlet得到的相关命令的历史记录导出到指定的文本文件中。这里需要注意的是如果我们指定了Action参数,那么相关事件就不会被发送到PowerShell的事件队列中,也就是说我们无法使用Get-Event查看事件队列中的相关信息。

订阅.NET对象产生的事件

接下来我们要来看看如何订阅.NET对象产生的事件。这里我将使用System.IO.FileSystemWatcher来进行演示。该类的作用是用来监视文件系统的相关活动。先来看看先关代码:

$FSW = New-Object System.IO.FileSystemWatcher 
$FSW.Path = "C:\PowerShell" Register-ObjectEvent -InputObject $FSW -EventName Created -SourceIdentifier FSW.Created

首先我们利用New-Object创建了System.IO.FileSystemWatcher类的一个实例。接着我们设置该实例的Path属性,该属性用来指定需要监视的文件夹。当然如果我们要监视该文件夹下所有子文件夹的话,可以将该实例的IncludeSubdirectories属性设置为$True。接下来我们利用Register-ObjectEvent cmdlet来订阅该对象产生的事件。然后我们来看看相关参数。首先是InputObject,代表产生事件的对象,这里当然是System.IO.FileSystemWatcher类的实例$FSW。接着我们看到的是EventName,从属性名中我们不难看出这是具体事件名。在上面的代码中使用的是Created,该事件在对象创建时触发,我们当然也可以指定其它的事件,如果不清楚其它事件的名称则可以通过以下命令查看:

PS> $FSW | Get-Member –MemberType Event


   TypeName:System.IO.FileSystemWatcher

Name     MemberType Definition
----     ---------- ----------
Changed  Event      System.IO.FileSystemEventHandler Changed(System.Object, System.IO.FileSystemEventArgs)
Created  Event      System.IO.FileSystemEventHandler Created(System.Object, System.IO.FileSystemEventArgs)
Deleted  Event      System.IO.FileSystemEventHandler Deleted(System.Object, System.IO.FileSystemEventArgs)
Disposed Event      System.EventHandler Disposed(System.Object, System.EventArgs)
Error    Event      System.IO.ErrorEventHandler Error(System.Object, System.IO.ErrorEventArgs)
Renamed  Event      System.IO.RenamedEventHandler Renamed(System.Object, System.IO.RenamedEventArgs)

接下来,我们可以在指定的文件夹中创建一个文件或文件夹,然后使用Get-Event来看看我们的代码有没有正确执行,结果如下:

PS> Get-Event

ComputerName     :
RunspaceId       : 4e20511c-407e-45f8-8854-6dc7f5e28265
EventIdentifier  : 353
Sender           : System.IO.FileSystemWatcher
SourceEventArgs  : System.IO.FileSystemEventArgs
SourceArgs       : {System.IO.FileSystemWatcher, 新建位图图像.bmp}
SourceIdentifier : FSW.Created
TimeGenerated    : 2014/9/6 23:13:23
MessageData      :

订阅WMI产生的事件

最后再来看看如何订阅WMI产生的事件。演示中我将监视Spooler服务是否停止,如果停止了则自动尝试启动服务,下面来看看相关代码:

$query = @" 
Select * From __instancemodificationevent Within 5 Where TargetInstance isa 'Win32_Service' And TargetInstance.Name = 'Spooler' And TargetInstance.State = 'Stopped' "@
Register-WmiEvent -Query $query -Action {Start-Service Spooler}

以上代码最关键的部分还是相关的WQL查询语句,__instancemodificationevent代表实例的修改事件,Within后跟的是秒数,代表每5秒查询一次,然后我们使用Where来限制实例为处于停止状态的后台打印服务。接下来我们就可以使用Register-WmiEvent来订阅相关事件,当相关事件发生后,脚本就会执行我们指定的操作:启动打印服务

原文作者:亚克西~
原文链接PowerShell – 事件监视

本文链接: https://www.pstips.net/monitor-event.html
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!

关于 Mooser Lee

我是一个Powershell的爱好者,创建了PowerShell中文博客,热衷于Powershell技术的搜集和分享。本站部分内容来源于互联网,不足之处敬请谅解,并欢迎您批评指正。

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注