WMI 的 C# 友好替代方案,用于按所有者迭代远程进程
本文关键字:迭代 所有者 程进程 进程 用于 方案 WMI | 更新日期: 2023-09-27 18:30:43
我们有一些代码可以工作,但太慢了。 我们使用 System.Management.ManagementObjectSearcher 来运行 ObjectQuery,用于"从Win32_Process中选择 *"。 然后,我们迭代返回的列表,调用"GetOwner"(通过 InvokeMethod)以查看进程是否由我们正在搜索的用户完成,然后调用"终止"(也通过 InvokeMethod)。
通过一些额外的异常处理来考虑在迭代时终止的进程,这是有效的,但是在我们需要运行它的数千个进程的机器上,迭代所有进程需要整整一个小时。
是否有不涉及在目标服务器上占用足迹的替代方法? 远程部分是我们正在做的事情的关键。 如果我们必须本地化,我们可以选择 win32 api,但我想如果在本地运行 WMI 会足够快。
不幸的是,如果要提高性能,WMI 检索进程所有者的速度非常慢,则必须使用 WInAPi 函数OpenProcessToken
和CloseHandle
。
检查此示例
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();
}
}
}
我不确定哪个工作缓慢,迭代或调用方法。我猜可能是后者。
- 您可以尝试 ManagementClass.GetInstances() 而不是运行 wmi 查询吗?
- 尝试循环访问返回的 WMI 实例并将其缓存到队列中。然后,您将能够创建多个线程。它们中的每一个都选取队列中的一个实例并调用方法。