Link to home
Start Free TrialLog in
Avatar of ProUAdmin
ProUAdmin

asked on

Display User Logged On to a Shared Computer with WMI and VBScript

We have several shared Windows XP computers that have special software on them. People either physically sit at them or connect via Remote Desktop. There's no way of knowing if they're in use, so our users get frustrated when they have to try to connect over and over to find an available one.

I plan on designing a webpage to list all the shared computers and who's currently using them. I might design this using PHP, Ruby, or ASPX - I haven't decided yet. However, I really only need the WMI required and a simple VBScript as a proof of concept. I know there's a lot of scripts like this online, but I couldn't find one that would only display the user actively using the desktop (RDP session 0). If the registry isn't released or there's a user connected via SMB share, they're also displayed. I only want the active user to be displayed.

Thanks.
Avatar of JLuhn
JLuhn
Flag of United States of America image

Avatar of ProUAdmin
ProUAdmin

ASKER

JLuhn, I tried example 3 and it worked well on one of the computers I tried it on, but on another it displayed "No one is currently logged on at COMPUTERNAME", but there was someone logged on. Any thoughts?
sorry again
but this is what i created.  You have to run it as someone who has privileges on the machine
blank return is no one is logged in


strComputer=InputBox ("Enter the computer name")


Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery( _
    "SELECT * FROM Win32_ComputerSystem",,48)
For Each objItem in colItems
   
    Wscript.Echo "UserName: " & objItem.UserName
Next
I tried that and got similar results for one of our computers. It displayed "UserName:" without any listed user, but there was a user actively using the computer.
Avatar of spinzr0
Try this one.  Let me know what the output is for the one that doesn't work
On Error Resume Next

sComputerName = "<compname>"
Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate,(Security)}!//" & sComputerName & "/root/cimv2")

If Err.Number <> 0 Then
    Msgbox "Unable to access WMI for computer: " & sComputerName
    Wscript.Quit
End If

Err.Clearn
Set cComputerSystem = oWMI.ExecQuery("Select UserName from Win32_ComputerSystem")

If Err.Number <> 0 OR cComputerSystem.Count = 0 Then
    Msgbox "Unable to get the user for computer: " & sComputerName
    Wscript.Quit
End If

For Each oComputerSystem in cComputerSystem
    If IsNull(oComputerSystem.UserName) Then 'If no one is logged on
        Msgbox "No one is logged in."
    Else
        Msgbox oComputerSystem.UserName
    End If
Next
Set cComputerSystem = Nothing

Open in new window

An easy way is to use netusers.exe and something like

ECHO Enter a Machine Name
SET /P Machine=
NetUsers \\%machine%

this will give you who is logged in.
spinzr0, it said "Unable to get the user for computer"

mortonmark, what is NetUsers and where can I get it?
mortonmark, I found NetUsers.exe. It's a pretty cool tool, but when I ran it, it shows two users listed as logged on locally, but it's a Windows XP machine, so only one person can be logged on at a time.
if you run it locally on the machine does it work?  It could be a corrupt WMI repository.  If it it, I can give you code to repair that.
Or, we can avoid WMI and just read the value of the last user that logged into the machine.  Might be easier.  Want code for that?  Or does it have to be WMI?
The article here demonstrates how to query the registry to obtain the last user to logon:

Hey, Scripting Guy! How Can I Get the Name of the Last User to Log on to a Computer?
http://blogs.technet.com/b/heyscriptingguy/archive/2007/01/23/how-can-i-get-the-name-of-the-last-user-to-log-on-to-a-computer.aspx

Regards,

Rob.
RobSampson, yes this is true but if auto admin logon is enabled this key will contain the name of the user setup to auto logon as, not necessarily the last user logged on
Yes true, but I would be surprised if too many people had auto admin logons in a work environment....

Rob.
spinzr0, can you give me the code to repair the WMI repository please.
ProUAdmin, you could try running WMIDiag: http://www.microsoft.com/downloads/details.aspx?familyid=d7ba3cd6-18d1-4d05-b11e-4c64192ae97d

or, probably as a last resort, as suggested here:
http://www.tek-tips.com/viewthread.cfm?qid=1448949&page=6

you could try running
rundll32 wbemupgd, UpgradeRepository

Regards.

Rob.
I ran WMIDiag on one of the computers and found some errors, so I ran rundll32 wbemupgd,UpgradeRepository, but I still had the same errors. When I have time, I may try the "comprehensive rebuild method" described at http://windowsxp.mvps.org/repairwmi.htm.

Most of these scripts work when no one is logged on or when I'm logged on, but when it's another user, they incorrectly display no user logged on. I'm a domain admin, so I don't think it's a security issue and psloggedon displays expected results. Any idea why these scripts, mainly the one attached, works when I'm logged on to the remote computer, but not when someone else is?
strComputer=InputBox ("Enter the computer name")


Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2") 
Set colItems = objWMIService.ExecQuery( _
    "SELECT * FROM Win32_ComputerSystem",,48) 
