Solved

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

Posted on 2010-09-24
37
3,858 Views
Last Modified: 2013-11-21
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.
0
Comment
Question by:ProUAdmin
  • 19
  • 9
  • 4
  • +2
37 Comments
 
LVL 4

Expert Comment

by:JLuhn
ID: 33756540
0
 
LVL 4

Expert Comment

by:JLuhn
ID: 33756575
0
 

Author Comment

by:ProUAdmin
ID: 33756659
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?
0
 
LVL 4

Expert Comment

by:JLuhn
ID: 33756688
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
0
 

Author Comment

by:ProUAdmin
ID: 33756747
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.
0
 
LVL 8

Expert Comment

by:spinzr0
ID: 33757258
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

0
 
LVL 1

Expert Comment

by:mortonmark
ID: 33757260
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.
0
 

Author Comment

by:ProUAdmin
ID: 33757799
spinzr0, it said "Unable to get the user for computer"

mortonmark, what is NetUsers and where can I get it?
0
 

Author Comment

by:ProUAdmin
ID: 33757823
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.
0
 
LVL 8

Expert Comment

by:spinzr0
ID: 33757966
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.
0
 
LVL 8

Expert Comment

by:spinzr0
ID: 33757970
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?
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 33759942
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.
0
 
LVL 1

Expert Comment

by:mortonmark
ID: 33761917
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
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 33762128
Yes true, but I would be surprised if too many people had auto admin logons in a work environment....

Rob.
0
 

Author Comment

by:ProUAdmin
ID: 33812214
spinzr0, can you give me the code to repair the WMI repository please.
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 33812439
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.
0
 

Author Comment

by:ProUAdmin
ID: 33837050
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

0
 

Author Comment

by:ProUAdmin
ID: 33837138
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?
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 8

Expert Comment

by:spinzr0
ID: 33837244
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

0
 

Author Comment

by:ProUAdmin
ID: 33901755
I will try that repair code and get back to you.
0
 

Author Comment

by:ProUAdmin
ID: 33937699
spinzr0, I created a vbs file and copied your code in it, but when I run it, nothing happens. Am I missing something?
0
 

Author Comment

by:ProUAdmin
ID: 33937880
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

0
 

Author Comment

by:ProUAdmin
ID: 33938105
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?
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 33953432
Have you tried QUser.exe for this problem?  Try the approach here to see if it works:
http://www.experts-exchange.com/Programming/Languages/Visual_Basic/VB_Script/Q_24084229.html

Regards,

Rob.
0
 

Author Comment

by:ProUAdmin
ID: 33984322
I will check out QUser.exe and report my findings here.
0
 

Author Comment

by:ProUAdmin
ID: 34095508
I still haven't had time to work on this, but when I do, I will report back my findings.
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 34097630
Sure, no problem. Thanks for the update.

Rob.
0
 

Author Comment

by:ProUAdmin
ID: 34170516
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?
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 34170567
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

0
 

Author Comment

by:ProUAdmin
ID: 34170615
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
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 34170617
I have made one last suggestion, and would like the author to try it.
0
 
LVL 65

Assisted Solution

by:RobSampson
RobSampson earned 500 total points
ID: 34170628
OK, well I did have this:
            If objUsers.Exists(LCase(strDomain & "\" & strUser)) = True Or strLogonType = "Console" Then

which shows the "Console" user no matter what, so change that to this:
            If objUsers.Exists(LCase(strDomain & "\" & strUser)) = True Then

and see what you get.

Rob.
0
 

Author Comment

by:ProUAdmin
ID: 34170669
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.
0
 

Accepted Solution

by:
ProUAdmin earned 0 total points
ID: 34184205
RobSampson, your code (attached) worked in all of the scenarios (user logged on via console, user logged on via RDP, user logged off) and it met my criteria. Thank you for your help, sir.
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 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

0
 

Author Comment

by:ProUAdmin
ID: 34184215
I accepted my own comment without awarding points by accident.
0
 
LVL 65

Expert Comment

by:RobSampson
ID: 34184327
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.
0
 

Author Closing Comment

by:ProUAdmin
ID: 34216182
RobSampson's original script plus minor change solved my problem.
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

It is only natural that we all want our PCs to be in good working order, improved system performance, so that is exactly how programs are advertised to entice. They say things like:            •      PC crashes? Get registry cleaner to repair it!    …
Know what services you can and cannot, should and should not combine on your server.
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now