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

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.

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.


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 quser executable. After several unsuccessful solution hereon SO, I ran into this particular answer and it inspired my solution:

Here's my code (all of them residing inside a class; in my case, the class inheriting 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;
    }

Found this solution on MSDN forums:

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.

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

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