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.
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.
http://www.computerperformance.co.uk/vbscript/wmi_who_logon.htm#Example_1_-_Discover_who_is_Logged_on_at_a_Computer
Also a nice little tool (WMI code creator)
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=2cc30a64-ea15-4661-8da4-55bbc145c30e&displaylang=en
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=2cc30a64-ea15-4661-8da4-55bbc145c30e&displaylang=en
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
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
ASKER
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.
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
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.
ECHO Enter a Machine Name
SET /P Machine=
NetUsers \\%machine%
this will give you who is logged in.
ASKER
spinzr0, it said "Unable to get the user for computer"
mortonmark, what is NetUsers and where can I get it?
mortonmark, what is NetUsers and where can I get it?
ASKER
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.
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.
Rob.
ASKER
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.
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.
ASKER
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?
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
ASKER
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?
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
ASKER
I will try that repair code and get back to you.
ASKER
spinzr0, I created a vbs file and copied your code in it, but when I run it, nothing happens. Am I missing something?
ASKER
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
ASKER
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.
https://www.experts-exchange.com/questions/24084229/Display-only-inactive-logged-in-remote-desktop-users-with-vbscript.html
Regards,
Rob.
ASKER
I will check out QUser.exe and report my findings here.
ASKER
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.
Rob.
ASKER
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?
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.
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
ASKER
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
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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.
This is one for the memory bank.
Regards,
Rob.
ASKER
RobSampson's original script plus minor change solved my problem.