Мне нужно наблюдать, когда определенные процессы запускаются или останавливаются на машине с Windows. В настоящее время я подключаюсь к системе WMI и запрашиваю ее каждые 5 секунд, но это вызывает скачок производительности процессора каждые 5 секунд, потому что WMI - это WMI. Есть ли лучший способ сделать это? Я мог бы просто составить список запущенных процессов и прикрепить к ним событие Exited через пространство имен System.Diagnostics, но обработчика событий для создания нет.





Это не совсем то, как вы бы сделали это в реальном мире, но должно помочь. Похоже, это совсем не сильно влияет на мой процессор.
static void Main(string[] args)
{
// Getting all instances of notepad
// (this is only done once here so start up some notepad instances first)
// you may want use GetProcessByPid or GetProcesses and filter them as required
Process[] processesToWatch = Process.GetProcessesByName("notepad");
foreach (var process in processesToWatch)
{
process.EnableRaisingEvents = true;
process.Exited +=
(s, e) => Console.WriteLine("An instance of notepad exited");
}
Thread watchThread = new Thread(() =>
{
while (true)
{
Process[] processes = Process.GetProcesses();
foreach (var process in processes)
{
Console.WriteLine("{0}:{1}", process.Id, process.ProcessName);
}
// Don't dedicate a thread to this like I'm doing here
// setup a timer or something similiar
Thread.Sleep(2000);
}
});
watchThread.IsBackground = true;
watchThread.Start();
Console.WriteLine("Polling processes and waiting for notepad process exit events");
Console.ReadLine();
}
Я использовал похожую технику для отслеживания всех запусков и завершений процессов. Даже при очень маленьком спящем режиме (50 мсек) в цикле мой процессор работает на ~ 0%. Как только PID получен таким образом, я вызываю Win32_Process и получаю дополнительную информацию о процессе, которой нет (или которую трудно получить без создания исключения) через класс Process.
У меня были скачки ЦП при прослушивании событий WMI в тех случаях, когда мне не удавалось должным образом отсоединиться от событий при выходе / очистке. Возможно, вы захотите проверить, не происходит ли «утечка» подписок на события WMI. На всякий случай отключитесь от мероприятия как можно раньше и убедитесь, что вы всегда это делаете.
Чтобы проиллюстрировать это дальше, вот пример из моя книга PowerShell, который прослушивает события WMI с помощью библиотеки PSEventing:
Add-PSSnapin PSEventing -ErrorAction SilentlyContinue
$queryString = @' SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_Service' AND TargetInstance.Name = 'w3svc' AND TargetInstance.State = 'Stopped' '@
$query = New-Object System.Management.WQLEventQuery ` -argumentList $queryString
$watcher = New-Object System.Management.ManagementEventWatcher($query)
Connect-EventListener watcher EventArrived
$watcher.Start()
echo "Waiting for the W3CSVC service to stop..." Get-Event -wait |
foreach {Write-Host -foreground Red "The W3SVC service has stopped!" }$watcher.Stop()
Disconnect-EventListener watcher EventArrived
echo "done"
Если я не использую бит Disconnect-EventListener при выходе из скрипта, я получаю скачки ЦП в третий или четвертый раз, когда я присоединяюсь к событию. Я предполагаю, что система все еще пытается доставить события.
Если вы ищете только PID / имя ваших процессов, вы можете вместо этого захотеть получать события Win32_ProcessTrace, используя WQL-запрос, такой как «SELECT * FROM Win32_ProcessTrace WHERE TargetInstance.ProcessName = 'name'» если это применимо*.
Ошибка использования «SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32Process' AND TargetInstance.Name = 'name'» заключается в том, как это работает на серверной части. Если вы проверите wbemess.log в каталоге% windir% \ system32 \ wbem \ logs, вы заметите следующие журналы (с использованием __InstanceDeletionEvent):
(Wed Jul 22 13:58:31 2009.73889577) : Registering notification sink with query select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process' in namespace //./root/CIMV2. (Wed Jul 22 13:58:31 2009.73889577) : Activating filter 047209E0 with query select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process' in namespace //./root/CIMV2. (Wed Jul 22 13:58:31 2009.73889577) : Activating filter 0225E560 with query select * from __ClassOperationEvent where TargetClass isa "Win32_Process" in namespace //./root/CIMV2. (Wed Jul 22 13:58:31 2009.73889577) : Activating filter 'select * from __ClassOperationEvent where TargetClass isa "Win32_Process"' with provider $Core (Wed Jul 22 13:58:31 2009.73889587) : Activating filter 'select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process'' with provider $Core (Wed Jul 22 13:58:31 2009.73889587) : Instituting polling query select * from Win32_Process to satisfy event query select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process' (Wed Jul 22 13:58:31 2009.73889587) : Executing polling query 'select * from Win32_Process' in namespace '//./root/CIMV2' (Wed Jul 22 13:58:31 2009.73889697) : Polling query 'select * from Win32_Process' done (Wed Jul 22 13:58:41 2009.73899702) : Executing polling query 'select * from Win32_Process' in namespace '//./root/CIMV2' (Wed Jul 22 13:58:41 2009.73899792) : Polling query 'select * from Win32_Process' done
Как видите, реальная реализация события на удаленном компьютере заключается в выполнении запроса к Win32_Process в интервале, который указан вашим значением в предложении WITHIN. В результате любые процессы, которые запускаются и останавливаются в этом опросе, никогда не вызовут событие.
Вы можете установить для предложения WITHIN небольшое значение, чтобы попытаться минимизировать этот эффект, но лучшим решением является использование истинного события, такого как Win32_ProcessTrace, которое должно срабатывать всегда.
* Обратите внимание, что MSDN указывает, что Win32_ProcessTrace требует для работы как минимум Windows XP на клиентском компьютере и Windows 2003 на сервере. Если вы работаете с более старой ОС, вы можете застрять при использовании запроса __InstanceModificationEvent.
В моем ответе здесь упоминается альтернатива, отличная от WMI: https://stackoverflow.com/a/50315772/3721646 Запросы WMI могут значительно снизить производительность ЦП, если они не спроектированы должным образом. Если внутреннее событие из класса Win32_Process используется для отслеживания события создания процесса, это сильно влияет на производительность. Альтернативный подход - использовать журналы аудита безопасности. Вы можете включить отслеживание процессов с помощью локальной политики безопасности или с помощью объекта групповой политики в случае нескольких компьютеров. После запуска отслеживания процессов вы можете подписаться на журналы событий безопасности с помощью настраиваемого XML-запроса для отслеживания определенных процессов, которые вас интересуют. Идентификатор события создания процесса - 4688. `
<QueryList>
<Query Id = "0" Path = "Security">
<Select Path = "Security">
*[EventData[Data[@Name='NewProcessName'] ='C:\Windows\explorer.exe']]
and
*[System[(EventID=4688)]]
</Select>
</Query>
</QueryList>
Это тот путь, по которому я пошел после того, как не смог заставить WMI быть лучше для меня.