For Each objItem in colItems 
    
    Wscript.Echo "UserName: " & objItem.UserName
Next

Open in new window

I just did some more tests with a spare computer in my office using the script I posted previously. In these tests, I'm UserA and my co-worker is UserB. These are my results:

No one logged on: Displays no one logged on
UserA logged on locally: Displays UserA
UserA logged on via RDP: Displays UserA
UserB logged on locally: Displays UserB
UserB logged on via RDP: Displays no one logged on (incorrect)

Any ideas?
I see you've done more testing.  Not sure why its not reading correctly.  Here is the code I use to repair WMI.
Call CheckWMIWorking()

Sub CheckWMIWorking()
    On Error Resume Next

    If Not IsObject(oWMI) Then
        Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate,(Security)}!\\.\root\cimv2")
        bClearObject = True
    End If
    Set cItems = oWMI.ExecQuery("Select EventCode from Win32_NTLogEvent where Logfile = 'System' AND SourceName ='disk'")

'*******************************************************************
'If the log file is unreadable, notify local IT
'*******************************************************************
    If Err.Number <> 0 Then
        Call RepairWMI()
        Wscript.Sleep 5000
    End If
    Set cItems = Nothing
    If bClearObject = True Then Set oWMI = Nothing
End Sub

Sub RepairWMI()
    On Error Resume Next

    If Not IsObject(oFS) Then Set oFS = CreateObject("Scripting.FileSystemObject")
    If Not IsObject(oWShell) Then Set oWShell = CreateObject("Wscript.Shell")

    Call VerifyServiceStartMode("Winmgmt", 2)

    sWindowsDirectory = oWShell.ExpandEnvironmentStrings("%windir%")

    oWShell.Run "Net stop winmgmt", 0, True

    If oFS.FolderExists(sWindowsDirectory & "\System32\Wbem\Repository") Then _
        oFS.MoveFolder sWindowsDirectory & "\System32\Wbem\Repository", sWindowsDirectory & "\System32\Wbem\Repository.OLD"

    oWShell.Run "Net start winmgmt", 0, True

    If InStr(LCase(GetWindowsVersion()), "windows 7") > 0 OR InStr(LCase(GetWindowsVersion()), "vista") > 0 Then
        oWShell.Run "winmgmt /salvagerepository", 0, True
    Else
        oWShell.Run "rundll32 wbemupgd, UpgradeRepository", 0, True
    End If
End Sub

