Как определить владельца процесса в C #? - PullRequest
39 голосов
/ 22 апреля 2009

Я ищу процесс с именем «MyApp.exe» и хочу убедиться, что получил процесс, принадлежащий конкретному пользователю.

Я использую следующий код для получения списка процессов:

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

Это дает мне список процессов, но, похоже, в классе Process нет способа определить, кому принадлежит этот процесс? Есть мысли о том, как я могу это сделать?

Ответы [ 8 ]

60 голосов
/ 22 апреля 2009

Вы можете использовать WMI, чтобы получить пользователя, владеющего определенным процессом. Чтобы использовать WMI, вам нужно добавить ссылку на System.Management.dll в ваш проект.

По идентификатору процесса:

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";
}

По имени процесса (находит только первый процесс, настроить соответственно):

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";
}
23 голосов
/ 30 июля 2016

Поскольку WMI не всегда является быстрым способом получения информации, вот родной способ P / Invoke сделать это:

Возвращаемое значение null в случае неудачи. Чтобы получить имена процессов, запущенных под пользователем SYSTEM, вам нужно выполнить этот код от имени администратора.

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);
7 голосов
/ 06 сентября 2012

Вот версия VB для не говорящих на 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
4 голосов
/ 22 апреля 2009

К сожалению, нет собственного .Net способа получить владельца процесса.

Взгляните на это для возможного решения:

0 голосов
/ 15 апреля 2019

@ bytecode77:

Я могу сказать вам прямо сейчас, просто взглянув на ваш код, что вы будете генерировать потенциальные FirstChanceExceptions ... в частности, из-за "ACCESS DENIED" (Win32Exception) и "NOT RUNNING" (ArgumentException) для этих. блок из оценщика выражений 'process.Handle'.

Дескриптор процесса является частным для приложения - другими словами, дескрипторы процесса не могут быть общими.

См. Также LinkDemand = 6 и SecurityCriticalAttribute .

Хотя для этого атрибута вам все еще может потребоваться «Инструменты -> Отладка -> Включено только мой код», исключения FirstChanceException по-прежнему будут вызываться.

Кроме этого, я согласен с тем, что ваш ответ в вызове Win32 pinvoke быстрее, чем WMI, особенно при переборе ВСЕХ процессов.

[DebuggerNonUserCode]
private static IEnumerable<Process> GetProcesses() =>
  Process.GetProcesses().Where(p => {
    var hasException = false;
    try {
      var x = p.Handle;
    } catch {
      hasException = true;
    }
    return !hasException;
  }).ToArray();
0 голосов
/ 11 января 2017

Это самый простой способ сделать это:

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

     // do some stuff
} 
0 голосов
/ 16 августа 2016
System.Security.Principal.WindowsIdentity.GetCurrent().Name
0 голосов
/ 29 февраля 2016

Добавьте ссылку на свой проект:

System.Management

Затем добавьте следующий метод в ваш проект:

    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;
    }

Затем добавьте этот метод:

    public DataTable GetProcessTable()
    {
        DataTable MethodResult = null;
        try
        {
            List<Process> Processes = Process.GetProcesses().ToList<Process>();

            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;
    }

Вызов GetProcessTable () дает вам DataTable всех запущенных процессов вместе с их Id и Name, что удобно, поскольку его можно использовать в качестве параметра источника данных DataGridView.

Дайте мне знать, если вам нужно больше полей для добавления в таблицу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...