Finding Logged on Users and More Scripting Secrets

Welcome back for the fourth installment of Nilpo’s Scripting Secrets. If you missed the first three articles in this series, this is where I present collections of useful script bits that perform useful tasks or present scripting workarounds that might not otherwise be possible in scripting. I’ve got some good stuff in store for you today, so let’s jump right in.

The first script I want to present to you is a very useful script that will enumerate all of the STOP or bug check errors on a system.  These are commonly referred to as BSODs or errors that result in a Blue Screen Of Death.  This script is especially handy for network administrators who want to poll an entire network of computers for trouble spots, or for technicians who are profiling a troublesome machine.  Heck, it’s even good for the average user to inspect a computer for problems they might not even know exist!

strComputer = "."

Set objWMIService = GetObject("winmgmts:" _

    & "{impersonationLevel=impersonate}!" & strComputer & "rootcimv2")

This script starts off the same way as any other WMI script.  VBScript’s GetObject method is used to connect to the local WMI service in the rootcimv2 namespace.  This is where all of the most common WMI classes are found.

Set colLoggedEvents = objWMIService.ExecQuery _

    ("Select * from Win32_NTLogEvent Where Logfile = ‘System’" _

        & " and SourceName = ‘SaveDump’")

Next we query the System Event Log for entries that have the source name “SaveDump.”  This is the name used by Windows any time that it logs a BSOD error.  Of course, your system will have to have logging enabled or it won’t be creating event log entries in the first place.  If you’re not sure what I’m talking about, don’t worry; it’s enabled by default.

For Each objEvent in colLoggedEvents

    Wscript.Echo "Event date: " & objEvent.TimeGenerated

    Wscript.Echo "Description: " & objEvent.Message

Next

The WMI query will return a collection of events from the event log.  A simple For loop can be used to move through each of them and print some information about the errors.  The TimeGenerated and Message properties are probably the most useful.  They return the time when the BSOD occurred and the associated error message, respectively.

{mospagebreak title=More on BSODs}

Since I mentioned that the system must be configured to write crashes to the System Event Log, let’s look at how we can check if it is.  Once again, WMI is our friend!

strComputer = "."

 

Set objWMIService = GetObject("winmgmts:" & strComputer & "rootcimv2")

Set colRecoveryConfigs = objWMIService.InstancesOf _

   ("Win32_OSRecoveryConfiguration")

 

For Each objRecoveryConfig In colRecoveryConfigs

   WScript.Echo "Write crashes to System Log: " _

       & CStr(objRecoveryConfig.WriteToSystemLog)

Next

This is a typical WMI script that returns a single property from a WMI class.  You’ve probably seen this done a million times.  I decided to switch it up a little here though.  Instead of writing a Select query and using WMI’s ExecQuery method, I’ve instead chosen to use the InstancesOf method.  Whenever you want to return all instances of a WMI class, this is a little more efficient than a “Select * from” query.

In this particular case, the Win32_OSRecoveryConfiguration class returns a single object that represents the OS recovery options.  The WriteToSystemLog property returns a Boolean value that indicates whether or not system crashes should be written to the event log.  And guess what?  It’s a read/write property, which means you can use a simple variation of this script to set that particular system setting.

strComputer = "."

 

Set objWMIService = GetObject("winmgmts:" & strComputer & "rootcimv2")

Set colRecoveryConfigs = objWMIService.InstancesOf _

   ("Win32_OSRecoveryConfiguration")

 

For Each objRecoveryConfig In colRecoveryConfigs

   objRecoveryConfig.WriteToSystemLog = vbTrue

Next

Here’s a script that does just that!  Once again we use WMI to connect to the Win32_OSRecoveryConfiguration class.  This time we assign the Boolean value True to the WriteToSystemLog property to configure the current system to write crash events to the System Event Log.  Since this is WMI, you could easily roll this out to all of the computers in a network.

{mospagebreak title=Getting the currently logged on user}

I’m constantly getting questions on my web site and various forum sites about how to determine the currently logged on user in WSH.  You would think that the WScript environment would provide such a useful piece of information, but it doesn’t.  That doesn’t, however, mean that it’s not possible.  In fact, I’m going to show you not one, but three different ways of doing it.

strComputer = "."

Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!" _

   & strComputer & "rootcimv2")

Set colComputers = objWMIService.InstancesOf("Win32_ComputerSystem")

The first way involves using the Win32_ComputerSystem WMI class, which returns basic information about the operating system and various system and environmental settings used for auditing a Windows session.

