PowerShell: как отменить потерянные события WMI - PullRequest
0 голосов
/ 03 января 2019

Следующий блок кода сгенерирует 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% ЦП.Если затем выполняется следующее, подписки на события удаляются и WmiPrvSE.exe падает до нормального уровня использования ЦП или закрывается вообще:

Get-EventSubscriber | Unregister-Event

Все это работает, как ожидалось.Однако, если окно PowerShell закрывается до запуска Get-EventSubscriber | Unregister-Event, WmiPrvSE.exe не завершается и продолжает использовать 30% -40% ЦП.Когда клавиатура вставлена, строка больше не записывается в файл.Если открывается новое окно PowerShell, Get-EventSubscriber или Get-EventSubscriber -Force не может найти подписчиков события.Если все экземпляры WmiPrvSE.exe принудительно закрыты, они запускаются снова и продолжают потреблять 30% -40% ЦП. Даже после выхода из системы и повторного входа WmiPrvSE.exe продолжает потреблять ЦП. Единственный найденный мной способ завершить эти подписки на события - это перезагрузить компьютер.

Как завершить работуподписки на события, которые были начаты в предыдущем сеансе PowerShell?

Обновление


Я обнаружил, что использование ЦП потерянными подписками на события можно прекратить, вызвав событие, на которое они подписаны.даже если кажется, что они не запускают код в блоке действий после закрытия окна PowerShell.Таким образом, в этом случае при подключении клавиатуры после закрытия PowerShell WmiPrvSE.exe возвращается к своему нормальному поведению.Это похоже на то, что подписки на события ожидают запуска события в последний раз, прежде чем их можно будет очистить, но теперь они принадлежат самой системе WMI.

1 Ответ

0 голосов
/ 03 января 2019

Это потенциальная копия этих вопросов и ответов.

Unregister-Event не удаляет потерянные подписки на события

Цитата из сообщения:

У меня была такая же проблема с таймером.Я как-то оставил таймер с тем же именем SourceIdentifier в моем сеансе PowerShell.Когда бы я ни ждал своего 10-секундного таймера, он всегда возвращался немедленно.

Я сохранял выходные данные Wait-Event и мог получить доступ к EventIdentifier, который позволил мне удалить Remove-Event с помощью EventIdentifier.Если бы я использовал SourceIdentifier, я бы не смог получить доступ к потерянному событию.Я мог сказать, что это было осиротевшим, исследуя выходные данные моего Wait-Event.TimeGenerated, который был старым.Вам нужно будет иметь доступ к потерянному событию с помощью уникального EventIdentifier.

Код сообщения:

$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
...