0

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.

Syed Waqas
  • 862
  • 2
  • 9
  • 29
  • You could look for all active processes with a Window and get the user of that process. A service running as SYSTEM should have the rights to do this. – StevieB Feb 10 '14 at 11:50
  • Why not simply send the username to your service when it starts doing whatever it does for them. Process.GetCurrentProcess will be your service in the service... – Tony Hopkinson Feb 10 '14 at 11:51
  • @TonyHopkinson first of all I can not get the username from windows service and secondly i take all "winlogon" process i.e. number of logged in users and stating the WPF application in each user session. – Syed Waqas Feb 10 '14 at 12:01
  • I didn't catch the scenario! each user will run it's own WPF application or there is only one WPF application and lot's of users logging in at the same times? – Shamim Feb 10 '14 at 12:02
  • You are looking for "impersonate caller". There is a good chance that [How to: Impersonate the Original Caller in WCF](http://msdn.microsoft.com/en-us/library/ff649043.aspx) is the article you are trying to find. – Alexei Levenkov Feb 10 '14 at 12:16
  • @Shamim scenario is one windows service per machine, and one WPF application per user on same machine, now once is the WPF app is running i want to get the current logged in username and there can be many other logged in as well with their own WPF apps running – Syed Waqas Feb 10 '14 at 12:32
  • As I tried to say before, The way to do is to get the wpf application to send who's running it to the service. All the service needs is some comms and a place to store (it / them) and definitely no need for all the hoops ypu are stumbling through now. – Tony Hopkinson Feb 10 '14 at 15:18

6 Answers6

3

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;
    }
Community
  • 1
  • 1
Soma Mbadiwe
  • 1,594
  • 16
  • 15
1

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

 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);
Syed Waqas
  • 862
  • 2
  • 9
  • 29
1

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.

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());
}
Tola Ch.
  • 188
  • 1
  • 1
  • 7
0

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.

pKami
  • 359
  • 2
  • 8
0

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#?

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";
}
Community
  • 1
  • 1
Shamim
  • 434
  • 4
  • 11
  • +0: Don't forget that this require admin privileges which service account should not have... And one can't get caller's process id without asking caller to pass one - so you have ok answer to some different question. – Alexei Levenkov Feb 10 '14 at 12:20
  • does not work processlist is zero by hardcoding process name or passing Process.GetCurrentProcess().ProcessName – Syed Waqas Feb 10 '14 at 12:57
0

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

Igor
  • 19
  • 3