Pregunta

Necesito mirar cuando ciertos procesos se inician o detienen en una máquina con Windows. Actualmente estoy conectado al sistema WMI y lo consulta cada 5 segundos, pero esto provoca un pico de CPU cada 5 segundos porque WMI es WMI. ¿Hay una mejor manera de hacer esto? Podría hacer una lista de los procesos en ejecución y adjuntarles un evento Exited a través del espacio de nombres System.Diagnostics, pero no hay un controlador de eventos para la creación.

¿Fue útil?

Solución

Esto no es exactamente cómo lo haría en el mundo real, pero debería ayudar. Esto parece no conducir mi CPU mucho en absoluto.

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

Otros consejos

He tenido picos de CPU al escuchar eventos WMI en los casos en que no he podido desconectarme correctamente de mis eventos al salir / limpiar. Es posible que desee comprobar que no tiene "fugas" Suscripciones a eventos WMI. Solo en caso de que se desconecte del evento lo antes posible y asegúrese de hacerlo siempre.

Para ilustrar más, aquí hay un ejemplo de mi libro de PowerShell que escucha a eventos WMI utilizando la biblioteca PSEventing:

  

Add-PSSnapin PSEventing -ErrorAction   SilentlyContinue

     

$ queryString = @ '       SELECCIONAR *       DE __InstanceModificationEvent       Dentro de 10       DÓNDE           TargetInstance ISA 'Win32_Service'           Y TargetInstance.Name = 'w3svc'           Y TargetInstance.State = 'Detenido' '@

     

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

     

$ watcher = Nuevo-Objeto   System.Management.ManagementEventWatcher ($ query)

     

Observador Connect-EventListener   EventArrived

     

$ watcher.Start ()

     

echo " Esperando el servicio W3CSVC   para parar ... '' Get-Event -wait |       foreach {           Write-Host -foreground Red " ¡El servicio W3SVC se ha detenido! & Quot;       }

     

$ watcher.Stop ()

     

Disconnect-EventListener watcher EventArrived

     

echo " hecho "

Si no hago el bit Disconnect-EventListener al salir del script, obtengo picos de CPU la tercera o cuarta vez que lo adjunto al evento. Supongo que el sistema todavía intenta entregar eventos.

Si solo está buscando PID / Nombre de sus procesos, es posible que desee retomar los eventos Win32_ProcessTrace, utilizando una consulta WQL como " SELECT * FROM Win32_ProcessTrace WHERE TargetInstance.ProcessName = 'name' " si corresponde * .

La trampa de usar " SELECT * FROM __InstanceModificationEvent DENTRO DE 10 DONDE TargetInstance ISA 'Win32Process' Y TargetInstance.Name = 'name' " está en cómo funciona en el back-end. Si inspecciona wbemess.log dentro de su directorio% windir% \ system32 \ wbem \ logs, notará los siguientes registros (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 puede ver, la implementación del evento real en la máquina remota es realizar una consulta en Win32_Process en un intervalo que se especifica por su valor en la cláusula WITHIN. Como resultado, cualquier proceso que comience y se detenga dentro de esa encuesta nunca activará un evento.

Puede establecer la cláusula WITHIN en un valor pequeño para intentar minimizar este efecto, pero la mejor solución es usar un evento verdadero como Win32_ProcessTrace, que debería siempre activarse.

* Tenga en cuenta que MSDN indica que Win32_ProcessTrace requiere un mínimo de Windows XP en una máquina cliente y Windows 2003 en una máquina servidor para funcionar. Si está trabajando con un sistema operativo anterior, es posible que esté atascado con la consulta __InstanceModificationEvent.

Mi respuesta aquí menciona una alternativa que no sea WMI: https://stackoverflow.com/a/50315772/3721646 Las consultas WMI pueden costar un alto rendimiento de la CPU si no se diseñan correctamente. Si se usa un evento intrínseco de la clase Win32_Process para rastrear el evento de creación de procesos, esto impacta fuertemente el rendimiento. Un enfoque alternativo es aprovechar los registros de Auditoría de Seguridad. Puede habilitar el seguimiento de procesos utilizando la política de seguridad local o un GPO en el caso de varias máquinas. Una vez que comienza el seguimiento del proceso, puede suscribirse a los registros de eventos de seguridad con una consulta XML personalizada para monitorear ciertos procesos de su interés. El ID de evento de creación del proceso es 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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top