了解吗,您可以监控Windows中的几乎每个操作?不,您不需要购买一些花哨的软件。基础设施监控事件,例如服务启动和停止,有人创建文件或文件夹等等,已经通过Windows管理工具(WMI)事件存在。
WMI事件不是PowerShell特有的功能,但是利用WMI事件并创建一些方便的工具的最简单方法之一是使用PowerShell。在这个分步教程中,您将学习如何利用PowerShell获取WMI事件,并掌握构建一些方便的监控工具的技能!
让我们开始吧!
先决条件
在这个实践教程中,您将看到许多演示。如果您想跟着任何演示进行操作,请确保您具备以下条件:
- Windows 7+或Windows Server 2012+ – 本教程将使用Windows Server 2019。
- 以本地管理员组中的用户身份登录。
- Windows PowerShell 5.1或PowerShell 6+ – 本教程将使用PowerShell v7.1.2。
了解WMI和CIM
在您深入研究WMI事件之前,首先要了解构建在其上的基础设施。尽管本教程不会深入介绍WMI,但您可以随时参考微软的WMI文档以获取更多信息。
WMI及其相關的數據模型通用信息模型(CIM)是內置於Windows中的模型,用於存儲與Windows內部運作和運行的任何信息相關的儲存庫。
WMI和CIM是管理員在本地和遠程管理Windows的強大工具。使用WMI或CIM,管理員可以查詢Windows系統上的信息,如已安裝應用程序、服務狀態、文件系統中的文件,以及幾乎所有其他信息。
WMI和CIM是許多企業監控解決方案收集操作系統和應用程序健康信息的工具。但您無需購買昂貴的監控工具來利用WMI;您可以使用PowerShell!
讓我們從兩個基本元素開始,隨著我們的進展,您將學習到其他所需的元素:
- 類: 類是應用程序(如PowerShell)可以調用以讀取和更新數據的事件和屬性。類位於命名空間內。
- 命名空間: 命名空間是WMI相關類的容器。可以將其視為包含與圖片相關內容的My Picture文件夾。有多個命名空間,其中最常見的是CIMv2,它包含大多數OS類。但是,所有命名空間都位於大的單一命名空間Root

WMI與CIM
WMI 和 CIM 都是與 Windows 系統上的存儲庫進行交互的方法,其中包含大量信息並且可以使用 WMI 事件(稍後會談到)來處理。但是,這兩種方法有一些不同之處,主要是管理員遠程交互的方式。
WMI 開始於 Windows NT4,並且是與存儲庫交互的原始(也是唯一)方式。當您使用 WMI 管理 Windows 系統時,Windows 使用 分佈式組件對象模型(DCOM)。DCOM 是 WMI 使用的一種遠程協議,用於在 Windows 機器上公開存儲庫中的信息。
為了在網絡上工作,DCOM 使用 遠程過程調用(RPC)。為了在網絡上通信,RPC 使用動態端口範圍,這對防火牆和網絡地址轉換(NAT)設備有時是一個挑戰。
如果您在使用 RPC 方面遇到問題,請查看文章 使用動態端口測試 RPC 連接。
Microsoft決定利用CIM以提供與Windows中的數據存儲庫進行更現代交互的方法。CIM使用WS-MAN(Web-Service for Management)而不是RPC,這是一種更適合遠程管理的HTTP協議。
在本文和其他文章中,WMI和CIM可能可互換使用。這兩種管理方法互動的數據存儲庫通常被稱為WMI存儲庫。幾乎所有術語都指的是WMI,而CIM通常在PowerShell cmdlets中提到。
WMI與CIM和PowerShell
幸運的是,對於WMI和CIM在PowerShell中的交互,你有一些選擇。PowerShell支持與數據存儲庫互動的兩種方式。當你在PowerShell中運行Get-Command
命令時,你可能會注意到各種Wmi
cmdlets,如Get-WmiObject
、Invoke-WmiMethod
、Remove-WmiObject
、Register-WmiEvent
和Set-WmiInstance
。
如果你正在運行Windows PowerShell 3或更高版本(你最好是!),你還會看到一些名稱類似的cmdlets,如Get-CimInstance
、Get-CimClass
和Remove-CimInstance
。
你應該使用哪個PowerShell cmdlets?答案很簡單;使用CIM cmdlets。CIM是微軟專注的新標準。WMI cmdlets甚至在PowerShell Core中都不可用!
查詢 WMI:基礎知識
在你開始使用 WMI 事件之前,你必須了解如何使用 PowerShell 查詢 WMI。從 WMI 存儲庫中查詢信息是 WMI 數據的最常見用法。
在 PowerShell 世界中查詢 WMI 數據,Get-CimInstance
cmdlet 是你的好朋友。這個 cmdlet 有幾種不同的方法來查詢 WMI 數據。但是,本教程將專注於 Query
參數。 Query
參數允許你提供一個 Windows 查詢語言(WQL)查詢來查詢 WMI。
例如,也許你想找到 Win32_Service
類中的所有 WMI 實例。與 SQL 類似,你會使用查詢 Select * from Win32_Service
,如下所示。星號 (*
) 告訴 WMI 返回找到的每個實例的所有屬性。

