简体   繁体   中英

C#-friendly alternatives to WMI for iterating remote processes by Owner?

We have some code that works, but too slowly. We use a System.Management.ManagementObjectSearcher to run an ObjectQuery for "Select * from Win32_Process). We then iterate the returned list, call "GetOwner" (via InvokeMethod) to see if the process is by the user we are searching for, and then call "Terminate" (also via InvokeMethod).

With some additional exception handling to account for processes that terminate while they are being iterated, this works, but on the machines with many thousands of processes we need to run this on, it takes fully an hour to iterate all the processes.

Is there an alternative that doesn't involve having a footprint on the target server? The remote part is key to what we're doing. If we have to go local, we have the option of the win32 api, but I imagine WMI would be fast enough if run locally.

Unfortunally the WMI is very slow to retrieve the owner of a process if you want improve the performance then you must use the WInAPi functions OpenProcessToken and CloseHandle .

Check this sample

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Security.Principal;
using System.Runtime.InteropServices;

namespace ConsoleApplicationTest
{
    class Program
    {
        static uint TOKEN_QUERY = 0x0008;

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CloseHandle(IntPtr hObject);


        static void Main(string[] args)
        {
            foreach (Process p in Process.GetProcesses())
            {
                IntPtr TokenHandle = IntPtr.Zero;
                try
                {
                    OpenProcessToken(p.Handle, TOKEN_QUERY, out TokenHandle);
                    WindowsIdentity WinIdent = new WindowsIdentity(TokenHandle);
                    Console.WriteLine("Pid {0} Name {1} Owner {2}", p.Handle, p.ProcessName, WinIdent.Name);
                }
                catch (Exception Ex)
                {
                    Console.WriteLine("{0} in {1}", Ex.Message, p.ProcessName);
                }
                finally
                {
                    if (TokenHandle != IntPtr.Zero) { CloseHandle(TokenHandle); }
                }
            }
            Console.ReadKey();
        }
    }
}

I'm not sure which one works slowly, iteration or invoking method. I'm guessing it's probably the latter one.

  • Can you try ManagementClass.GetInstances() instead of running a wmi query?
  • Try to iterate over the returned WMI instances and cache them into a queue. Then you would be able to create multiple threads. Each of them picks up an instance in the queue and invokes methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM