以下代码块将生成 100 个 WMI 事件订阅。这种特殊情况只是一个示例,只要插入键盘,就会将字符串写入文件(100 次):
$KeyboardQuery = "SELECT * FROM __InstanceCreationEvent Within 1 WHERE TargetInstance ISA 'Win32_Keyboard'"
for ($i = 0; $i -lt 100; $i++) {
Register-WmiEvent -Query $KeyboardQuery -Action {
"A keyboard was just inserted." >> ~\event-log.txt
}
}
在 PowerShell 中执行此操作时,进程 WmiPrvSE.exe
消耗30%-40%的CPU。如果随后执行以下操作,则删除事件订阅并 WmiPrvSE.exe
降至正常水平的 CPU 使用率或完全关闭:Get-EventSubscriber | Unregister-Event
这一切都按预期工作。但是,如果 PowerShell 窗口在运行前关闭 Get-EventSubscriber | Unregister-Event
, WmiPrvSE.exe
不退出,继续消耗30%-40%的CPU。插入键盘后,不再将字符串写入文件。如果打开一个新的 PowerShell 窗口,Get-EventSubscriber
或 Get-EventSubscriber -Force
找不到事件订阅者。如果 WmiPrvSE.exe
的所有实例被强制关闭,它们再次启动并继续消耗 30%-40% 的 CPU。 即使在注销并重新登录后,WmiPrvSE.exe
继续消耗CPU。 我发现结束这些事件订阅的唯一方法是重新启动计算机。如何结束在之前的 PowerShell session 中启动的事件订阅?
更新
我发现孤立事件订阅的 CPU 使用率可以通过触发它们订阅的事件来结束,即使在 PowerShell 窗口关闭后它们似乎没有运行操作 block 中的代码。所以在这种情况下,关闭 PowerShell 后插入键盘会导致
WmiPrvSE.exe
恢复其正常行为。就像事件订阅正在等待最后一次触发事件才能被清理,但现在归 WMI 系统本身所有。
最佳答案
这是此问答的潜在副本。
Unregister-Event not removing orphaned event subscriptions
引用帖子:
I had the same problem with a timer. I had somehow left a timer with the same SourceIdentifier name in my PowerShell session. Whenever I would wait for my 10 second timer, it would always return immediately.
I saved the output of the Wait-Event and could access the EventIdentifier, which allowed me to Remove-Event by the EventIdentifier. If I used the SourceIdentifier, I could not access the orphaned event. I could tell it was orphaned by examining the output of my Wait-Event.TimeGenerated, which was old. You will need to be able to access the orphaned event by the EventIdentifier which is unique.
帖子中的代码:
$eventDone = "Done"
$job2 = Register-ObjectEvent -InputObject $timer2 -EventName Elapsed -SourceIdentifier $eventDone
$timer2.Interval = 10000;
$timer2.AutoReset = $false;
$timer2.Enabled = $true;
$waitEvent = Wait-Event -SourceIdentifier $eventDone;
# Look at the $waitEvent.TimeGenerated for a clue it is old
# use the $waitEvent.EventIdentifier to access the event and remove it
$orphanEventID = $waitEvent.EventIdentifier
Remove-Event -EventIdentifier $orphanEventID
关于PowerShell:如何取消注册孤立的 WMI 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54016050/