如何使用.NET在多用户环境中从Windows服务获取当前的Windows用户名

时间:2014-02-10 11:41:58

标签: c# wpf windows windows-services

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

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

6 个答案:

答案 0 :(得分:1)

在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

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

答案 1 :(得分:1)

我通过在我的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);

答案 2 :(得分:1)

我在构建Windows服务时遇到了类似的问题。就像你一样,我有会话ID,需要获得相应的用户名。由于微软似乎删除了quser可执行文件,因此Syed的上述答案在我的机器上无效(Windows 10)。经过几次不成功的解决方案,我遇到了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;
    }

答案 3 :(得分:1)

你可以试试这个Code spinet。 每当用户登录到Windows时,Username属性将包含用户的用户名。如果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());
}

答案 4 :(得分:0)

我做了一点搜索,找到了适合你的代码:
它将获得正在运行该进程的用户名...
参考: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";
}

答案 5 :(得分:0)

您可以尝试以下代码:

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

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