在上面的例子中,你找到了 所有 在 Win32_Service
類中的每個服務實例,但是如果你只想找到幾個呢?在這種情況下,你會使用 WHERE
子句。 WHERE
子句創建一個過濾器,僅返回與特定條件匹配的實例。
WHERE
子句告訴Get-CimInstance
僅在實例屬性匹配特定值的情況下返回實例。例如,也許您只想找到State
屬性為Running
的服務實例。如果是這樣,您將定義WHERE
子句Where State='Running'
,如下所示。
您可以看到Get-CimInstance
僅返回State
屬性等於Running
的服務實例。

WMI事件:WMI的操作
WMI包含有關Windows中數千個項目的大型存儲庫的信息。您可以通過與上面相同的方式查詢它來獲取該信息,但它還具有另一個不太知名的功能;WMI事件。
在Windows中,任何時候都可能發生數百個事件。當您使用Windows的各種功能,例如創建文件、停止和啟動服務、安裝軟件或其他任何操作時,可能會觸發WMI事件。
幾乎在Windows上執行的每個操作都可以通過WMI事件公開。當在Windows上執行操作時,Windows通過其內部基礎架構觸發事件。默認情況下,您無法看到這些事件;它們正在後台發生。要查看這些事件,您必須訂閱它們。
使用PowerShell構建服務監視腳本
為了演示WMI事件的工作原理,而不是用大量信息來使您厭煩,讓我們來建立一個有用的工具。由於WMI事件在Windows中發生時觸發,因此您可以使用它們創建一些方便的監視工具。
也许你想在关键服务器上的 Windows 服务状态发生变化时写入消息到日志文件。然后,你可以订阅这些动作触发的 WMI 事件。当你订阅事件并且事件触发时,你可以执行一些动作,比如记录到文件、发送电子邮件,或者其他你可以用 PowerShell 做的事情。
与购买昂贵的监控解决方案不同,一个简单的 PowerShell 脚本可以成为一个很棒的穷人监控工具!如果你准备好了,请打开你的 PowerShell 控制台,让我们开始吧!
查找 CIM 类
在 WMI 中,像静态实例一样,事件包含在类中。这些类包含了你上面查询的所有静态数据,以及触发对这些实例的更改。你可以在微软文档中找到所有 CIM 类的列表。
要查找所有 CIM 类,请运行Get-CimClass
命令而不带任何参数。Get-CimClass
命令默认返回ROOT/cimv2
命名空间中的所有类。ROOT/cimv2
命名空间是存储几乎所有有趣的 Windows 类的“主”命名空间。
然而,你可以看到下面返回了很多类。

也許你已經做了一些調查,最終意識到 Windows 服務都存儲在 Win32_Service
中。因此,當你知道類名時,請使用 ClassName
參數指定名稱,如下所示。

尋找 CIM 類屬性
一旦你知道要查看的類是什麼,接下來你必須弄清楚要查看的屬性是什麼。當實例屬性的值發生變化(或者整個實例被創建或移除時),會觸發一個事件。你必須捕獲那個狀態的變化。為了做到這一點,你必須知道你想要監視的是哪個屬性。
要找到該屬性,請檢查在上一節中查詢的 CIM 類實例上的 CimClassProperties
PowerShell 物件屬性。
請注意下面其中一個屬性是 State
屬性。

