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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21676225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 10:47:03  来源:igfitidea点击:

How to get current windows username from windows service in multiuser environment using .NET

c#wpfwindowswindows-services

提问by Syed Waqas

I have a windows service which run a WPF application all the time for all the logged in users which works fine, now in the WPF application i can not get a current username as Environment.UserName; returns 'SYSTEM' which is understandable. so what i thought was to find session id of current process which could be retrieved by Process.GetCurrentProcess().SessionId and then get the list of all users logged in to the machine and looping through it to find the session id match with process session id and later his username.

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

but i don't how to get the list of all logged in users or i would appreciate if someone can help me with alternative.

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

回答by Syed Waqas

I solve it by executing powershell command "quser" in my WPF application which returns all the logged in users then I am iterating to find session id in which the application is running with user session id and then retrieving his name. below is the function which fetch the username by passing his session id

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

the function can be called by

该函数可以被调用

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

回答by Soma Mbadiwe

I ran into a similar problem while building a Windows Service. Just like you, I had the Session ID and needed to get the corresponding username. Syed's answer above did not work on my machine (Windows 10) as Microsoft seems to have removed the quserexecutable. After several unsuccessful solution hereon SO, I ran into this particular answerand it inspired my solution:

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

Here's my code (all of them residing inside a class; in my case, the class inheriting ServiceBase)

这是我的代码(它们都驻留在一个类中;在我的情况下,类继承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;
    }

回答by Tola Ch.

You can try this Code spinet. Whenever a user logged onto windows, the Username attribute will contain the username of the user. In the case when there are no users in the windows system, there will be no instances of the Win32_ComputerSystem class.

你可以试试这个 Code 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());
}

回答by pKami

Found this solution on MSDN forums:

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

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

Now this is easily tested by creating a new Console Application, pasting the above code, and writing the username string to Console. Seems to work fine, but for services it's apparently a more complex situation. Since all services are run in a container that runs under the SYSTEM user, that's what they return. For more information see the below link, esp. all Harry Zhu's answers.

现在可以通过创建一个新的控制台应用程序、粘贴上述代码并将用户名字符串写入控制台来轻松测试。似乎工作正常,但对于服务来说,这显然是一个更复杂的情况。由于所有服务都在以 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

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

It would seem it's not possible to achieve what you are trying to get, as services are totally seperate from users' session.

似乎不可能实现您想要的目标,因为服务与用户会话完全分开。

回答by Shamim

i made a little search and find this code that should work for you:
it will get the username whom is running the process...
reference: How do I determine the owner of a process in C#?

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

回答by Igor

You can try this Code:

你可以试试这个代码:

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

Implementation of method GetUsername here: https://stackoverflow.com/a/35810391/10412686

在此处实现方法 GetUsername:https://stackoverflow.com/a/35810391/10412686