【问题标题】:How to get current windows username from windows service in multiuser environment using .NET如何使用 .NET 从多用户环境中的 windows 服务获取当前 windows 用户名
【发布时间】:2014-03-07 17:25:55
【问题描述】:

我有一个 Windows 服务,它一直为所有登录的用户运行一个 WPF 应用程序,它工作正常,现在在 WPF 应用程序中我无法获得当前用户名作为 Environment.UserName;返回“SYSTEM”,这是可以理解的。所以我的想法是找到可以通过 Process.GetCurrentProcess().SessionId 检索的当前进程的会话 ID,然后获取登录到机器的所有用户的列表并循环通过它找到与进程会话匹配的会话 ID id 和后来的用户名。

但我不知道如何获取所有登录用户的列表,或者如果有人可以帮助我提供替代方案,我将不胜感激。

【问题讨论】:

  • 您可以使用 Window 查找所有活动进程并获取该进程的用户。以 SYSTEM 身份运行的服务应该有权执行此操作。
  • 当它开始为他们做任何事情时,为什么不简单地将用户名发送到您的服务。 Process.GetCurrentProcess 将是您在服务中的服务...
  • @TonyHopkinson 首先我无法从 Windows 服务获取用户名,其次我采用所有“winlogon”进程,即登录用户数并在每个用户会话中说明 WPF 应用程序。
  • 我没看懂剧情!每个用户将运行自己的 WPF 应用程序,还是只有一个 WPF 应用程序和许多用户同时登录?
  • 您正在寻找“冒充呼叫者”。 How to: Impersonate the Original Caller in WCF 很有可能是您要查找的文章。

标签: c# wpf windows windows-services


【解决方案1】:

我在构建 Windows 服务时遇到了类似的问题。就像你一样,我有会话 ID,需要获取相应的用户名。上面 Syed 的回答在我的机器(Windows 10)上不起作用,因为微软似乎已经删除了 quser 可执行文件。经过几次不成功的解决方案,我遇到了this particular answer,它激发了我的解决方案:

这是我的代码(它们都在一个类中;在我的例子中,类继承了ServiceBase

    [DllImport("Wtsapi32.dll")]
    private static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WtsInfoClass wtsInfoClass, out IntPtr ppBuffer, out int pBytesReturned);
    [DllImport("Wtsapi32.dll")]
    private static extern void WTSFreeMemory(IntPtr pointer);

    private enum WtsInfoClass
    {
        WTSUserName = 5, 
        WTSDomainName = 7,
    }

    private static string GetUsername(int sessionId, bool prependDomain = true)
    {
        IntPtr buffer;
        int strLen;
        string username = "SYSTEM";
        if (WTSQuerySessionInformation(IntPtr.Zero, sessionId, WtsInfoClass.WTSUserName, out buffer, out strLen) && strLen > 1)
        {
            username = Marshal.PtrToStringAnsi(buffer);
            WTSFreeMemory(buffer);
            if (prependDomain)
            {
                if (WTSQuerySessionInformation(IntPtr.Zero, sessionId, WtsInfoClass.WTSDomainName, out buffer, out strLen) && strLen > 1)
                {
                    username = Marshal.PtrToStringAnsi(buffer) + "\\" + username;
                    WTSFreeMemory(buffer);
                }
            }
        }
        return username;
    }

【讨论】:

    【解决方案2】:

    在 MSDN 论坛上找到了这个解决方案:

    using System.Security.Principal;
    .
    .
    .
    WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
    String username = wp.Identity.Name;
    

    现在可以通过创建一个新的控制台应用程序、粘贴上面的代码并将用户名字符串写入控制台来轻松测试。似乎工作正常,但对于服务来说,这显然是一个更复杂的情况。由于所有服务都在 SYSTEM 用户下运行的容器中运行,因此它们返回的就是这些。有关更多信息,请参阅以下链接,尤其是。所有 Harry Zhu 的答案。

    http://social.msdn.microsoft.com/Forums/vstudio/en-US/3be119b0-88b4-442e-9613-6856cbb27adb/how-can-i-get-current-username-in-windows-service?forum=csharpgeneral

    似乎无法实现您想要获得的目标,因为服务与用户会话完全分开。

    【讨论】:

    • +0: OP 已经有等效代码 (Environment.UserName),不确定您的建议如何更好。
    • 不起作用,它返回 Environment.UserName 所做的事情
    【解决方案3】:

    我通过在我的 WPF 应用程序中执行 powershell 命令“quser”来解决它,该命令返回所有登录的用户,然后我正在迭代以查找应用程序正在运行的会话 ID,并使用用户会话 ID 然后检索他的名字。下面是通过传递他的会话 id 来获取用户名的函数

     private string GetUserName(int SessionId)
            {
                try
                {
                    Runspace runspace = RunspaceFactory.CreateRunspace();
                    runspace.Open();
    
                    Pipeline pipeline = runspace.CreatePipeline();
                    pipeline.Commands.AddScript("Quser");
                    pipeline.Commands.Add("Out-String");
    
                    Collection<PSObject> results = pipeline.Invoke();
    
                    runspace.Close();
    
                    StringBuilder stringBuilder = new StringBuilder();
                    foreach (PSObject obj in results)
                    {
                        stringBuilder.AppendLine(obj.ToString());
                    }
    
                    foreach (string User in stringBuilder.ToString().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Skip(1))
                    {
                        string[] UserAttributes = User.Split(new string[]{" "},StringSplitOptions.RemoveEmptyEntries);
                        if (int.Parse(UserAttributes[2].Trim()) == SessionId)
                        {
                            return UserAttributes[0].Replace(">", string.Empty).Trim();
                        }
                    }
    
                    return stringBuilder.ToString();
                }
                catch (Exception ex)
                {
                }
    
                return string.Empty;
            }
    

    函数可以被调用

    string CurrentUser = GetUserName(Process.GetCurrentProcess().SessionId);
    

    【讨论】:

      【解决方案4】:

      你可以试试这个代码spinet。 每当用户登录 Windows 时,用户名属性将包含用户的用户名。在windows系统没有用户的情况下,不会有Win32_ComputerSystem类的实例。

      ManagementScope ms = new ManagementScope("\\\\.\\root\\cimv2");
      ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_ComputerSystem");
      ManagementObjectSearcher searcher = new ManagementObjectSearcher(ms, query);
      foreach(ManagementObject mo in searcher.Get())
      {
          Console.WriteLine(mo["UserName"].ToString());
      }
      

      【讨论】:

        【解决方案5】:

        我做了一些搜索,找到了适合你的代码:
        它将获取正在运行该进程的用户名...
        参考:How do I determine the owner of a process in C#?

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

        【讨论】:

        • +0:不要忘记,这需要管理员权限,服务帐户不应该拥有......而且如果不要求调用者传递一个,就无法获取调用者的进程 ID - 所以你有好的答案一些不同的问题。
        • 不起作用 processlist 通过硬编码进程名称或传递 Process.GetCurrentProcess().ProcessName 为零
        【解决方案6】:

        你可以试试这个代码:

        string username = "SYSTEM";
        var explorer = Process.GetProcessesByName("explorer").FirstOrDefault();
        if (explorer != null)
        {
            username = GetUsername(explorer.SessionId);
        }
        

        这里GetUsername方法的实现:https://stackoverflow.com/a/35810391/10412686

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多