Sign in to follow this  
Followers 0
PhyrePhoX

Find out currently logged on user on remote machine

20 posts in this topic

Hello folks,

atm i am writing a script to help administrating pc in my office. though i found out a lot of stuff myself, there still is one function i dont know how to turn into code:

Finding out who (domain\account) is currently logged in on a remote machine. Sometimes we need this feature to find out who is using a machine without physically going there and taking a look.

i HAVE a way of finding out, but it is VERY ugly & slow. Right now i doscall "tasklist /v /s Computername /u Computername/Adminaccount /p PASSWORD"

The output takes a while to produce, i then look for the "explorer.exe" task and parse it's user - thats the username of the currently logged in user.

there has GOT to be a better and quicker way? normally i manage to find a lot of stuff on google, but seems all the search strings & combinations i used led me to "wrong forum topics" and stuff.

hope my question comes across the right way.

regards, PhoX

Share this post


Link to post
Share on other sites



How about trying Sysinternals PsLoggedOn and parsing the output? Just a thought....

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

i know its not exactly ideal and there is probably a way using proper script, but microsoft have taken ownership of pstools. one of the tools is psloggedon.exe which can show what you need.

so something like:

RunWait(@ComSpec & " /c " & "psloggedon" & "\\" & $pcname, "", @SW_HIDE)

not sure if its the correct syntax but the exe should be able to give you the correct syntax.

**edit** what giltree said :whistle:

Edited by darkleton

Share this post


Link to post
Share on other sites

@PhyrePhoX / darkleton

Why don't you stay native and avoid using external tools.

Const $HKEY_LOCAL_MACHINE = 0x80000002

Dim $strKeyPath, $strValueName, $strValue

$strComputer = "10.0.0.3"
 
$objRegistry=ObjGet("winmgmts:\\" & $strComputer & "\root\default:StdRegProv")
 
$strKeyPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon"

$strValueName = "DefaultUserName"
$objRegistry.GetStringValue ($HKEY_LOCAL_MACHINE, $strKeyPath, $strValueName, $strValue)

Consolewrite ($strValue &@CR)

$strValueName = "DefaultDomainName"
$objRegistry.GetStringValue ($HKEY_LOCAL_MACHINE, $strKeyPath, $strValueName, $strValue)

Consolewrite ($strValue &@CR)

Enjoy !!

ptrex

Share this post


Link to post
Share on other sites

as i said there's probably a scripting way. but i've only been looking at autoit for about 5 days now, so don't know all of its capabilities yet.

i'll bear it in mind though, thanks :whistle:

Share this post


Link to post
Share on other sites

my 2ct.: doesn't seem like there's a predefined way in AutoIt to ask for logged-on user on a remote machine, but there is a macro for finding out who is logged on locally. This is @UserName.

If you put some effort into this, you might want to do what I did for a very application-specific system that I have on my network and saves me a whole lot of time (so my exact tool is no use to you but it was nice practise in scripting TCP comm and network-related scripting): create a monitoring system with a server-side version and workstation-side version, where the ws-side acts as a TCP-server on a specific port, and the server-side connects to all workstations in a certain IP-range on that port when you run it, and reads out certain information that is presented by the workstation-version. For instance the @UserName as read by the ws-side.

(You can ofcourse give as much information as you want from the ws-side to the server-side. I myself use it to report the file dates of certain security patches and AV-updates from the ws-version to the server-version, and the server version compares them to it's own file dates, and if they differ I get a nice popup in my server console.)

The nice thing about this system is that you don't need to do anything difficult to access remote registries, you don't even need to be logged on as admin on the server, you can exchange a lot of information, make your own alert system (my little network script here for instance also alarms me when the ws-side has less than 500MB harddisk space), suggest actions based on certain information, etc.. There are some tools freely available that let you monitor this kind of thing, but none of them catered my exact needs and coding this was only a few hours of work.

Be sure to make sure any firewall allows the incoming port connection on the workstations though :-) (I troubleshooted my script for HOURS back then before I found out that I forgot to make a domain policy for the Windows XP sp2 Firewall to open my port-of-choice everywhere! Did learn a whole lot about TCP though! heheh)

P.S. Sorry for the long post; hope you didn't fall asleep reading it :whistle:


Roses are FF0000, violets are 0000FF... All my base are belong to you.

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Wow people, you're fast! Posted this before lunch and now i already got several working solutions, thanks a bunch!

@PhyrePhoX / darkleton

Why don't you stay native and avoid using external tools.

Yes, i want to avoid using external tools, external as in "not preinstalled in XP". but your approach is much better, thanks, already tested it (although it throws an error when there is a local user logged in on the remote pc - the registry values are not filled then - there must be preinstalled tool that covers that too?).

Since you guys solved my problem so easily, you maybe also have some ideas regarding another problem:

