Pergunta

Eu preciso assistir quando certos processos são iniciados ou parados em uma máquina Windows. Atualmente estou aproveitado para o sistema WMI e consultando-lo a cada 5 segundos, mas isso faz com que a CPU pico a cada 5 segundos, porque WMI é WMI. Existe um jeito melhor de fazer isso? Eu poderia apenas fazer uma lista de processos em execução e anexar um evento Exited a eles através do Namespace System.Diagnostics, mas não há nenhum manipulador de eventos para a criação.

Foi útil?

Solução

Este não é exatamente como você faria no mundo real, mas deve ajudar. Isto parece não dirigir meu CPU muito em tudo.

    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();
    }

Outras dicas

Eu tive picos de CPU quando ouvir eventos WMI nos casos em que não conseguiram separar adequadamente dos meus eventos de saída / limpeza. Você pode querer verificar que você não está "vazando" inscrições de evento WMI. Apenas no caso de desconexão do evento o mais cedo possível e certifique-se que você sempre fazê-lo.

Para ilustrar ainda mais, aqui está um exemplo de meu livro PowerShell que escutas para eventos WMI usando a biblioteca PSEventing:

Add-PSSnapin PSEventing -ErrorAction SilentlyContinue

$ queryString = @' SELECT * DE __InstanceModificationEvent Dentro de 10 ONDE TargetInstance ISA 'Win32_Service' E TargetInstance.Name = 'w3svc' E TargetInstance.State = 'Parado' '@

$ query = New-Object System.Management.WQLEventQuery ` -ArgumentList $ queryString

$ observador = New-Object System.Management.ManagementEventWatcher ($ query)

Connect-EventListener observador EventArrived

$ watcher.Start ()

echo "Esperando o serviço W3CSVC a parada ..." Get-Event -wait | foreach { Write-Host -foreground Red "O serviço W3SVC parou!" }

$ watcher.Stop ()

Desconectar-EventListener observador EventArrived

echo "feito"

Se eu não fizer o Desconectar-EventListener pouco após a saída de script, recebo picos de CPU a terceira ou quarta vez que atribuo ao evento. Meu palpite é que o sistema ainda tenta entregar eventos.

Se você está apenas procurando PID / Nome de seus processos, você pode em vez disso quiser pegar em eventos Win32_ProcessTrace, usando uma consulta WQL como "SELECT * FROM Win32_ProcessTrace ONDE TargetInstance.ProcessName = 'nome'" se aplicável * .

A armadilha de usar "SELECT * FROM __InstanceModificationEvent dentro de 10 ONDE TargetInstance ISA 'Win32Process' E TargetInstance.Name = 'nome'" está na forma como ele funciona no back-end. Se você inspecionar wbemess.log dentro de sua% windir% \ system32 \ wbem \ logs, você vai notar os seguintes logs (usando __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

Como você pode ver, a implementação evento real na máquina remota é a realização de uma consulta em relação Win32_Process em um intervalo especificado pelo seu valor na cláusula WITHIN. Como resultado, todos os processos que iniciar e parar dentro dessa pesquisa nunca vai acionar um evento.

Você pode definir a cláusula WITHIN para um valor pequeno para tentar minimizar este efeito, mas a melhor solução é usar um verdadeiro evento como Win32_ProcessTrace, que deve sempre fogo.

* Nota que MSDN indica Win32_ProcessTrace requer um mínimo de Windows XP em uma máquina cliente e Windows 2003 em uma máquina servidor ao trabalho. Se você estiver trabalhando com um sistema operacional mais antigo, você pode ser preso usando a consulta __InstanceModificationEvent.

A minha resposta aqui menciona uma outra alternativa senão WMI: https://stackoverflow.com/a/50315772/3721646 consultas WMI pode custar o desempenho da CPU pesado se não projetada corretamente. Se um evento intrínseco da classe Win32_Process é usado para rastrear evento de criação processo, este afeta o desempenho fortemente. Uma abordagem alternativa é aproveitar os logs de auditoria de segurança. Você pode ativar o controle de processos utilizando a política de segurança local ou usando um GPO em caso de várias máquinas. Uma vez que o rastreamento processo começa, você pode se inscrever para logs de eventos de segurança com uma consulta XML personalizado para monitorar determinados processos de seu interesse. O evento ID criação processo é 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>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top