当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

作者:精品下载站 日期:2024-12-14 08:08:55 浏览:13 分类:玩电脑

使用 PowerShell 和 WMI 处理事件(第 2 部分)


[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

在这篇博文中,我们将了解 WMI 事件。您将了解两种类型的 WMI 事件(外部事件和内部事件)以及如何使用 PowerShell 处理这两种事件。

这是我们“使用 PowerShell 处理事件”系列的第 2 部分。单击此处,查看使用 PowerShell 和 .NET 处理事件系列的第一部分

什么是 WMI 事件

WMI 代表 Windows 管理工具。 WMI 是 CIM(通用信息模型)的 Microsoft 实现。 CIM 是 DMTF(分布式管理任务组)的一个标准,它定义了如何表示系统信息。简而言之,CIM 是一个供应商中立的模型,用于表示系统信息。 Microsoft 对 CIM 的实现称为 WMI。

人们可以将 WMI 视为存储有关系统信息的数据库。但是我们如何查看这些信息以及它存储在哪里呢?在 Windows 系统上,您可以找到 WMI,如图所示。 1 下面。

C:\Windows\System32\wbem\Repository

[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

图 1:WMI 位置

Wmic 是与 WMI 交互的首选工具,但后来已被弃用。尽管它在 Windows 系统上仍然可用,但如果您尝试使用它,您将收到如图所示的消息。 2..

[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

图 2:已弃用的 WMIC 命令

展望未来 Microsoft 建议使用 PowerShell 与 WMI 交互。 PowerShell 具有内置的 cmdlet 来与 WMI 交互。这些被称为“WMI cmdlet”,但自 PowerShell 版本 3 起,它们已被弃用,取而代之的是 CIM cmdlet。在本文中,我们将使用 CIM cmdlet。为了查看可用的 CIM cmdlet,我们将使用我们最喜欢的名为 Get-Command 的 cmdlet

Get-Command -noun *CIM*

它为我们提供了以下 CIM cmdlet 列表:

Get-CimAssociatedInstance
Get-CimClass
Get-CimInstance
Get-CimSession
Invoke-CimMethod
New-CimInstance
New-CimSession
New-CimSessionOption
Register-CimIndicationEvent
Remove-CimInstance
Remove-CimSession
Set-CimInstance

为了完整起见,我们还可以使用以下 cmdlet 查看 PowerShell 中可用的 WMI cmdlet

Get-Command -noun *wmi*

产生以下列表:

Get-WmiObject
Invoke-WmiMethod
Register-WmiEvent
Remove-WmiObject
Set-WmiInstance

可以清楚地看到,CIM cmdlet 多于 WMI cmdlet。 CIM cmdlet 是未来,因此我们不会再谈论 WMI cmdlet。

前面提到,WMI是用来表示系统信息的,但是它是如何存储这些信息的呢?答案很简单:WMI 使用从命名空间开始的分层结构来存储和管理系统范围的信息。这些命名空间下面有各种类,每个类代表特定的系统信息。因此,例如 WIN32_DiskDrive 类用于表示磁盘驱动器上的信息。如果系统有磁盘驱动器,则此类将具有一个对象,该对象的属性和方法代表该系统的磁盘驱动器。

我们可以使用Get-CIMInstance cmdlet 与WMI 交互并查看该对象。 Get-CIMInstance 需要类名 作为参数之一。正如我们在图中看到的那样。 3,Get-CIMInstance cmdlet 返回Win32_DiskDrive 类的对象。该对象具有以下属性:DeviceIDCaptionPartitionsSizeModel ETC。

[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

图 3:Win32_DiskDrive 对象

让我们再举一个例子:假设——这在现代笔记本电脑上几乎不可能——我想要有关我的 CD-ROM 的信息?。 WMI 有 Win32_CDROMDrive 类,用于表示 CD-ROM 信息。让我们使用 Get-CIMInstance cmdlet 来获取该对象。

[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

图 4::没有 Win32_CDROMDrive 对象

由于我使用的是现代笔记本电脑,所以我没有 CD-ROM,因此我们的 cmdlet 没有返回任何对象(如图 4 所示)。
这里有两个有趣的观察结果:即使 CD-ROM 对象不存在,我们仍然可以查询该对象而不会收到错误,其次,即使系统上不存在 CD-ROM,WMI 仍然具有可用的 Win32_CDROMDrive 类

同样,我们可以通过WMI查询系统上所有正在运行的进程的信息,如下所示

[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

图 5:Win32_Process 类的对象

如果您需要更多信息或想要探索 WMI 中提供的其他类
有关 WMI 的 Microsoft 文档是一个不错的起点。

除了表示系统信息之外,WMI 还提供了一项强大的功能,称为“事件”。本质上,WMI 提供了监视系统范围事件并通知用户的功能。 WMI 中有两种类型的事件:内部事件和外部事件。

固有 WMI 事件

内在事件与 WMI 本身联系更紧密。它们是为了响应 WMI 结构的变化而触发的。例如,如果系统上创建了一个新进程,则会导致为 WIN32_Process 类创建一个新实例,这将导致 __Instancecreationevent 类型的事件。另一个示例是在 WMI 中创建一个新类,这将导致 __ClassCreationEvent 类型的事件。

就像 WMI 中的所有内容都表示为对象一样,事件也表示为对象,并且每个事件类型都有一个关联的类,如下所示。然而,要记住的一件事是,这些代表事件的对象是短暂的,因此我们在创建事件过滤器时使用池化,否则我们可能会错过这些正在创建的对象。

以下是不同类型的内在事件:

__NamespaceOperationEvent, 
__NamespaceModificationEvent,
__NamespaceDeletionEvent, 
__NamespaceCreationEvent,
__ClassOperationEvent 
__ClassDeletionEvent, 
__ClassModificationEvent,
__ClassCreationEvent, 
__InstanceOperationEvent, 
__InstanceCreationEvent,
__MethodInvocationEvent, 
__InstanceModificationEvent,
__InstanceDeletionEvent, 
__TimerEvent


外部 WMI 事件

外部事件是根据底层操作系统级别的更改生成的。这是一个主要区别,内部事件在 WMI 结构内寻找变化,而外部事件在操作系统级别寻找 WMI 之外的变化。例如,计算机关闭事件是操作系统级别的事件,因此它被归类为外部事件。外部事件不需要池化。

以下是不同类型的外部事件:

Win32_ComputerShutdownEvent,
Win32_IP4RouteTableEvent,
Win32_ProcessStartTrace,
Win32_ModuleLoadTrace,
Win32_ThreadStartTrace, 
Win32_VolumeChangeEvent,
Msft_WmiProvider*,
RegistryKeyChangeEvent,
RegistryValueChangeEvent

为了处理这些事件,我们需要了解过滤器的概念,但在讨论过滤器之前,我们先快速转到WQL
WQL是 WMI 查询语言,类似于 SQL。它使用与 SQL 相同的语法来查询 WMI 信息。
有关 WQL 的更多信息可以在 Microsoft 文档站点上找到。

使用 WQL 进行事件过滤器

我们使用 WQL 来创建事件过滤器。 过滤器可以被视为寻找特定事件的搜索条件

让我们举个例子:假设我们想要捕获一个新的进程创建事件,特别是计算器进程。为此,我们需要创建一个 WQL 查询来定义捕获此事件的过滤器。在本例中,我们希望捕获进程名称为“calc.exe”的 WIN32_Process 类的新实例的创建,一旦捕获此事件,我们就希望采取行动。对于这个具体示例,我们要打印“WMI is Awesome”。

让我们首先使用 WQL 定义过滤器,在本例中我们正在寻找实例创建事件,因此我们的查询以

Select * from __InstanceCreationEvent

接下来,由于这是一个内在事件,我们需要定义池间隔,因此我们的 WQL 查询变为

Select * from __InstanceCreationEvent within 10

接下来,我们需要定义我们要寻找哪个类实例?因此,我们将该信息添加到我们的查询中

Select * from __InstanceCreationEvent within 10 where TargetInstance ISA “Win32_Process”

接下来,我们需要具体说明我们正在寻找的实例类型,在本例中,我们正在寻找名称属性为“calc.exe”的流程实例,因此我们的 WQL 查询最终如下所示。

Select * from __InstanceCreationEvent within 10 where TargetInstance ISA “Win32_Process” and TargetInstance.Name like “%calc%”

现在我们已经定义了过滤器,我们需要订阅事件并定义观察到事件后要采取的操作。

为此,我们将使用 Register-CimInductionEvent cmdlet。 Register-CimInductionEvent cmdlet 需要以下参数来订阅事件(如图 6 所示)

-wqlQuery
-SourceIdentifier
-Action

-SouceIdentifier 参数可以提供用户定义的名称。

[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

图 6:WMI 临时事件订阅

如果 cmdlet 成功,您将收到一条如图 1 所示的消息。 7. 表示我们已成功订阅该活动。

[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

图7:事件订阅成功

正如您所观察到的,一旦我启动 calc.exe 进程,我就会在屏幕上看到消息“WMI is Awesome”。

在您退出 PowerShell 命令提示符之前,此操作正常。由于这是一个临时事件订阅,因此它取决于创建它的进程的生命周期,在我们的例子中是 PowerShell 命令提示符。一旦我们退出父进程,我们就会失去订阅。

WMI 提供永久的 WMI 事件订阅,这使得我们的订阅永久并持续系统重新启动。

这给我们带来了在开始构建永久事件订阅之前需要理解的下一个重要概念。有3个主要概念需要理解

  • 事件过滤器
  • 事件消费者
  • 事件过滤器到消费者的绑定

事件过滤器

我们在上一个示例中已经见过事件过滤器,如前面提到的事件过滤器用于订阅特定事件。您可以将它们视为查找特定事件的搜索条件。但有一个区别:在上一个示例中,我们定义了过滤器并以 WQL 查询的形式将其提供给 Register-CimInspirationEvent cmdlet,如果是永久事件订阅,我们将在以下位置创建过滤器: WQL,但是我们随后将初始化 __EventFilter 类的对象,并将过滤器作为该对象的属性之一提供。

事件消费者

一旦我们的事件过滤器符合条件,我们就会采取某些操作,就像我们在临时事件订阅示例中所做的那样。对于永久事件订阅,我们有五种不同消费者类别提供的五种操作类型可供选择。

  • LogFileEventConsumer:写入日志文件。
  • ActiveScriptEventConsumer:执行脚本。
  • NTEventLogEventConsumer:写入Windows事件日志。
  • SMTPEventConsumer:发送电子邮件。
  • CommandLineEventConsumer:命令行执行。

就像事件过滤器的情况一样,一旦我们知道要采取什么操作,我们需要初始化该类的对象并为其提供某些属性的值。

一旦定义了事件过滤器和消费者,剩下的唯一工作就是将它们连接在一起,过滤器到消费者的绑定正是为我们做的。我们创建一个 __FilterToConsumerBinding 类的对象,并为其提供 Filter 和 Consumer 对象的值。

示例:设置永久 WMI 事件订阅

举个例子,假设我们想在用户插入 USB 设备时生成事件日志。我们可以使用 WMI 事件轻松地做到这一点。

这是一个三步过程:

  1. 我们首先为表示“用户插入 USB 记忆棒”的事件定义过滤器
  2. 然后我们定义一个Consumer,当该Filter与Event匹配时生成Event日志
  3. 最后,过滤器到消费者的绑定将事件过滤器与合法的消费者连接起来

图 8 显示了该过程的示意图。

[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

图8:永久WMI事件订阅流程

New-CimInstance cmdlet 用于创建 CIM 类的实例,如果与 CimSession 参数一起使用,则可用于在远程计算机上创建实例。

在我们的脚本中,我们使用 New-CIMInstance cmdlet 为 EventFilterEventConsumerFilterToConsumer 类创建实例。

话虽如此,让我们将所有这些整合在一起并创建我们的第一个 WMI 事件订阅:

第 1 步:首先,我们为过滤器定义 WQL 查询:

$WQLQuery = 'SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE TargetInstance ISA "Win32_USBControllerDevice"'

当 USB 设备插入系统时,会创建一个新的 WIN32_USBControllerDevice 实例,因此我们正在寻找实例创建事件。 现在,我们定义过滤器,如下所示:

$WMIFilterInstance = New-CimInstance -ClassName __EventFilter -Namespace "rootsubscription" -Property @{Name="myFilter";
                 EventNameSpace="rootcimv2";
                 QueryLanguage="WQL";
                 Query=$WQLQuery
                }

正如您所注意到的,我们正在创建一个 __EventFilter 类的对象并将其存储在 $WMIFilterInstance变量中。我们还为此对象的一些属性提供值,最重要的是NameQuery

第 2 步:接下来,我们定义消费者,在我们的例子中,我们想要生成事件日志,因此我们创建一个 NTEventLogEventConsumer 类的实例。

$WMIEventConsumer = New-CimInstance -ClassName NTEventLogEventConsumer -Namespace "rootsubscription" -Property  @{Name="USBLogging";
                        EventId = [uint32] 1; EventType = [uint32] 4; #EventType can have following values; Error 1, FailureAudit 16, Information 4, SuccesAudit 8, Warning 2
                        SourceName="PowerShell-Script-Log"; Category= [uint16] 1000 } #Category is never really used but can have any value and basically meant to provide more information about the event

需要记住的一些事情是 EventIDEventType 属性,sourceName 也用于定义事件的来源。<br>
第 3 步:最后,我们将过滤器与消费者绑定。

$WMIWventBinding = New-CimInstance -ClassName __FilterToConsumerBinding -Namespace "rootsubscription" -Property @{Filter = [Ref] $WMIFilterInstance;
                    Consumer = [Ref] $WMIEventConsumer
                    }

您可能会注意到,为了创建过滤器到消费者的绑定,我们需要为之前创建的对象提供 Filter 和 Consumer 属性的值。您可以在我的 GitHub 存储库中找到我正在使用的完整脚本

执行后,此脚本将创建永久事件订阅。下次用户插入 USB 设备时,您会注意到 Windows 事件日志中创建了一个条目,如图 1 所示。 9 和图。 10 以下。

[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

图 9:Windows 事件日志

[玩转系统] 使用 PowerShell 和 WMI 处理事件(第 2 部分)

图 10:显示事件 ID 和来源的事件日志

删除事件订阅

在结束这篇博文之前,最后要注意的是:如果我们想删除永久事件订阅,我们需要执行以下三个命令:

Get-CimInstance -ClassName __EventFilter -namespace rootsubscription -filter "name='myFilter'" | Remove-CimInstance

Get-CimInstance -ClassName NTEventLogEventConsumer -Namespace rootsubscription -filter "name='FolderWriteLogging'" | Remove-CimInstance

Get-CimInstance -ClassName __FilterToConsumerBinding -Namespace rootsubscription -Filter "Filter = ""__eventfilter.name='myFilter'""" | Remove-CimInstance

Get-CimInstance cmdlet 返回使用 ClassName 参数指定的类的对象,我们将其传递给 Remove-CimInstance cmdlet 进行删除。有关 GetCimInstance 的更多信息可以在 Microsoft 文档中找到。

结论

正如您所注意到的,我们可以利用 WMI 事件来监视整个系统的各种变化。 WMI 是一项功能强大的技术,但系统管理员仍然不了解它。 PowerShell 为我们提供了有用的 cmdlet,使我们能够轻松地与 WMI 交互和使用。我希望本文能够鼓励读者更多地了解 WMI 并利用 PowerShell 将这项技术用于有趣的项目。

完全控制、完全可追溯

您可以通过使用 ScriptRunners Report/Audit DB Connector 进一步利用您的监控功能。它允许您将所有有关脚本执行的报告存储在一个中央存储库中,并为您提供所有流程的完整可追溯性。

来源

  • Windows Management Instrumentation - Win32 应用程序 | Windows Management Instrumentation微软文档
  • WQL(用于 WMI 的 SQL)- Win32 应用程序 |微软文档
  • 通用信息模型 (CIM) | DMTF
  • 基于 Web 的企业管理 (WEBM) | DMTF

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