Domanda

Devo controllare quando alcuni processi vengono avviati o arrestati su un computer Windows. Attualmente sto intercettando il sistema WMI e lo interrogo ogni 5 secondi, ma questo provoca un picco della CPU ogni 5 secondi perché WMI è WMI. C'è un modo migliore per farlo? Potrei semplicemente fare un elenco di processi in esecuzione e allegare loro un evento Exited tramite lo spazio dei nomi System.Diagnostics, ma non esiste un gestore eventi per la creazione.

È stato utile?

Soluzione

Questo non è esattamente come lo faresti nel mondo reale, ma dovrebbe aiutare. Questo non sembra guidare molto la mia CPU.

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

Altri suggerimenti

Ho avuto picchi di CPU durante l'ascolto di eventi WMI nei casi in cui non sono riuscito a staccare correttamente dai miei eventi all'uscita / pulizia. Potresti voler verificare di non aver " perdite " Abbonamenti eventi WMI. Nel caso in cui ti stacchi dall'evento il prima possibile e assicurati di farlo sempre.

Per illustrare ulteriormente, ecco un esempio da il mio libro PowerShell che ascolta agli eventi WMI utilizzando la libreria PSEventing:

  

Add-PSSnapin PSEventing -ErrorAction   SilentlyContinue

     

$ queryString = @ '       SELEZIONA *       DA __InstanceModificationEvent       ENTRO 10       DOVE           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)

     

Watcher Connect-EventListener   EventArrived

     

$ watcher.Start ()

     

echo " In attesa del servizio W3CSVC   per interrompere ... " Get-Event -wait |       foreach {           Write-Host -foreground Red " Il servizio W3SVC si è interrotto! & Quot;       }

     

$ watcher.Stop ()

     

Disconnect-EventListener watcher EventArrived

     

echo " done "

Se non eseguo il bit Disconnect-EventListener all'uscita dallo script, ottengo picchi di CPU la terza o quarta volta che mi collego all'evento. La mia ipotesi è che il sistema tenta ancora di fornire eventi.

Se stai solo cercando PID / Nome dei tuoi processi, potresti invece voler raccogliere su eventi Win32_ProcessTrace, usando una query WQL come " SELECT * FROM Win32_ProcessTrace DOVE TargetInstance.ProcessName = 'name' " se applicabile * .

La trappola dell'uso di " SELECT * DA __InstanceModificationEvent ENTRO 10 DOVE TargetInstance ISA 'Win32Process' AND TargetInstance.Name = 'name' " è come funziona sul back-end. Se controlli wbemess.log nella directory% windir% \ system32 \ wbem \ logs, noterai i seguenti registri (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

Come puoi vedere, l'implementazione dell'evento effettivo sul computer remoto è di eseguire una query su Win32_Process su un intervallo specificato dal valore nella clausola WITHIN. Di conseguenza, tutti i processi che si avviano e si interrompono all'interno di quel sondaggio non genereranno mai un evento.

Puoi impostare la clausola WITHIN su un valore piccolo per cercare di ridurre al minimo questo effetto, ma la soluzione migliore è utilizzare un evento vero come Win32_ProcessTrace, che dovrebbe sempre attivarsi.

* Si noti che MSDN indica che Win32_ProcessTrace richiede un minimo di Windows XP su un computer client e Windows 2003 su un computer server per funzionare. Se stai lavorando con un sistema operativo precedente, potresti essere bloccato usando la query __InstanceModificationEvent.

La mia risposta qui menziona un'alternativa diversa da WMI: https://stackoverflow.com/a/50315772/3721646 Le query WMI possono costare elevate prestazioni della CPU se non progettate correttamente. Se un evento intrinseco della classe Win32_Process viene utilizzato per tenere traccia dell'evento di creazione del processo, ciò influisce pesantemente sulle prestazioni. Un approccio alternativo è quello di sfruttare i log di audit di sicurezza. È possibile abilitare il monitoraggio dei processi utilizzando la politica di sicurezza locale o utilizzando un oggetto Criteri di gruppo in caso di più macchine. Una volta avviato il tracciamento del processo, è possibile iscriversi ai registri degli eventi di sicurezza con una query XML personalizzata per monitorare determinati processi di proprio interesse. L'ID evento di creazione del 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>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top