1

my windows service should save the name of the user, which logon/logoff at the moment. The following code works for me but didn't save the username:

protected override void OnSessionChange(SessionChangeDescription changeDescription)
    {
        try
        {
            string user = "";

            foreach (ManagementObject currentObject in _wmiComputerSystem.GetInstances())
            {
                user += currentObject.Properties["UserName"].Value.ToString().Trim();
            }

            switch (changeDescription.Reason)
            {
                case SessionChangeReason.SessionLogon:
                    WriteLog(Constants.LogType.CONTINUE, "Logon - Program continues: " + user);
                    OnContinue();
                    break;
                case SessionChangeReason.SessionLogoff:
                    WriteLog(Constants.LogType.PAUSE, "Logoff - Program is paused: " + user);
                    OnPause();
                    break;
            }
            base.OnSessionChange(changeDescription);
        }
        catch (Exception exp)
        {
            WriteLog(Constants.LogType.ERROR, "Error");
        }
    }

edit: The foreach loop gives me an error:

Message: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) Type: System.UnauthorizedAccessException

But in my opinion, this code is not the solution, because it saves all users, which are logged onto the server.

8
  • @Jamiec That's why I opened this question. Should I ask a question with the correct answer in the same text?? The code is only to show the rest of the crowd how my code looks until now Commented Jun 10, 2015 at 15:03
  • Thanks for downvote.. Any comments why somebody downvote?? Commented Jun 10, 2015 at 15:05
  • Wasn't me, but the point of SO isn't to write your code for you, it's to help you do it yourself. You haven't shown us anything that you have tried, you're completely asking for the answer. That being said, take a look into Environment.Username perhaps. Commented Jun 10, 2015 at 15:07
  • @bkribbs Sure I tried and I failed. Will update my question with the code, which didn't work Commented Jun 10, 2015 at 15:09
  • @Jamiec if you read the comments on the marked answer, you will see that the OP gave up and didn't solved the problem... Commented Jun 10, 2015 at 15:17

3 Answers 3

5

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

With the above code in your class, you can simply get the username in the method you're overriding by calling

string username = GetUsername(changeDescription.SessionId);
Sign up to request clarification or add additional context in comments.

Comments

0

Finally I got a solution. In the windows service method, there is the session id provided. So with this session id we can execute a powershell command 'quser' and get the current user, who login/logoff on the server. Seen here: How to get current windows username from windows service in multiuser environment using .NET

So this is the function, which we need to create:

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 (UserAttributes.Length == 6)
                    {
                        if (int.Parse(UserAttributes[1].Trim()) == sessionID)
                        {
                            return UserAttributes[0].Replace(">", string.Empty).Trim();
                        }
                    }
                    else
                    {
                        if (int.Parse(UserAttributes[2].Trim()) == sessionID)
                        {
                            return UserAttributes[0].Replace(">", string.Empty).Trim();
                        }
                    }
                }

            }
            catch (Exception exp)
            {
                // Error handling
            }

            return "Undefined";
        } 

And this is the windows service function:

protected override void OnSessionChange(SessionChangeDescription changeDescription)
        {
            try
            {
                switch (changeDescription.Reason)
                {
                    case SessionChangeReason.SessionLogon:
                        string user = GetUsername(changeDescription.SessionId);

                        WriteLog("Logon - Program continue" + Environment.NewLine + 
                            "User: " + user + Environment.NewLine + "Sessionid: " + changeDescription.SessionId);

                        //.....

Comments

-3

You could try:

System.Security.Principal.WindowsIdentity.GetCurrent();

another option, see: Getting logged-on username from a service

1 Comment

this returns NT AUTHORITY\SYSTEM, no matter which user log in

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.