c# - 如何获得在没有 WMI 的远程计算机上运行的进程的所有者
问题描述
我正在创建远程任务管理器应用程序,并且试图弄清楚如何在没有 WMI 的情况下获得在远程机器上运行的进程的进程所有者。使用 WMI 真的很容易,但是太慢了。我尝试使用 WTSQuerySessionInformation,但它只适用于本地机器。
为了更详细地说明,我的远程任务管理器应用程序将在工作站上运行,并将连接到另一个工作站,也连接到同一网络中的服务器。将运行该应用程序的用户将是两台机器上的管理员。
拜托,您知道如何获得远程进程所有者的另一种方法,或者对下面的代码进行一些改进/修复吗?
我的 WMI 版本(太慢了……)
public static Dictionary<Process, string> GetOwners(this IEnumerable<Process> processes)
{
Dictionary<Process, string> result = new Dictionary<Process, string>();
if (processes == null || processes.Count() == 0) { return result; }
string select = "SELECT Handle, ProcessID FROM Win32_Process";
select += processes.Count() <= 10 ? string.Format(" WHERE ProcessID = {0}", string.Join(" OR ProcessID = ", processes.Select(p => p.Id))) : string.Empty;
ManagementScope scope = new ManagementScope(string.Format("\\\\{0}\\root\\cimv2", processes.ElementAt(0).MachineName));
SelectQuery selectQuery = new SelectQuery(select);
scope.Connect();
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, selectQuery))
{
using (ManagementObjectCollection objectCollection = searcher.Get())
{
foreach (ManagementObject managementObject in objectCollection)
{
try
{
int id = Convert.ToInt32(managementObject["ProcessID"]);
string owner = managementObject.InvokeMethod("GetOwner", null, null)["User"]?.ToString();
result.Add(processes.Single(p => p.Id == id), owner);
}
catch
{
}
}
}
}
return result;
}
我的 WTSQuerySessionInformation 版本(仅适用于本地机器)
public static Dictionary<Process, string> GetPInvokeProperties(this IEnumerable<Process> processes)
{
Dictionary<Process, string> result = new Dictionary<Process, string>();
if (processes == null || processes.Count() == 0) { return result; }
string machineName = processes.ElementAt(0).MachineName;
IntPtr serverHandle = (machineName == Environment.MachineName || machineName == ".") ? IntPtr.Zero : NativeMethods.OpenServer(machineName);
foreach (Process process in processes)
{
try
{
IntPtr buffer;
int strLen;
string username = "SYSTEM";
if (NativeMethods.QuerySessionInformation(serverHandle, process.SessionId, WTS_INFO_CLASS.WTSUserName, out buffer, out strLen) && strLen > 1)
{
username = Marshal.PtrToStringUni(buffer);
NativeMethods.FreeMemory(buffer);
}
result.Add(process, username);
}
catch
{}
}
NativeMethods.CloseServer(serverHandle);
return result;
}
单独类中的 NativeMethods:
public static class NativeMethods
{
#region Native Methods
[DllImport("wtsapi32.dll")]
private static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] string pServerName);
[DllImport("wtsapi32.dll")]
private static extern void WTSCloseServer(IntPtr hServer);
[DllImport("Wtsapi32.dll")]
private static extern void WTSFreeMemory(IntPtr pointer);
[DllImport("Wtsapi32.dll")]
private static extern bool WTSQuerySessionInformationW(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out int pBytesReturned);
#endregion
#region Public Methods
public static IntPtr OpenServer(string Name)
{
IntPtr server = WTSOpenServer(Name);
return server;
}
public static void CloseServer(IntPtr ServerHandle)
{
WTSCloseServer(ServerHandle);
}
public static void FreeMemory(IntPtr pointer)
{
WTSFreeMemory(pointer);
}
public static bool QuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out int pBytesReturned)
{
return WTSQuerySessionInformationW(hServer, sessionId, wtsInfoClass, out ppBuffer, out pBytesReturned);
}
#endregion
}
解决方案
我建议迁移到较System.Management
旧、较慢且无法扩展的较新名称空间。您追求的较新框架是Microsoft.Management.Infrastructure
. 这是解释这一点的Microsoft 文档以及两者的示例。
所以你会使用这样的东西:
Using Microsoft.Management.Infrastructure;
CimSession Session = CimSession.Create("computer_name");
CimInstance Instance = Session.QueryInstances(@"root\cimv2", "WQL", "SELECT Name FROM Win32_ComputerSystem");
foreach (CimInstance i in Instance){
Console.WriteLine(i.CimInstanceProperties["Name"].Value);
}
或者
Using Microsoft.Management.Infrastructure;
CimSession Session = CimSession.Create("computer_name");
CimInstance Instance = Session.QueryInstances(@"root\cimv2", "WQL", "SELECT Name FROM Win32_ComputerSystem").First();
Console.WriteLine(Instance.CimInstanceProperties["Name"].Value);
我希望这能给你一些新的兔子洞来跑下来:-D 如果你需要其他东西,请告诉我们:)
推荐阅读
- python - Flask App 响应未收到客户端
- python - 创建文件并在必要时更新它
- javascript - 如何使用在搜索字段中工作的 target_blank?
- wordpress - 如何刷新 WordPress 永久链接?
- reactjs - TypeError:在动作执行时分派
- c# - 您将如何使用 LINQ 编写此映射过滤器链?
- angular - 带有Angular 9基本安装的CKEditor5导致“'ckeditor'不是已知元素:'”
- wordpress - Woocommerce 根据付款方式更改总价
- javascript - 理解 Vue 和 Return 和 Async Await
- r - 结合renderUI、dataTableOutput、renderDataTable和reactive