In order to resolve the account into a full name (surname and given name) and department, a colleague of mine wrote a vb script which i also could not convert into actual autoit code. instead i take the vbscript code, alter it (the variables), write it to a file and dosrun the script via cscript and parse the output - everytime i need the builtin function.

Set wshnetwork = CreateObject("WScript.Network")
DomainName = "DOMAIN"
UserName = "USERNAME"

Set user = GetObject("WinNT://" & DomainName & "/" & username & ",user")
wscript.echo "FullName: " & user.FullName
wscript.echo "Description: " & user.Description

i know this is extremely dumb, and only adds up to my 400 lines of spaghetti code - but it works. there's gotta be some other way though, aint it?

thanks in advance, PhoX

Edited by PhyrePhoX

Share this post


Link to post
Share on other sites

hm, can't edit my post anymore. ptrex, seems your script only is of use in case it is run by a domainadmin (or an account which is admin on both the local and the remote machine). since in our environment the admin accounts are local only i need a way of telling your script to run as another user, including password etc. do you think this is possible?

Share this post


Link to post
Share on other sites

i don't think this is 100% correct, but it might be a bit closer than having to use VB script :

$wshnetwork = ObjCreate("WScript.Network")
$DomainName = "DOMAIN"
$UserName = "USERNAME"

 $user = ObjGet("WinNT://" & $DomainName & "/" & $UserName & ",user")
_WriteLog ("FullName: " & $user.FullName)
_WriteLog ("Description: " & $user.Description)

Something like that?

Share this post


Link to post
Share on other sites

i don't think this is 100% correct, but it might be a bit closer than having to use VB script :

...

Something like that?

exactly like that. muchas gracias!

Share this post


Link to post
Share on other sites

have a look for the VB to AU3 converter script somewhere on the forum. It's helped me out a lot.

Even if it doesn't convert it 100% correct it gives you an idea of how it should be laid out. A definite must if you are used to using VB a lot

Share this post


Link to post
Share on other sites

Can't you use the DOS commands of %username% and %userdomain% in the script to get this?

Share this post


Link to post
Share on other sites

have a look for the VB to AU3 converter script somewhere on the forum. It's helped me out a lot.

Even if it doesn't convert it 100% correct it gives you an idea of how it should be laid out. A definite must if you are used to using VB a lot

oh, i didnt know something like this exists, thanks.

Can't you use the DOS commands of %username% and %userdomain% in the script to get this?

well, these commands only return the local user, not the one logged in on the remote machine :whistle: (if i understood this correctly)

Share this post


Link to post
Share on other sites

If you run the script on the remote machine it should give you their details. Something like this:

runwait("cmd /c echo %username% > c:\user.txt", "", @SW_HIDE)
runwait("cmd /c echo %userdomain% > c:\domain.txt", "", @SW_HIDE)

$userfile = "c:\user.txt"
$domainfile = "c:\domain.txt"

$openuser = FileOpen($userfile,0)
$opendomain = FileOpen($domainfile,0)

$userline = FileRead($openuser)
$domainline = FileRead($opendomain)

MsgBox (0, "Logged in user details", "Domain = " & $domainline & " Username = " & $userline)

Share this post


Link to post
Share on other sites

well, that could be a solution, if there was an easy way of actually running these commands on remote machines. therein lies the whole problem.

Share this post


Link to post
Share on other sites

#16 ·  Posted (edited)

hm, can't edit my post anymore. ptrex, seems your script only is of use in case it is run by a domainadmin (or an account which is admin on both the local and the remote machine). since in our environment the admin accounts are local only i need a way of telling your script to run as another user, including password etc. do you think this is possible?

found a way to run the script - i just have to mount the administrative share of the remote computer in order to have the right to execute the "get values from registry" program. so the only problem remaining is to find out if (&who) a local user is logged on.

$strComputer = "Machine"
$adminpw = "Password"
DriveMapAdd("", "\\" & $strComputer & "\c$", 0, $text & "\administrator" & $adminpw)
Const $HKEY_LOCAL_MACHINE = 0x80000002

Dim $strKeyPath, $strValueName, $strValue
 
$objRegistry=ObjGet("winmgmts:\\" & $strComputer & "\root\default:StdRegProv")
 
$strKeyPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon"

$strValueName = "DefaultUserName"
$objRegistry.GetStringValue ($HKEY_LOCAL_MACHINE, $strKeyPath, $strValueName, $strValue)

MsgBox(1,"",$strValue &@CR)

$strValueName = "DefaultDomainName"
$objRegistry.GetStringValue ($HKEY_LOCAL_MACHINE, $strKeyPath, $strValueName, $strValue)

MsgBox(1,"",$strValue &@CR)

hm, i managed to write autotit instead of autoit twice in this post, only realized that because i remembered to delete our adminpw and thus searched the code again. hm, seems i'm a freak :whistle:

2nd Edit: haha, i had my source wrong, it still doesnt work on remote pcs :P

