Come posso determinare il proprietario di un processo in C #?

Sto cercando un processo con il nome di “MyApp.exe” e voglio assicurarmi di ottenere il processo che è di proprietà di un particolare utente.

Io uso il seguente codice per ottenere un elenco dei processi:

Process[] processes = Process.GetProcessesByName("MyApp"); 

Questo mi dà una lista di processi, ma non sembra che ci sia un modo nella class Process per determinare chi è il proprietario di quel processo? Qualche idea su come posso farlo?

È ansible utilizzare WMI per ottenere l’utente in possesso di un determinato processo. Per utilizzare WMI è necessario aggiungere un riferimento a System.Management.dll al progetto.

Per ID processo:

 public string GetProcessOwner(int processId) { string query = "Select * From Win32_Process Where ProcessID = " + processId; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); ManagementObjectCollection processList = searcher.Get(); foreach (ManagementObject obj in processList) { string[] argList = new string[] { string.Empty, string.Empty }; int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList)); if (returnVal == 0) { // return DOMAIN\user return argList[1] + "\\" + argList[0]; } } return "NO OWNER"; } 

Per nome del processo (trova solo il primo processo, regolare di conseguenza):

 public string GetProcessOwner(string processName) { string query = "Select * from Win32_Process Where Name = \"" + processName + "\""; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); ManagementObjectCollection processList = searcher.Get(); foreach (ManagementObject obj in processList) { string[] argList = new string[] { string.Empty, string.Empty }; int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList)); if (returnVal == 0) { // return DOMAIN\user string owner = argList[1] + "\\" + argList[0]; return owner; } } return "NO OWNER"; } 

Dal momento che WMI non è sempre un modo veloce per recuperare informazioni, ecco il modo nativo di P / Invoke di farlo:

Il valore di ritorno è null quando non è riuscito. Per ottenere i nomi dei processi in esecuzione con l’utente SYSTEM, è necessario eseguire questo codice come amministratore.

 private static string GetProcessUser(Process process) { IntPtr processHandle = IntPtr.Zero; try { OpenProcessToken(process.Handle, 8, out processHandle); WindowsIdentity wi = new WindowsIdentity(processHandle); string user = wi.Name; return user.Contains(@"\") ? user.Substring(user.IndexOf(@"\") + 1) : user; } catch { return null; } finally { if (processHandle != IntPtr.Zero) { CloseHandle(processHandle); } } } [DllImport("advapi32.dll", SetLastError = true)] private static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseHandle(IntPtr hObject); 

Ecco la versione VB per i diffusori non C #:

 Function GetProcessOwner(ProcessName As String) As String Dim query = "Select * from Win32_Process Where Name = """ + ProcessName + """" Dim searcher = New ManagementObjectSearcher(query) Dim processList = searcher.Get() For Each obj As ManagementObject In processList Dim argList As String() = {String.Empty, String.Empty} Dim returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList)) If returnVal = 0 Then ' return DOMAIN\user Dim owner = argList(1) + "\\" + argList(0) Return owner End If Next Return "NO OWNER" End Function Function GetProcessOwner(processId As Integer) As String Dim query = "Select * From Win32_Process Where ProcessID = " & processId Dim searcher = New ManagementObjectSearcher(query) Dim processList = searcher.Get() For Each obj As ManagementObject In processList Dim argList As String() = {String.Empty, String.Empty} Dim returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList)) If returnVal = 0 Then ' return DOMAIN\user Return argList(1) + "\\" + argList(0) End If Next Return "NO OWNER" End Function 

Sfortunatamente non esiste un modo nativo .Net per ottenere il proprietario del processo.

Dai un’occhiata a questi per una potenziale soluzione:

 System.Security.Principal.WindowsIdentity.GetCurrent().Name 

Aggiungi un riferimento al tuo progetto:

 System.Management 

Quindi aggiungi il seguente metodo al tuo progetto:

  public string GetProcessOwner(int processId) { string MethodResult = null; try { StringBuilder sb = new StringBuilder(); sb.Append(" SELECT "); sb.Append(" * "); sb.Append(" FROM "); sb.Append(" WIN32_PROCESS"); sb.Append(" WHERE "); sb.Append(" ProcessId = " + processId); string Query = sb.ToString(); ManagementObjectCollection Processes = new ManagementObjectSearcher(Query).Get(); foreach (ManagementObject Process in Processes) { string[] Args = new string[] { "", "" }; int ReturnCode = Convert.ToInt32(Process.InvokeMethod("GetOwner", Args)); switch(ReturnCode) { case 0: MethodResult = Args[1] + "\\" + Args[0]; break; default: MethodResult = "None"; break; } } } catch //(Exception ex) { //ex.HandleException(); } return MethodResult; } 

Quindi aggiungere questo metodo:

  public DataTable GetProcessTable() { DataTable MethodResult = null; try { List Processes = Process.GetProcesses().ToList(); DataTable dt = new DataTable(); dt.Columns.Add("Name", typeof(string)); dt.Columns["Name"].ReadOnly = true; dt.Columns.Add("Id", typeof(string)); dt.Columns["Id"].ReadOnly = true; dt.Columns.Add("Owner", typeof(string)); dt.Columns["Owner"].ReadOnly = true; foreach (Process p in Processes) { DataRow r = dt.NewRow(); bool Match = false; r["Id"] = p.Id.ToString(); r["Name"] = p.ProcessName; r["Owner"] = GetProcessOwner(p.Id); dt.Rows.Add(r); } MethodResult = dt; } catch //(Exception ex) { //ex.HandleException(); } return MethodResult; } 

La chiamata a GetProcessTable () fornisce un DataTable di tutti i processi in esecuzione insieme al relativo ID e Nome, il che è utile in quanto può essere utilizzato come parametro Datasource di DataGridView.

Fammi sapere se hai bisogno di altri campi che aggiungono alla tabella.

Questo è il modo più semplice che ho trovato per farlo:

 Process[] processes = Process.GetProcessesByName("MyApp"); foreach (Process process in processes) { string username = process.StartInfo.Environment["USERNAME"]; // do some stuff }