現在你知道你想要監視的 CIM 類和屬性是什麼,是時候訂閱 WMI 事件了!
構建 WMI 事件訂閱:高級概述
如果你以前從未創建過 WMI 事件訂閱,那麼創建一個可能是一個令人困惑的任務。為了幫助你保持行動一致,讓我們首先在開始討論具體步驟之前先從整體上概述基本步驟。
創建 WMI 事件訂閱需要四個大致步驟:
- 製作 WQL 查詢 – 就像查詢靜態數據時一樣,您必須創建一個符合您想查看的 WMI 事件類型的 WQL 查詢。但是,與查詢數據存儲不同,您必須在查詢中使用一些更複雜的組件,如系統類和檢查週期(稍後會談到更多內容)。
- 創建事件篩選器 – 一旦您創建了 WQL 查詢,您必須創建事件篩選器。事件篩選器將 WQL 查詢註冊在 CIM 中。
- 創建使用者 – 當事件篩選器查詢返回類中的變化時,使用者定義要採取的操作。例如,每當服務狀態啟動、停止、創建或刪除時,使用者就會觸發一個動作。
- 將事件篩選器綁定到使用者 – 將 Windows WMI 查詢與使用者連接在一起的膠水。綁定是在事件篩選器收到匹配時通知使用者的方法。
將這些項目組合在一起時,您就創建了一個訂閱。

製作 WQL 查詢
A WQL query for a WMI event looks a bit different than performing a simple query with Get-CimInstance
. Below you’ll find a typical WMI event query.
由於一開始 WQL 查詢可能看起來很嚇人,讓我們將其拆解並了解每個組件的工作原理。
系統類
在Get-CimInstance
示例中,您已經發現希望在Win32_Service
類的實例發生更改時收到通知。您仍然需要此類,但是不是像這樣的 WQL 查詢:
相反,查询将以以下方式开始。您查询的主要类不是包含您希望接收通知的实例的类。相反,该类是一个系统类。
系统类是表示事件引发的更改类型的内部类。WMI事件有四种类型的系统类:
- InstanceModificationEvent – 检查类中实例的任何属性值更改。您将使用此类,因为您希望监视
Win32_Service
类的一个实例(服务)上的属性值Status
。 - InstanceCreationEvent – 检查任何新实例。例如,如果您想监视任何新创建的服务,您将使用此系统类。
- InstanceDeletionEvent – 检查任何已删除的实例。例如,如果您想监视已删除的服务,您将使用此系统类。
- InstanceOperationEvent – 此系统类检查所有事件类型,包括修改、创建和删除。
对于我们的监视脚本,WQL查询的开头将如下所示:
WMI 系統類別名稱總是以兩個底線 (__) 開頭,後面跟著類別名稱。
檢查週期
接下來,您有檢查週期。檢查週期包括關鍵字 within
和代表以秒為單位的輪詢間隔的值。
WMI 事件不是即時的,因此您必須為訂閱定義一定的間隔以檢查變更。例如,如果您將檢查週期設定為 10,則訂閱將每 10 秒檢查上一次輪詢週期以尋找變更。如果發現變更,則觸發消費者。
如果在輪詢間隔內根據系統類別更改、創建或刪除實例,則不會檢測到變更!請考慮您需要的頻率,但請確保它對 CPU 和內存友好!
對於教程中的服務監控示例,讓我們將檢查週期設定為 10,以每 10 秒輪詢 WMI 以尋找 Windows 服務的變更。WQL 查詢正在增加!
過濾器
最後,為了完成 WQL 查詢,您必須定義一個過濾器以限制從系統類別返回的實例。您必須以以下形式定義該過濾器。在這種情況下,您想要監視的 CIM 類別稱為 TargetInstance
。
ISA
是一個運算符,它將查詢應用於指定類別的子類別。
由於教程正在建立一個用於監視 Windows 服務的訂閱,您將像下面這樣創建過濾器:
以下是翻譯:
如今,該過濾器尋找所有 Win32_Service
實例。如果您只想監視單個屬性,例如特定服務,您應該使用 AND
運算符。
教程過濾器(以及整個查詢)現在已經完成,如下面的代碼片段所示。
創建事件過濾器
既然您有了查詢過濾器,餘下的過程就容易理解多了!您現在必須創建事件過濾器以使用該查詢。事件過濾器實際上是 __EventFilter
類 中的另一個 CIM 實例,位於 Root/subscription
命名空間中。
以下是包含所需内容的代码片段。下面的脚本将WQL查询分配给$FilterQuery
变量。然后创建一个包含事件过滤器所需属性和值的哈希表。然后运行New-CimInstance
cmdlet来创建事件过滤器。
生成的CIM实例对象随后存储在变量($CIMFilterInstance
)中以供以后使用。
现在,运行Get-CimInstance
来验证是否已创建新的__EventFilter
的CIM实例。

