WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

User Profiles

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

Best way to find the currently logged in user


Question:

What is the best way to find the currently logged in user if your compiled winbatch .exe will not be run in the currently logged in user's context? I have used both Environment("USERNAME") and wntGetUser(netname) and if I double click the winbatch program containing either of these two commands, I get the currently logged in user. If I run the executable as someone else (to simulate an SMS job distribution) I get the name of the SMS account running the Winbatch job. Is there a reliable way of finding the currently logged in user?

Answer:

See Also: http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/nftechsupt.web+WinBatch/How~To/User~Profiles+Get~Logged~In~User~from~Local~System~Account.txt

You might be able to obtain the logged in user from the registry. However, all methods that rely on the registry are unreliable in various situations. It is possible for a user's profile to be held open such that their registry hive is still in memory when they've logged out.

; CurrentInteractiveUser(@True) = Get user and domain
; CurrentInteractiveUser(@False) = Get user only

#DefineFunction CurrentInteractiveUser(IncludeDomain)
User = ""
Domain = ""
Key = RegOpenKey(@REGUSERS,"")
SIDList = RegQueryKeys(Key)
RegCloseKey(Key)
For i = 1 To ItemCount(SIDList,@TAB)
   SID = ItemExtract(i,SIDList,@TAB)
   If RegExistKey(@REGUSERS,StrCat(SID,"_Classes"))
      Key = "%SID%\Software\Microsoft\Windows\CurrentVersion\Explorer[Logon User Name]"
      If RegExistValue(@REGUSERS,Key) Then User = RegQueryValue(@REGUSERS,Key)
   EndIf
Next
If IncludeDomain && User<>""
   Domain = RegQueryValue(@REGMACHINE,"Software\Microsoft\Windows NT\CurrentVersion\Winlogon[DefaultDomainName]")
   User = StrCat(Domain,"\",User)
EndIf
Return(User)
#EndFunction

; Let"s try it
User = CurrentInteractiveUser(@FALSE)
DomainUser = CurrentInteractiveUser(@TRUE)
Message(User,DomainUser)

If I remember correctly, WMI has functionality that can retrieve the desired information reliably.

#DefineFunction udfRemoteUser( computername )
   IntControl(73,2,@TRUE,0,0)
   username = ""
   objLocator = ObjectCreate("WbemScripting.SWbemLocator")
   objService = objLocator.ConnectServer(computername,"root/cimv2","","")
   objSecurity = objService.Security_
   objSecurity.ImpersonationLevel = 3
   ; query instances
   query = "SELECT * FROM Win32_ComputerSystem"
   colInstances = objService.ExecQuery(query)
   ; loop once for each instance
   ForEach objInstance In colinstances
      type = ObjectTypeGet(objInstance)
      If type=="EMPTY" Then Break
      ; obtain properties
      username = objinstance.UserName
   Next
   objSecurity = 0
   objService = 0
   objLocator = 0
   Return username

   :WBERRORHANDLER
   Pause("Error",wberroradditionalinfo)
   Exit
#EndFunction

computername = 'B64' ;'.' for the local computer
un = udfRemoteUser( computername )
Pause('UserName',un)

You can also use the Terminal Server extender to enumerate the connected sessions on a desktop system running WinXP & newer, too. Each session may then be queried to see what user is logged on to the session and whether the session is connected to the physical console on the workstation. If the workstations are Win2K or older, then this method won't work.

Call wtsGetActiveConsoleSessId() first in order to find out what session id # is associated with the console.The actual session id # will vary in some cases, especially if WinXP has F.U.S. [Fast User Switching] enabled. You'll also see the session id # varying on Win2K3 servers when you connect to the console in remote admin mode as opposed to just having remote admin session that wasn't started with the switch that tells it to connect to the console.

On workstation operating systems, there's only one connected session allowed, so if there's multiple simultaneous users logged on in different sessions, all but one of those sessions will be in a disconnected state and the remaining one will be connected.

Alternatively, you can call wtsEnumSessions() to get back an array of session id #s, and then you can iterate thru the array in a loop to process session that currently exists. This would be by far the most reliable method that would work on all variants & versions of Windows that have terminal services built into them in one form or another.

Then, when you do call wtsQuerySessionInfo() for that particular session id #, you can be certain that you've the right session id # to be querying for information. If there's no user logged on to that session, then the array element [14] should be an empty string.

ServerSpec = ''
SessId = wtsGetActiveConsoleSessId()
arrSession = wtsQuerySessionInfo( ServerSpec, SessId )
strLoggedOnUser = arrSession[14]
if strLoggedOnUser == ""
   Message( 'Logged in user for SessionID #':SessId, 'No user logged on' )
else
   Message( 'Logged in user for SessionID #':SessId, strLoggedOnUser )
endif


UDF that attempts all three methods

#DefineFunction udfGetRemoteUser( computername )

   IntControl(73,2,@TRUE,0,0)
   username = ""

   ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   ; WMI
   ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   :TryWMI
   objLocator = ObjectCreate("WbemScripting.SWbemLocator")
   objService = objLocator.ConnectServer(computername,"root/cimv2","","")
   If objService == 0 Then Goto TryReg
   objSecurity = objService.Security_
   objSecurity.ImpersonationLevel = 3
   ; query instances
   query = "SELECT * FROM Win32_ComputerSystem"
   colInstances = objService.ExecQuery(query)
   ; loop once for each instance
   ForEach objInstance In colinstances
      type = ObjectTypeGet(objInstance)
      If type=="EMPTY" Then Break
      ; obtain properties
      username = objinstance.UserName
   Next
   objSecurity = 0
   objService = 0
   objLocator = 0
   If username !="" Then Return username

   ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   ; Registry
   ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   ; assumes remote system is windows vista or newer and is 64-bit
   :TryReg
   Key = RegConnect("\\":computername, @REGMACHINE, "RemoteOS64")
   If key == 0 Then Goto TryWTS
   If RegExistKey(Key,"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI")
      If RegExistValue( Key,"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI[LastLoggedOnUser]")
         username = RegQueryValue(Key,"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI[LastLoggedOnUser]" )
      EndIf
   EndIf
   RegCloseKey(Key)
   ;Replace . with computername
   startpos = StrIndex( username, ".", 1, @FWDSCAN )
   If startpos Then username = StrReplace( username, ".", computername )
   If username!="" Then Return username



   ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   ; Windows Terminal Services Extender
   ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   :TryWTS
   AddExtender( "WWWTS44I.DLL" , 0, "WWWTS64I.DLL" )
   SessId = wtsGetActiveConsoleSessId()
   arrSession = wtsQuerySessionInfo( "\\":computername, SessId )
   username = arrSession[14]
   If username !="" Then Return username

   ;Give up
   Return "*NOTFOUND*"

   :WBERRORHANDLER
   ;Use for debugging
   ;Pause("Error","On line: ": wberrorhandlerline :@CRLF:"Extended Error Info: ": wberroradditionalinfo)
   IntControl(73,2,@TRUE,0,0)
   Return

#EndFunction

computername = 'Abba';'b64'
;computername = ComputernameGet(0); local computername
un = udfGetRemoteUser( computername )
Pause('UserName',un)

Exit

Article ID:   W17033
File Created: 2014:07:18:09:51:38
Last Updated: 2014:07:18:09:51:38