Getting the currently logged-in user to a Windows XP Pro system

We have a XP machine which runs scheduled tasks early in the morning and unfortunately has to be logged into the desktop of a certain user for that to work. Unfortunately, that user sometimes gets logged out—either from an administrator logging in (and forgetting to log back in the correct user), or from it being restarted to apply security updates, etc.

I'd like to have Nagios monitor the currently logged in user, to confirm its the right one. Nagios is running on Linux.

So far, I've looked for an SNMP variable with the current user; I've had no luck. I tried snmpbulkwalk -m all -v2c -c community machine and grep'd it for the user name, and also did a before login & after login, and checked the diff, and found nothing useful.

I checked the net command (from Samba), but I don't see anything there—though I admit its possible I missed something. The various session options seem to only display the net session (even when I use my domain admin account).


%WINDIR%\System32\dllcache\query.exe session will give you a list of all the currently logged on users on WinXP.

For some reason, query.exe was not in my path environment variable on my WinXP test machine so that is why I specified the entire path.

query

If you need something that is capable of getting this information remotely over RPC/DCOM, then check out a couple of things I wrote:

http://myotherpcisacloud.com/post/2013/01/16/Usersexe-v1003.aspx

http://www.myotherpcisacloud.com/post/2013/01/13/Getting-RDP-Sessions-with-Client-Computer-Name.aspx

By the way, you need to get off of XP ASAP. It's very old.

Edit: OK, I am going to give you another alternative since none of this has helped you yet. You want to query this WinXP machine over the network using your Linux machine. You want to use WMI. You have found a WMI client for Linux. So far so good.

This will get you currently logged on users of a local or remote machine through WMI WQL queries. I wrote this in Powershell. Sorry, I won't (read: can't) convert it to Perl or Bash for you, but the concept is what is still the same as long as you can do WQL queries:

$Sessions = Get-WMIObject -Query "SELECT * FROM Win32_LogonSession WHERE LogonType=2 OR LogonType=10"
Foreach($Session In $Sessions)
{
    If($Session -AND $Session.PSObject.Properties.Match('LogonId').Count)
    {
        Get-WMIObject -Query "Associators Of {Win32_LogonSession.LogonId=$($Session.LogonId)} WHERE AssocClass=Win32_LoggedOnUser Role=Dependent"
    }
}

LogonTypes of 2 and 10 cover both local and remote interactive sessions, but not service logons, network logons, or batch logons.

Yes, you do need permissions to access the WinXP machine. It's not just going to cough up all this data for an anonymous network process. The local groups on WinXP are not very granular, because WinXP is very old, and its security is far inferior to that of modern versions of Windows... my point being that putting your network monitoring user in the local Admins group of the WinXP machine may be your best option. But I commend you if you still want to go with the principle of least privilege, in which case, you can use the WMI Control Console, wmimgmt.msc, and set the permissions to exactly whatever account you want to assign the permissions to.


Thanks yo @Ryan Ries, here is the actual Perl script I'm using. Hopefully it proves useful to someone else. It appears to be working, please feel free to report any bugs. I'll try to remember to update this if I find any.

Also, I couldn't find any way to make this work on XP other than putting the monitoring user in Administrators. I think that's the only way to do it on XP.

#!/usr/bin/perl -w
use 5.010;
use IPC::Run qw(run);
use Nagios::Plugin;
use strict;

my $np = Nagios::Plugin->new(
    shortname => 'check_windows_user',
    version   => '0.01',
    license   => 'Copyright 2013 Customer Relationship Metrics, LC. Based on a Powerhell program by Ryan Ries. CC-BY-SA http://creativecommons.org/licenses/by-sa/3.0/',
    usage =>
        'Usage: %s -H <host> -A <authfile> -u <user>|-s <sid> -w <threshold> -c <threshold>',
    extra => <<EXTRA

Thresholds are in session counts.

See http://nagiosplug.sourceforge.net/developer-guidelines.html for a
description of the threshold format.
EXTRA
);

$np->add_arg(
    spec     => 'host|H=s',
    help     => '-H, --host=hostname',
    required => 1,
);
$np->add_arg(
    spec     => 'user|u=s',
    help     => '-u, --user=username',
    required => 0,
);
$np->add_arg(
    spec     => 'sid|s=s',
    help     => '-s, --sid=sid',
    required => 0,
);
$np->add_arg(
    spec     => 'authentication_file|authentication-file|A=s',
    help     => '-A, --authentication-file=FILE',
    required => 1,
);
$np->add_arg(
    spec     => 'warning|w=s',
    help     => '-w, --warning=INTEGER:INTEGER',
    required => 1,
);
$np->add_arg(
    spec     => 'critical|c=s',
    help     => '-c, --critical=INTEGER:INTEGER',
    required => 1,
);
$np->getopts;
$np->set_thresholds(
    warning  => $np->opts->warning,
    critical => $np->opts->critical
);

# setup
local $SIG{ALRM} = sub { die "alarm timed out\n" };
alarm 30;

my $target_user = defined $np->opts->user ? lc $np->opts->user : undef;
my $target_sid  = defined $np->opts->sid  ? lc $np->opts->sid  : undef;

my @wmic = (
    'wmic',
    -A => $np->opts->authentication_file,
    ('//' . $np->opts->host));
my $wmic_out;

# get all logon ids
my @all_logon_ids;
run [
    @wmic,
    q{SELECT LogonId FROM Win32_LogonSession WHERE LogonType = 2 or LogonType = 10}
    ],
    \undef, \$wmic_out;
@all_logon_ids = split("\n", $wmic_out);

$all_logon_ids[0] =~ /^CLASS: Win32_LogonSession$/
    or die "Unexpected wmic result: $wmic_out";
$all_logon_ids[1] =~ /^LogonId$/
    or die "Unexpected wmic result: $wmic_out";
splice @all_logon_ids, 0, 2;

# get user of each logon, check if matches
my $session_count = 0;
foreach my $logon_id (@all_logon_ids) {
    # does not seem to be a way to specify which fields we want, or
    # their order  :-(
    #
    # also, it only seems to do delimited data — pick a character that
    # isn't going to occur in the data. And unit separator is even for
    # that purpose!
    run [
        @wmic,
        '--delimiter' => "\x1F",
        qq{Associators Of {Win32_LogonSession.LogonId=$logon_id} WHERE AssocClass=Win32_LoggedOnUser Role=Dependent}
        ],
        \undef, \$wmic_out;

    # sessions get left in Win32_LogonSession after log out (sometimes).
    next if '' eq $wmic_out;

    my @tmp = split("\n", $wmic_out);
    3 == @tmp && $tmp[0] =~ /^CLASS: Win32_UserAccount$/
        or die "Unexpected associator: $wmic_out";
    my %record;
    @record{map lc, split("\x1F", $tmp[1])} = map lc,
        split("\x1F", $tmp[2]);

    # try to disqualify
    defined $target_user && $target_user ne $record{caption}
        and next;
    defined $target_sid && $target_sid ne $record{sid}
        and next;

    # qualified
    ++$session_count;
}

$np->add_message($np->check_threshold($session_count),
    "$session_count sessions");

$np->nagios_exit($np->check_messages);

Changelog

  • Apparently, if you log out a session via remote desktop, and don't log in another user, the session gets left in Win32_LogonSession, but with nothing associated. Status is always null, so can't filter that way. Filter by lack of associations. Without this two-line fix, plugin would die (and thus return unknown).