创建消费者
接下来,是创建消费者或在Windows触发WMI事件时将发生的操作的时候了。创建消费者时,根据您希望触发的操作类型,您有几个选项。
- ActiveScriptEventConsumer – 執行使用任意腳本語言(如VBscript)編寫的腳本。
- CommandLineEventConsumer – 啟動一個進程。
確保可執行檔的ACL正確定義,以防止有人將EXE替換為惡意二進制檔。
- LogFileEventConsumer – 創建一個文本日誌。
- NTEventLogEventConsumer – 將事件寫入Windows事件日誌。
- SMTPEventConsumer – 發送電子郵件。
在本教程中,讓我們使用LogFileEventConsumer
消費者類型,在符合WQL查詢的服務發生變化時寫入一個日誌檔案。
每个消费者类都有自己的参数,因此请查看
CimClassProperties
以获取有关每个类的更多详细信息,例如(Get-CimClass -ClassName __NTEventLogEventConsumer).CimClassProperties
。
创建消费者后,再次使用Get-Ciminstance
检查其是否存在。

将事件过滤器和消费者绑定在一起
最后,是时候完成这个订阅并将事件过滤器和消费者绑定在一起了!正如你可能猜到的那样,创建绑定意味着创建一个更多的CIM实例。这次你必须在__FilterToConsumerBinding
类中创建一个新的实例。
下面的代码片段使用之前创建的两个实例(过滤器和消费者)作为哈希表,定义了创建新实例所需的属性。然后将其像以前一样传递给New-CimInstance
以创建绑定。
如往常一样,通过再次运行Get-CimInstance
来确认绑定已创建。
如你所见,绑定包含了有关Filter
和Consumer
的信息。

测试订阅
你终于完成了!现在是时候测试你努力的成果了!你现在需要做的唯一一件事就是改变BITS服务的状态,看看PowerShell是否会将一个条目写入到C:\MyCIMMonitoring.txt的日志文件中。
根据BITS服务的状态,停止、启动或仅仅使用Restart-Service
命令重新启动它。
等待大約10秒,然後檢查C:\MyCIMMonitoring.txt。現在你應該在創建消費者時定義的日誌文件中看到文字。

要監視所有WMI事件活動,請查看路徑應用程序和服務日誌\Microsoft\Windows\WMI-Activity\Operational中的Windows事件日誌。
停止並清理訂閱
完成訂閱後,是清理的時候了。要停止並刪除WMI事件訂閱,必須刪除事件篩選器、消費者和綁定實例。
首先通過使用Get-CimInstance找到實例來刪除事件篩選器。

接下來,以相同的方式刪除消費者。

最後,刪除綁定。找到綁定的屬性略有不同。綁定實例不是使用Name屬性,而是使用一個Filter屬性,它實際上是一個帶有Name屬性的對象。

結論
WMI/CIM是一個方便而強大的系統,用於查找有關Windows的信息並使用WMI事件進行監視。使用WMI事件監視變化能夠為您提供很好的可見性,並更快地對可能出現的問題做出反應,使得對每個事件自動化響應變得更加容易。
對於一個很好的現實世界例子,請查看如何使用WMI事件跟蹤Active Directory更改。
Source:
https://adamtheautomator.com/your-goto-guide-for-working-with-windows-wmi-events-and-powershell/