Sub VerifyServiceStartMode(sService, iStartMode)
    On Error Resume Next

    If Not IsObject(oWShell) Then Set oWShell = CreateObject("Wscript.Shell")
    iCurrentStart = oWShell.RegRead("HKLM\SYSTEM\CurrentControlSet\services\" & sService & "\Start")
    If iCurrentStart <> iStartMode Then _
        oWShell.RegWrite "HKLM\SYSTEM\CurrentControlSet\services\" & sService & "\Start", iStartMode, "REG_DWORD"
End Sub

Function GetWindowsVersion()
    On Error Resume Next

    If Not IsObject(oWShell) Then Set oWShell = CreateObject("Wscript.Shell")
    GetWindowsVersion = oWShell.RegRead("HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName")
End Function

Open in new window

I will try that repair code and get back to you.
spinzr0, I created a vbs file and copied your code in it, but when I run it, nothing happens. Am I missing something?
I messed around with this some more and found that the attached code gives me better results. I will continue to test it and report my results back.
strComputer = "prou-13h67d1"

Set objWMI = GetObject("winmgmts:" _
              & "{impersonationLevel=impersonate}!\\" _
              & strComputer & "\root\cimv2")

Set colSessions = objWMI.ExecQuery _
    ("Select * from Win32_LogonSession Where LogonType = 2 OR LogonType = 10")

If colSessions.Count = 0 Then
   Wscript.Echo "No interactive users found"
Else
   For Each objSession in colSessions
     If objSession.LogonType = 2 Then
       WScript.Echo "Logon type: Console"
     Else
       WScript.Echo "Logon type: RDP/Terminal Server"
     End If
     Set colList = objWMI.ExecQuery("Associators of " _
         & "{Win32_LogonSession.LogonId=" & objSession.LogonId & "} " _
         & "Where AssocClass=Win32_LoggedOnUser Role=Dependent" )

     For Each objItem in colList
       WScript.Echo "User: " & objItem.Name
       WScript.Echo "FullName: " & objItem.FullName
       WScript.Echo "Domain: " & objItem.Domain
     Next
     Wscript.Echo "Session start time: " & objSession.StartTime
     WScript.Echo
   Next
End If

Open in new window

The code I attached in my previous comment works for users logged on locally or via RDP, but it's incorrectly displaying users that have already logged off. So, I installed the User Profile Hive Cleanup Utility thinking this would fix the problem. After restarting, it correctly displayed no user logged on. I logged on as a test user and it correctly displayed that user. However, after logging off, it still displayed my test user. I would assume this is just a problem with the computer and not the script itself. Any ideas?
Have you tried QUser.exe for this problem?  Try the approach here to see if it works:
https://www.experts-exchange.com/questions/24084229/Display-only-inactive-logged-in-remote-desktop-users-with-vbscript.html

Regards,

Rob.
I will check out QUser.exe and report my findings here.
I still haven't had time to work on this, but when I do, I will report back my findings.
Sure, no problem. Thanks for the update.

Rob.
QUser.exe didn't work for me. Every time I run it against a Windows XP machine, I get this error:

Error opening Terminal server COMPUTERNAME
Error [5]:Access is denied.

Is quser.exe only for servers?
OK, how about this? I've combined your latest code, with a routine that obtains a list of Explorer.exe process instances on the system, and their owners.  It then compares the two to see who has a live session.

Regards,

Rob.
If LCase(Right(Wscript.FullName, 11)) = "wscript.exe" Then
    strPath = Wscript.ScriptFullName
    strCommand = "%comspec% /k cscript  """ & strPath & """"
    Set objShell = CreateObject("Wscript.Shell")
    objShell.Run(strCommand), 1, True
    Wscript.Quit
End If

strComputer = InputBox("Enter computer name:")

Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set objUsers = CreateObject("Scripting.Dictionary")
Set colProcessList = objWMI.ExecQuery("Select Name From Win32_Process Where Name='explorer.exe'")
For Each objProcess In colProcessList
	colProperties = objProcess.GetOwner(strNameOfUser,strUserDomain)
	If objUsers.Exists(LCase(strUserDomain & "\" & strNameOfUser)) = False Then objUsers.Add LCase(strUserDomain & "\" & strNameOfUser), 0
Next

Set colSessions = objWMI.ExecQuery("Select * From Win32_LogonSession Where LogonType = 2 OR LogonType = 10")

If colSessions.Count = 0 Then
	Wscript.Echo "No interactive users found"
Else
	For Each objSession In colSessions
		If objSession.LogonType = 2 Then
			strLogonType = "Console"
		Else
			strLogonType = "RDP/Terminal Server"
		End If
		strLoginID = objSession.LogonID

		Set colList = objWMI.ExecQuery("Associators of " _
			& "{Win32_LogonSession.LogonId=" & strLoginID & "} " _
			& "Where AssocClass=Win32_LoggedOnUser Role=Dependent" )

		For Each objItem In colList
			strUser = objItem.Name
			strFullName = objItem.FullName
			strDomain = objItem.Domain
		Next
		strSessionStart = objSession.StartTime
		
		If objUsers.Exists(LCase(strDomain & "\" & strUser)) = True Or strLogonType = "Console" Then
			WScript.Echo "Logon type: " & strLogonType
			WScript.Echo "Login ID: " & strLoginID
			WScript.Echo "User: " & strUser
			WScript.Echo "FullName: " & strFullName
			WScript.Echo "Domain: " & strDomain
			WScript.Echo "Session start time: " & strSessionStart
			WScript.Echo
		End If
	Next
End If

Open in new window

Thanks for trying, RobSampson, but it still incorrectly displayed the last logged on user. Before I logged on is said user "First Last" was logged on even though he wasn't:

Logon type: Console
Login ID: 687066269
User: flast
FullName: First Last
Domain: DOMAIN
Session start time: 20101117170047.465726-480

After I logged on, it showed me and "First Last", but it's Windows XP, so that's not even possible:

Logon type: Console
Login ID: 687066269
User: flast
FullName: First Last
Domain: DOMAIN
Session start time: 20101117170047.465726-480

Logon type: RDP/Terminal Server
Login ID: 732628151
User: prouadmin
FullName: ProU Admin
Domain: DOMAIN
Session start time: 20101118215225.917562-480
I have made one last suggestion, and would like the author to try it.
SOLUTION
Avatar of RobSampson
RobSampson
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
RobSampson, that's pretty promising. I will need to test it some more tomorrow, but so far, it looks like it's working as expected. Thanks for your help.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I accepted my own comment without awarding points by accident.
That's good to hear.  That was the last idea I had!  I remember reading somewhere that Win32_LogonSession wasn't reliable, for the reasons you have encountered, but at least we could use active processes to help make it more accurate.

This is one for the memory bank.

Regards,

Rob.
RobSampson's original script plus minor change solved my problem.