For Each objComputer in colComputers

   strUser = objComputer.UserName

   strUser = Replace(strUser, objComputer.Name & "", "")   ‘Local User Account

   strUser = Replace(strUser, objComputer.Domain & "", "") ‘Domain User Account

   ‘Exit For

Next

 

WScript.Echo "User:", strUser

Once you grab the current instance of the Win32_ComputerSystem class, you can use its UserName property to return the currently logged on user.  This will return in the form of either ComputerNameUser or DomainUser, dependent upon whether this current user is a local or domain user, respectively. 

In the example above, I’ve done a little parsing to return just the user’s name.  VBScript’s Replace function is used to strip out the computer name or the domain name from the string.  These two bits of information can be returned by the Win32_ComputerSystem class as well using the Name and Domain properties.

{mospagebreak title=Getting the currently logged on user, method 2}

The second method I’ll show you for getting the local logged on user is a little more involved script that returns the user name of a currently logged on interactive user.  It’s also capable of returning a lot of information about the current Windows session, including logon time among other things.

strComputer = "."

Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!" _

   & strComputer & "rootcimv2")

Set colSessions = objWMI.ExecQuery _

   ("Select * from Win32_LogonSession Where LogonType = 2")

The code begins in a way that should be very familiar to you for WMI scripts.  It first returns a reference to the local WMI service.  Then, it executes a query that returns all instances of the Win32_LoginSession class where the LogonType property has a value of 2 (interactive logon).

If colSessions.Count = 0 Then

   ‘ No interactive session found

   WScript.Echo "No interactive user found"

Else

Next, I add a simple If statement that prevents the script from bombing out if there is no current interactive session.

   ‘Interactive session found

   For Each objSession in colSessions

       Set colList = objWMI.ExecQuery("Associators of " _

          & "{Win32_LogonSession.LogonId=" & objSession.LogonId & "} " _

          & "Where AssocClass=Win32_LoggedOnUser Role=Dependent")

Here’s where the script begins to get tricky.  The query we ran to start the script returned a collection of current logon sessions.  For each of those sessions we are going to run a second query that uses a special Associators of syntax.

In WMI, the Associators of statements will return all instances from other WMI classes that are associated with a given WMI instance.  In this case, we’re returning all associated instances for the current session logon instance that was provided by the Win32_LogonSession.  In this case, the associated instances provide user information for the user who is logged on to the current session.

       ‘ Show user info

       For Each objItem in colList

          WScript.Echo "User: " & objItem.Name

          WScript.Echo "FullName: " & objItem.FullName

          WScript.Echo "Domain: " & objItem.Domain

       Next

Here you can see where I’m accessing properties provided by the associated instances.  Specifically, I’m accessing the Name property for the logged-on user’s name, the FullName property for the user’s Full Name, and the current domain name.

       ‘ Show session start time

       WScript.Echo "Start Time: " & objSession.StartTime

   Next

End If

The instance returned by the Win32_LogonSession class also contains valuable information, such as the time when the user logged on.  Notice that this property is coming from the original objSession instance, and not the associated objItem instance.

{mospagebreak title=Getting the currently logged on user, method 3}

The third and final method I’m presenting for finding the locally logged on user returns information based on networking settings.  This is the credential information used by Windows NT Authentication when attempting to connect to other computers or servers.  Since NT Authentication bases this off the current user’s Windows login information, the details are the same.

strComputer = "."

Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!" _

   & strComputer & "rootcimv2")

 

Set colProfiles = objWMIService.InstancesOf("Win32_NetworkLoginProfile")

 

For Each objProfile In colProfiles

   If InStr(objProfile.Caption, "NT AUTHORITY") = 0 Then

       strUser = objProfile.Caption

       Exit For

   End If

Next

 

WScript.Echo "Network User:", strUser

Again, this should be a familiar-looking WMI script.  It simply returns all instances of the Win32_NetworkLoginProfile class which represent logged-on network users.  However, since there are also default profiles (such as those used by network shares), we need to weed this list down to just the currently logged on user.  Fortunately, all of the system profiles begin with the text NT AUTHORITY.  Thus, ignoring all instances containing this text will return only the locally logged on user’s instance.  The Caption property contains the user’s name.

That wraps up this installment of Nilpo’s Scripting Secrets.  I hope you’ve found something useful or educational in these scripts.  For nearly every task you’d like to complete in scripting, there is a solution if you are willing to look hard enough for it.  Until next time, keep coding!

[gp-comments width="770" linklove="off" ]