How to Get Current logged in user from within a Windows Service

T

thephatp

Is there any possible way to get the currently logged in (active) user
from within a service?

I need the service to start at runtime. I need to capture log on / log
off / switch user events. I haven't gotten to that yet, but it IS
possible from within a windows service, correct? I figured I'd ask
because of my current problem.

Line of code in question:

System.Security.Principle.WindowsIdentity.GetCurre nt().Name

From within an application running locally, the output is
<myLoginName>.
From within a Windows Service running locally in the background, the
output is `NT AUTHORITY\SYSTEM`.

Is there any way to get the currently logged in and active user (in
the case that multiple users are logged in, we only care about the
active one) from code executing in a windows service??

Thanks in advance.

Chad
 
N

Norman Diamond

There can be 0 or more current logged in users. If you want all of the 0 or
1 users who are currently logged in at the console then P/Invoke to
WTSGetActiveConsoleSessionId and WTSQuerySessionInformation. If you want
all of the users then you'll need to call WTSQuerySessionInformation in a
loop.

Warning: Only call the Unicode version of WTSQuerySessionInformation. If
your application runs in ANSI then explicitly call the Unicode version
WTSQuerySessionInformationW and convert the result to ANSI by calling
WideCharToMultiByte. From C# you mostly don't have to worry about this,
just make sure that your P/Invoke declaration specifies the Unicode version.
 
J

John B

thephatp said:
Is there any possible way to get the currently logged in (active) user
from within a service?

I need the service to start at runtime. I need to capture log on / log
off / switch user events. I haven't gotten to that yet, but it IS
possible from within a windows service, correct? I figured I'd ask
because of my current problem.

Line of code in question:

System.Security.Principle.WindowsIdentity.GetCurre nt().Name

From within an application running locally, the output is
<myLoginName>.
From within a Windows Service running locally in the background, the
output is `NT AUTHORITY\SYSTEM`.

Is there any way to get the currently logged in and active user (in
the case that multiple users are logged in, we only care about the
active one) from code executing in a windows service??

Thanks in advance.

Chad
From pinvoke.net

NetWkstaUserEnum
..
Summary
The NetWkstaUserEnum function lists information about all users
currently logged on to the workstation. This list includes interactive,
service and batch logons.
The NetWkstaUserEnum function lists information about all users
currently logged on to the workstation. This list includes interactive,
service and batch logons.
16/03/2007 14:05:56 - -204.193.143.9
..

If you want to find the user logged in to the workstation, consider
instead a WMI query ("select UserName from Win32_ComputerSystem"), which
has certain advantages (runs faster, less ambigious results, doesn't
require Interop if using .Net 2.0 System.Management namespace, etc.)

Otherwise you could _possibly_ iterate through all the current processes
and find the owning usernames.

HTH

JB
 
W

Willy Denoyette [MVP]

thephatp said:
Is there any possible way to get the currently logged in (active) user
from within a service?

I need the service to start at runtime. I need to capture log on / log
off / switch user events. I haven't gotten to that yet, but it IS
possible from within a windows service, correct? I figured I'd ask
because of my current problem.

Line of code in question:

System.Security.Principle.WindowsIdentity.GetCurre nt().Name

From within an application running locally, the output is
<myLoginName>.
From within a Windows Service running locally in the background, the
output is `NT AUTHORITY\SYSTEM`.

Is there any way to get the currently logged in and active user (in
the case that multiple users are logged in, we only care about the
active one) from code executing in a windows service??

Thanks in advance.

Chad



There are different ways to retrieve the "currently logged on users", it's
however not that easy to get what you call "the currently active interactive
user". The reason for this is that you can have multiple "active interactive
logon sessions" in Windows.
The most reliable way to get at this info is by using System.Management to
query the security eventlog, most Windows versions do write a "Logon/Logoff
record" to the security log (policy dependent) whenever an account logs on
to the system or domain. In order to trace the Logon/Logoff activity, one
could use System.Management and ManagementEventWatcher to watch the
Logon/Logoff as they get written to the eventlog.
When running Vista, one can use the latest
System.Diagnostics.Eventing.Reader EventLogQuery class to get at the same
info as the above method.

Willy.
 
T

thephatp

There are different ways to retrieve the "currently logged on users", it's
however not that easy to get what you call "the currently active interactive
user". The reason for this is that you can have multiple "active interactive
logon sessions" in Windows.
The most reliable way to get at this info is by using System.Management to
query the security eventlog, most Windows versions do write a "Logon/Logoff
record" to the security log (policy dependent) whenever an account logs on
to the system or domain. In order to trace the Logon/Logoff activity, one
could use System.Management and ManagementEventWatcher to watch the
Logon/Logoff as they get written to the eventlog.
When running Vista, one can use the latest
System.Diagnostics.Eventing.Reader EventLogQuery class to get at the same
info as the above method.

Willy.- Hide quoted text -

- Show quoted text -

