1

Windows 10 on start automatically log-on multiple (local) users & programs. So I might have some 'ghost' users logged in once only 1 user is 'active' at this time

I need to recognize in my app if user is really active (works in session), not being just logged by Windows in background.

Is there any way to do that in .NET ? (from non-admin account) Googled a lot but count find anything reliable

PS. I found cmd line command (qwinsta) what seems doing what I need- but I dont know how to run it from C# code and read output (Im receiving qwinsta not found)

Plz advise...

* EDIT *

Clarification: I dont need to find active user name (this is pretty easy) Im looking to get info about all sessions on local machine and check which is currently active (see below qwinsta.exe output from command line).

Imagine all local users have my app in startup - app needs to do something, but only when user has ulocked session is doing something at this moment in front of computer (not being automatically logged in by this Windows-10 mechanism I personally hate...)

qwinsta.exe will do job for me but if I start this process from .NET it always says that qwinsta.exe cant be found. Even if I give full path: c:\Windows\system32\qwinsta.exe

 SESSIONNAME       USERNAME                 ID  STATE   TYPE        DEVICE
 services                                    0  Disc
>console           carl                    1  Active
 rdp-tcp                                 65536  Listen
Maciej
  • 10,423
  • 17
  • 64
  • 97
  • can you share some code? – Junius Nov 28 '19 at 00:25
  • https://stackoverflow.com/questions/2017705/get-the-logged-in-windows-user-name-associated-with-a-desktop *may* be related to what you are asking... Some good clarification what you mean "active" would be nice... – Alexei Levenkov Nov 28 '19 at 00:30
  • 1
    https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.systemevents.sessionswitch?view=netframework-4.8 – Hans Passant Nov 28 '19 at 00:33
  • Side note : If you having problems with existing answers on https://www.bing.com/search?q=c%23+process+start+read+output you should post debugging question which requires [MCVE]… – Alexei Levenkov Nov 28 '19 at 00:38
  • 1
    If you have a 32-bit app that's running in 64-bit Windows under WOW64, then the path is "%SystemRoot%\SysNative\qwinsta.exe". You should know that accessing the "System32" directory is redirected to "SysWOW64" when running under WOW64. The first thing you should check in this case is whether the file you want is actually distributed as a 32-bit program in "SysWOW64" by inspecting it from a 64-bit process such as Explorer or CMD. You'll find it's only distributed as a native 64-bit binary, in the real "System32" directory. This is accessible as "SysNative" under WOW64. – Eryk Sun Nov 28 '19 at 09:31
  • Thanks will check that. What I achieved so far was copying this file from system 32 folder to temp folder and run it out of there – Maciej Nov 28 '19 at 17:34

7 Answers7

1

Use this. I did this once a few years back, and it worked out well.

string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;

Here is the original post

Hounddog75
  • 71
  • 6
  • Can you please clarify how current user name (always exist) helps to figure out if user is "active" (whatever OP means it to be)? – Alexei Levenkov Nov 28 '19 at 00:23
  • I am thinking he wants to know if the user is logged in and is ative - being logged in is being active I feel. Here is the straight dope from MS: https://learn.microsoft.com/en-us/dotnet/api/system.environment.username?view=netframework-4.8 – Hounddog75 Nov 28 '19 at 00:29
  • Sorry I dont need to get current user name... As I wrote earlier I'm looking to get all users names / sessions and find which is active – Maciej Nov 28 '19 at 07:27
1

Here is my code sample which finally works (Thanks to @Eryk Sun) - maybe someone will find it usefull. PS. A it was rightly pointed - I might should mention that my app was x86 but W10 is x64 ...

public static bool IsUserActive(string userName) {
    Process p = new Process();
    p.StartInfo.UseShellExecute         = false;
    p.StartInfo.RedirectStandardOutput  = true;
    p.StartInfo.FileName                =  "c:\\Windows\\SysNative\\qwinsta.exe";
    p.StartInfo.Arguments               = userName;
    p.Start();
    string output = p.StandardOutput.ReadToEnd();
    p.WaitForExit();

    return output.Contains("  Active");
}
Maciej
  • 10,423
  • 17
  • 64
  • 97
1

For system-level Applications

    [DllImport("Wtsapi32.dll")]
    public static extern bool WTSQuerySessionInformationW(
          IntPtr hServer,
          int SessionId,
          int WTSInfoClass,
          out IntPtr ppBuffer,
          out IntPtr pBytesReturned);

public static void AddArray<xArray>(ref xArray[] array, dynamic deger)
    {
        try
        {
            int diziboyu;
            if (array == null)
            {
                diziboyu = 0;
            }
            else
                diziboyu = array.Length;
            diziboyu++;
            System.Array.Resize(ref array, diziboyu);
            array[diziboyu - 1] = deger;
        }
        catch (Exception)
        {

        }
    }

public static string[] Online_userNames = null;

Process[] pname = Process.GetProcessesByName("explorer");
foreach (Process proc in pname)
            {
                IntPtr AnswerBytes;
                IntPtr AnswerCount;
                WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE,
                                                    proc.SessionId,
                                                    WTS_UserName,
                                                    out AnswerBytes,
                                                    out AnswerCount);

                AddArray(ref Online_userNames, Marshal.PtrToStringUni(AnswerBytes));
            }

            pname = null;
hamza pro
  • 41
  • 1
1

There's a windows API call to get the currently active session.

var activeSession = WTSGetActiveConsoleSessionId();

If you're in c#, you'll need to load the DLL with this.

[DllImport("kernel32.dll")]
private static extern uint WTSGetActiveConsoleSessionId();

You can find the session you're running in with this line.

var mySession = System.Diagnostics.Process.GetCurrentProcess().SessionId;

Then it's just a matter of comparing the two to determine if you're running on the console or in a background session.

It's also possible that you're running in a remote desktop session though. The code above will only find the active local session IE. the person sitting at the actual computer, not remoted

0

In c# I use this

private string MyUser = System.Environment.UserName;
ToCarbajal
  • 420
  • 3
  • 6
  • Sorry I dont need to get current user name... As I wrote earlier I'm looking to get all users names / sessions and find which is active – Maciej Nov 28 '19 at 07:28
0

There's a better solution which uses winapi which is what qwinsta probably does.
I can't take credit for the implementation - this is the github link:
https://github.com/murrayju/CreateProcessAsUser

What this does is, using winapi, enumerates all the sessions in the machine. for each session it calls another winapi that gets details about this session and this is how you get the indication if this session is active.

Take a look at that project I linked, it's a much better solution that parsing output of a different app

Alonzzo2
  • 959
  • 10
  • 24
  • 1
    And an even shorter way to get the active session and from it to get the user name is calling "WTSGetActiveConsoleSessionId" which is also at the project I linked. – Alonzzo2 Apr 14 '20 at 14:49
0

Here is my code sample which works. I am making the code to use x86 process instead of x64, as W10 is x64.

IntPtr ptr = new IntPtr();
Wow64DisableWow64FsRedirection(ref ptr);
var p = Process.Start(
         new ProcessStartInfo("qwinsta", $"/server:")
         {
             CreateNoWindow = true,
             UseShellExecute = false,
             RedirectStandardError = true,
             RedirectStandardOutput = true,
             WorkingDirectory = Environment.CurrentDirectory
         }
     );

p.WaitForExit();
string output = p.StandardOutput.ReadToEnd().TrimEnd();
string errorInfoIfAny = p.StandardError.ReadToEnd().TrimEnd();

Wow64RevertWow64FsRedirection(ptr);

Add this two import methods.

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);

Sample output

Bibin Gangadharan
  • 1,393
  • 12
  • 13