Edited by PhyrePhoX

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

@ PhyrePhoX

Func _GetUserName($strClient)
Local $objWMIService, $objItem, $colItems,  $strUser, $strDomain,  $Result
    $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\"  & $strClient)
    $colItems = $objWMIService.InstancesOf("Win32_Process")
        If IsObj($colItems) Then
            For $objItem In $colItems
                If ($objItem.Caption = "explorer.exe") Then
                    $Result = $objItem.GetOwner($strUser, $strDomain)
                        If (Not @error) And ($Result = 0) Then Return $strUser
                EndIf
            Next
        EndIf
Return ""
EndFunc

Enjoy

Vic Fontaine

Edited by VicFontaine

Share this post


Link to post
Share on other sites

@ PhyrePhoX

Func _GetUserName($strClient)
Local $objWMIService, $objItem, $colItems,  $strUser, $strDomain,  $Result
    $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\"  & $strClient)
    $colItems = $objWMIService.InstancesOf("Win32_Process")
        If IsObj($colItems) Then
            For $objItem In $colItems
                If ($objItem.Caption = "explorer.exe") Then
                    $Result = $objItem.GetOwner($strUser, $strDomain)
                        If (Not @error) And ($Result = 0) Then Return $strUser
                EndIf
            Next
        EndIf
Return ""
EndFunc

Enjoy

Vic Fontaine

thanks for the reply, but how do i "impersonate" another account?

the situation is as follows: on my workstation i am logged in as a regular domain user with no special privileges. in order to read out the process list of the "target pc" i have to use the (on the target pc) local administrator account. how do i set these credentials?

many thanks in advance!

Share this post


Link to post
Share on other sites

#19 ·  Posted (edited)

;- This function returns the user who is logged in on a remote machine, provided you know the proper admin credentials of the remote machine. 
; This assumes you either have ONE domain or local accounts (can be changed easily).
; In our environment we (the admins) only have LOCAL adminrights, our useraccounts are no domainadminaccounts. 
; you can rewrite this script so that you can use domainadminaccounts whatever.
; one problem remains: execution of the script does take a while (as in a few seconds). tested on win2k and winxp (both local and remote)
; no extratools needed, tasklist is already preinstalled in windows
; p.s: i know this code is ugly as hell, but it works ;)

#include <String.au3>
Func _GetUserName($hostname,$admaccount,$adminpw,$domain)
Local $process = Run("tasklist /v /fo list /fi ""IMAGENAME eq explorer.exe"" " & "/s "& $hostname & " /u " & $hostname & "\" & $admaccount & " /p " & $adminpw, "", @SW_HIDE, 2)
Local $_buffer = ''
Local $Result
Local $exploreruser

Do
    $_buffer &= StdoutRead($process)
Until @error

If StringReplace($_buffer, 'explorer.exe', '') <> $_buffer Then
    If StringReplace($_buffer, $domain & '\', '') <> $_buffer Then
        ;Show Domainuser
        $exploreruser = _StringBetween($_buffer,$domain & "\",@CRLF) 
        Return $exploreruser[0]& " (Domain account!)"
    Else
        ;No domainuser, show local logged in account
        $exploreruser = _StringBetween($_buffer,$hostname&"\",@CRLF)
        Return $exploreruser[0] & " (Local account!)"
    EndIf
Else
    Return "no user logged in locally (or no windows OS :D)"
EndIf
EndFunc

;Example usage
;~ $hostname = "machine1"
;~ $admaccount = "administrator"
;~ $adminpw = "foo"
;~ $domain = "domain"
;~ MsgBox(1,"Currently logged in user on " & $hostname & " is:",_GetUserName($hostname,$admaccount,$adminpw,$domain))

though it is ugly and i still have to parse cmd, it suits my needs. this script is working, take it :whistle:

Edited by PhyrePhoX

Share this post


Link to post
Share on other sites

this is more a function that shows the primary user of a machine not whose logged on... bc if no one is logged on it still reports the same name...

@PhyrePhoX / darkleton

Why don't you stay native and avoid using external tools.

Const $HKEY_LOCAL_MACHINE = 0x80000002

Dim $strKeyPath, $strValueName, $strValue

$strComputer = "10.0.0.3"
 
$objRegistry=ObjGet("winmgmts:\\" & $strComputer & "\root\default:StdRegProv")
 
$strKeyPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon"

$strValueName = "DefaultUserName"
$objRegistry.GetStringValue ($HKEY_LOCAL_MACHINE, $strKeyPath, $strValueName, $strValue)

Consolewrite ($strValue &@CR)

$strValueName = "DefaultDomainName"
$objRegistry.GetStringValue ($HKEY_LOCAL_MACHINE, $strKeyPath, $strValueName, $strValue)

Consolewrite ($strValue &@CR)

Enjoy !!

ptrex

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0