Thanks for the responses, everyone. This has been really insightful.
Not encouraging, but insightful. ;)

So, Willy, when you say "policy dependent", what type of scenario are
you talking about? Is this typically in a corporate environment,
where an IT group is pushing out policies? Or is this a likely/
unlikely/etc. scenario for the average user at home? And I'm assuming
there is not other way to do this? I figured it was a long shot, but
I was really hoping a I could grab an event of some sort that is fired
in windows that I could catch. Then again, I know so little about
Windows Services vs. Applications--I don't even know if you can use
events (and delegates) in a Windows Service. Is that possible?

Thanks!

Chad
 
W

Willy Denoyette [MVP]

There are different ways to retrieve the "currently logged on users", it's
however not that easy to get what you call "the currently active
interactive
user". The reason for this is that you can have multiple "active
interactive
logon sessions" in Windows.
The most reliable way to get at this info is by using System.Management to
query the security eventlog, most Windows versions do write a
"Logon/Logoff
record" to the security log (policy dependent) whenever an account logs on
to the system or domain. In order to trace the Logon/Logoff activity, one
could use System.Management and ManagementEventWatcher to watch the
Logon/Logoff as they get written to the eventlog.
When running Vista, one can use the latest
System.Diagnostics.Eventing.Reader EventLogQuery class to get at the same
info as the above method.

Willy.- Hide quoted text -

- Show quoted text -

Thanks for the responses, everyone. This has been really insightful.
Not encouraging, but insightful. ;)

So, Willy, when you say "policy dependent", what type of scenario are
you talking about? Is this typically in a corporate environment,
where an IT group is pushing out policies? Or is this a likely/
unlikely/etc. scenario for the average user at home? And I'm assuming
there is not other way to do this? I figured it was a long shot, but
I was really hoping a I could grab an event of some sort that is fired
in windows that I could catch. Then again, I know so little about
Windows Services vs. Applications--I don't even know if you can use
events (and delegates) in a Windows Service. Is that possible?

Thanks!

Chad



Chad,
When say policy I mean "local", domain imposed "group
policy" management and default OS behavior. For instance it's possible that
logging is prevented by
Group Policy managent, also local policies may prevent this, although these
can easily be changed by a local admin.
So, first thing you need to know is your environment, that is the OS
version(s), the
Framework version and kind policy management , after that you have to
inspect your
Security eventlog to see whether logon/logoff events are written. If there
aren't any Logon/Logoff messages written, you'll have to change the policy
(may depend on the OS version).

Only after you see the logon/logoff events in the Security log, you can
start
coding, keep in mind that different OS versions may require some different
techniques, you'll have to code accordingly.

One way to watch for Logon/Logon events, which works on all OSses (XP and
up), is by using System.Management
(basically WMI wrappers) to listen for the Logon/Logoff events when they get
written into the security log.

In your service process, you'll have to spawn a thread to run the Eventlog
"watcher", you may let this thread run until the service stops.

Following snip illustrates the process, I hope it helps to get you
started...

using System.Management;
....

// Thread procedure, start this thread from within OnStart of from
your own service thread procedure.
// Initialize an Eventlog event watcher to look for Security events
with EventIdentifier = 528 (Logon events)
// Note that 528 is valid for W2K, XP, W2K3, this value is not valid
for Vista and higher!
public void WatchLogonEvent(object stateObject)
{
AutoResetEvent stopWatcher = stateObject as AutoResetEvent;
WqlEventQuery q = new WqlEventQuery();
q.EventClassName = "__InstanceCreationEvent";
q.WithinInterval = new TimeSpan(0, 0, 3);
q.Condition = @"TargetInstance ISA 'Win32_NtLogEvent' and
TargetInstance.LogFile='Security' and TargetInstance.EventIdentifier=528";
try
{
using(ManagementEventWatcher watcher = new
ManagementEventWatcher(q))
{
watcher.EventArrived += new
EventArrivedEventHandler(LogonEventArrived);
watcher.Start();
// wait for a stop event
stopWatcher.WaitOne();
watcher.Stop();
}
}
catch(Exception e)
{
// log the event and stop the thread in case of failure, ...
here dump the exception to the debugger
Debug.WriteLine(e);
}
}
// Handle the event, this sample eventhandler dumps all properties
to the debugger
static void LogonEventArrived(object sender, EventArrivedEventArgs
e)
{
foreach(PropertyData pd in e.NewEvent.Properties)
{
ManagementBaseObject mbo = null;
if(( mbo = pd.Value as ManagementBaseObject) != null)
{
foreach(PropertyData prop in mbo.Properties)
{
string eventMessage = string.Format("{0} - {1}",
prop.Name, prop.Value);
// Parse the "InsertionString" property ... to
filter what you need
// For demo purposes dump the string to the debugger
Debug.WriteLine(eventMessage);
}
}
}
}



Check MSDN for details on the Win32_NtLogEvent properties.

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top