It's useful to be able to query a computer for the users that are logged on
locally. You can do this with Sysinternals' free PsLoggedOn utility, but sometimes
you want to use the information directly in a scripted task (e.g., contacting
users who are logged on to a terminal server that needs a reboot because of
a security patch). Although it's possible to execute the PsLoggedOn utility
and parse its output in a script for use in other scripts, I decided to see
whether I could gather the names of logged-on users by using a script instead
of relying on PsLogged-On.
How PsLoggedOn Works
I started by downloading and examining the C source code for the Ps-LoggedOn
utility to see how it determines locally logged-on users. The technique it uses
isn't complex and is fairly easy to implement by calling the methods in Windows
Management Instrumentation's (WMI's) StdRegProv class. An overview of the technique
PsLoggedOn uses is as follows:
- Enumerate the subkeys in the computer's HKEY_USERS registry subtree.
- For each subkey in the subtree that contains a SID value, determine whether
the subkey contains a Volatile Environment subkey. If it does, and if the
Volatile Environment subkey contains one or more values, then the user that
the SID represents is currently logged on.
- Convert the SID value into the corresponding username.
In Figure 1, the HKEY _USERS subtree is expanded
to show a subkey that has a SID value. You can also see that the subkey contains
a Volatile Environment subkey that contains values. Thus, you know that the
user represented by the SID S-1-5-21-299502267-1078145449-725345543-500 is currently
logged on.
Introducing LoggedOn.js
LoggedOn.js provides a couple of advantages over the PsLoggedOn tool. First,
you don't have to parse Logged-On.js's output when you need a list of logged-on
users for a script. Second, it doesn't rely on any third-party functionality.
Depending on third-party code can be a problem in some environments. LoggedOn.js
uses the same technique as PsLoggedOn to list local logons on a specified computer.
To run the script, you need either Windows XP or later, or Windows 2000 with
Windows Script Host (WSH) 5.6. The script's command-line syntax is
LoggedOn.js <computername>
where computername is the name of the computer whose locally logged-on users you want to retrieve. Logged-On.js connects to the specified computer and lists the users who are logged on locally.
If you need to query Win2K Service Pack 4 (SP4) computers for local logons,
there's a problem you need to know about. Win2K SP4's StdRegProv class has a
bug that prevents WMI-based scripts and programs from querying the HKEY_USERS
subtree. To fix this bug, you need to get a copy of the hotfix mentioned in
the Microsoft article "Cannot Use WMI to Query HKEY Users After You Install
SP4" at http://support.microsoft.com/?kbid= 817478. The hotfix updates the stdprov.dll
file in %SystemRoot%\system 32 and doesn't require a reboot. You'll have to
call Microsoft Product Support Services to get a copy of the hotfix.
Also, for best results, I highly recommend that you use UPHClean, a free Microsoft
utility that monitors a computer when users log off and ensures that user profiles
are completely unloaded. Otherwise, Logged-On.js (and PsLoggedOn as well) might
report logons for users who have since logged off but whose profiles didn't
unload completely. For more information about the UPHClean service, see the
Microsoft article "Troubleshooting profile unload issues" at http://support.microsoft.com/?kbid=837115.
Inside LoggedOn.js
The LoggedOn.js script, excerpted in Listing
1, starts by declaring some global variables. It then calls the Quit method
of the WScript object, with the main function as a parameter. In other words,
the main function's return value is the script's exit code.
The main function declares some variables and parses the command line. It uses
the first unnamed argument (i.e., the first argument on the script's command
line that doesn't start with a / character) as the computer name. Callout C
in Listing 1 shows the try block
that the main function uses to connect to the computer. If the connection succeeds,
the code in the catch block never executes. In case an error occurs, the catch
block causes the main function to display an error message and execute the return
statement with the error number as its argument.