I'm creating remote task manager app and I'm trying to figure out how to get process owner of process running on remote machine without WMI. With WMI it's really easy, but it's too slow. I'm tried to use WTSQuerySessionInformation, but it only worked for local machine.
For closer specification, my remote task manager app will run on workstations and will connect against another workstations and also against servers in the same network. User, which will run the app, wil be administrator on both machines.
Please, do you know some another way how to get owner of remote process, or some improvement/fix for my code below?
My WMI version (it's too slow...)
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;
}
My WTSQuerySessionInformation version (works only for local machine)
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 in separate class:
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
}