Quick-Hits: Find currently logged on users

I was recently tasked with locating all servers on our network and query for users that were currently logged onto each server, either through a terminal session or logged on via console session.  This got me thinking of what ways are available to make this happen.  When it was all said and done, I came up with 4 ways to do this.

The first method is to use the Win32_ComputerSystem and grab the UserName property. The thing that you keep in mind with is that this will only return the user that is logged on using a console session, meaning that they are locally logged onto the machine, not logged on via remote desktop.

Untitled

The second method involves another WMI query that will work for both console sessions and remote sessions.  This query looks at the Win32_Process class and then performs a query to look for all of the explore.exe process, which is the user shell for each user that is logged into the server.  Using this query, you can perform a wmi search and then create a custom object to hold the data. I used an advanced function I wrote to perform the query. This gets the job done and shows you who is logged into the machine, but it doesn’t really give you a lot of information to work with.

Untitled

Function Get-WMIComputerSessions {
<#
.SYNOPSIS
    Retrieves tall user sessions from local or remote server/s
.DESCRIPTION
    Retrieves tall user sessions from local or remote server/s
.PARAMETER computer
    Name of computer/s to run session query against.
.NOTES
    Name: Get-WmiComputerSessions
    Author: Boe Prox
    DateCreated: 01Nov2010

.LINK
    https://boeprox.wordpress.org
.EXAMPLE
Get-WmiComputerSessions -computer "server1"

Description
-----------
This command will query all current user sessions on 'server1'.

#>
[cmdletbinding(
	DefaultParameterSetName = 'session',
	ConfirmImpact = 'low'
)]
    Param(
        [Parameter(
            Mandatory = $True,
            Position = 0,
            ValueFromPipeline = $True)]
            [string[]]$computer
    )
Begin {
    #Create empty report
    $report = @()
    }
Process {
    #Iterate through collection of computers
    ForEach ($c in $computer) {
        #Get explorer.exe processes
        $proc = gwmi win32_process -computer $c -Filter "Name = 'explorer.exe'"
        #Go through collection of processes
        ForEach ($p in $proc) {
            $temp = "" | Select Computer, Domain, User
            $temp.computer = $c
            $temp.user = ($p.GetOwner()).User
            $temp.domain = ($p.GetOwner()).Domain
            $report += $temp
          }
        }
    }
End {
    $report
    }
}

The third method is made using the query sessions command line, which is available in Vista and above OS’s and on systems running Terminal Servers. Just using this command line will return a string value which does list out a nice amount of information sessiontype, username, active state of the session, etc…:

query session /server:"boe-laptop"

Untitled

This is nice and all, but I would rather return an object that I can sort or export into a csv or something else. So with that I went and created this advanced function to parse the data and make into a more usable object:

Function Get-ComputerSessions {
<#
.SYNOPSIS
    Retrieves tall user sessions from local or remote server/s
.DESCRIPTION
    Retrieves tall user sessions from local or remote server/s
.PARAMETER computer
    Name of computer/s to run session query against.
.NOTES
    Name: Get-ComputerSessions
    Author: Boe Prox
    DateCreated: 01Nov2010

.LINK
    https://boeprox.wordpress.org
.EXAMPLE
Get-ComputerSessions -computer "server1"

Description
-----------
This command will query all current user sessions on 'server1'.

#>
[cmdletbinding(
	DefaultParameterSetName = 'session',
	ConfirmImpact = 'low'
)]
    Param(
        [Parameter(
            Mandatory = $True,
            Position = 0,
            ValueFromPipeline = $True)]
            [string[]]$computer
            )
Begin {
    $report = @()
    }
Process {
    ForEach($c in $computer) {
        # Parse 'query session' and store in $sessions:
        $sessions = query session /server:$c
            1..($sessions.count -1) | % {
                $temp = "" | Select Computer,SessionName, Username, Id, State, Type, Device
                $temp.Computer = $c
                $temp.SessionName = $sessions[$_].Substring(1,18).Trim()
                $temp.Username = $sessions[$_].Substring(19,20).Trim()
                $temp.Id = $sessions[$_].Substring(39,9).Trim()
                $temp.State = $sessions[$_].Substring(48,8).Trim()
                $temp.Type = $sessions[$_].Substring(56,12).Trim()
                $temp.Device = $sessions[$_].Substring(68).Trim()
                $report += $temp
            }
        }
    }
End {
    $report
    }
}

So now when I run this, I have my custom object that can be ran on multiple machines and list out much more information than my previous function.

Untitled

The fourth and final way that I found to do this was using a freely available Terminal Services module, built by Shay Levi to query for user sessions. As you can see from the output, it works rather nicely.

Import-Module PSTerminalServices
Get-TSSession -ComputerName "dc1"

Untitled

As you can see, there are a variety of ways to gather information on user sessions on local and remote machines.  Some are very basic, but will work from any workstation/server, while others contain more information, but may only be available on certain systems.

This entry was posted in powershell, scripts and tagged , , , . Bookmark the permalink.

28 Responses to Quick-Hits: Find currently logged on users

  1. Definitely imagine that which you said. Your favorite justification seemed to be
    at the internet the easiest thing to take note of. I say to you, I definitely get irked while other people consider concerns that they plainly don’t
    realize about. You controlled to hit the nail upon the highest as well as defined out the whole thing with no need side effect ,
    other folks could take a signal. Will likely be again to get more.
    Thank you

  2. Denial Parl says:

    Simply excellent !
    Though a similar article which I would like to add here and might interested for others – https://community.spiceworks.com/how_to/130398-how-to-track-user-logon-session-using-event-log

  3. Pingback: List users logged on to your machines » PowerShell.org

  4. sciteqmh says:

    Hi,

    Nice post, had to edit the WMI script to ask for creds, as I have systems that I cant get onto.

    $creds = $host.ui.PromptForCredential(“Need credentials for $c”, “Please enter your user name and password.”, “”, “”)
    $proc = gwmi win32_process -computer $c -Filter “Name = ‘explorer.exe'” -Credential $creds

  5. Sananda sen says:

    i need a power shell script to display idle time sessions in terminal servers and to logoff idle sessions for more than 5hrs.plese help me

  6. Ben says:

    Any easy way to get the full name rather than just the user name?

    • Boe Prox says:

      You could probably use [adsisearcher] (if you wanted to avoid using a dependency such as the ActiveDirectory module) to search for the account and then pull the full name from the results of the search.

      ([adsisearcher]”samaccountname=$user”).FindOne()

  7. Ganesh says:

    Hi..
    when I am running the script under third method, I am getting below error… Please help
    The term ‘query’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spel
    ing of the name, or if a path was included, verify that the path is correct and try again.
    At line:38 char:26
    + $sessions = query <<<< session /server:$c
    + CategoryInfo : ObjectNotFound: (query:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    Cannot index into a null array.
    At line:42 char:47
    + $temp.SessionName = $sessions[ <<<< $_].Substring(1,18).Trim()
    + CategoryInfo : InvalidOperation: (1:Int32) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

    Cannot index into a null array.
    At line:43 char:44
    + $temp.Username = $sessions[ <<<< $_].Substring(19,20).Trim()
    + CategoryInfo : InvalidOperation: (1:Int32) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

    Cannot index into a null array.
    At line:44 char:38
    + $temp.Id = $sessions[ <<<< $_].Substring(39,9).Trim()
    + CategoryInfo : InvalidOperation: (1:Int32) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

    Thanks
    Ganesh

  8. sandeep says:

    Hi Boe – I am trying to find get IDLE TIME by modifying your script as below, but i don’t get values as I get just by simply using quser, can you help me here.

    [Parameter(
    Mandatory = $True,
    Position = 0,
    ValueFromPipeline = $True)]
    [string[]]$computer
    )
    Begin {
    $report = @()
    }
    Process {
    ForEach($c in $computer) {
    # Parse ‘query session’ and store in $sessions:
    $sessions = query session /server:$c | Select-Object -Skip 1
    1..($sessions.count -1) | % {
    $temp = “” | Select Computer,SessionName, Username, Id, State, Type, IDLE_TIME
    $temp.Computer = $c
    $temp.SessionName = $sessions[$_].Substring(1,18).Trim()
    $temp.Username = $sessions[$_].Substring(19,20).Trim()
    $temp.Id = $sessions[$_].Substring(39,9).Trim()
    $temp.State = $sessions[$_].Substring(48,8).Trim()
    $temp.Type = $sessions[$_].Substring(56,12).Trim()
    $temp.IDLE_TIME=$sessions[$_].Substring(75).Trim()
    $report += $temp
    }
    }
    }
    End {
    $report
    }
    }

  9. Pingback: Quick-Hits: Find currently logged on users | Learn Powershell | Achieve More | Soyka's Blog

  10. Pingback: Get a list of machine names and logged on or active user(s) « prgmr.io

  11. Pingback: Get a list of machine names and logged on or active user(s) | prgmr.io

  12. pamkkkkk says:

    Hi Boe!

    You can use the WMI classes Win32_LogonSession and the associated Win32_LoggedOnUser to query logged on users! This gives more Informations.
    I have developed a full blown function for that.
    See: http://poshcode.org/4304
    unfortunately I did not found a use case for the session IDs 😦
    If you use Quser.exe (or Query User) you get back a session ID, which you can use with LogOff.exe to log off a specific user. With that I have extended ArPosh
    http://blog.richprescott.com/2011/07/arposh-client-system-administration.html

  13. Pingback: Get a list of machine names and logged in user(s) | use-powershell

  14. Ricky says:

    Yours, combined with
    http://www.peetersonline.nl/index.php/powershell/oneliner-get-logged-on-users-with-powershell/
    and
    http://forums.techarena.in/software-development/1118294.htm

    function get-loggedonusers
    {
    param([Array]$Computer)
    $computers = get-wmiobject Win32_Computersystem -computername $Computer
    $report = @()
    foreach ($c in $computers) {
    $temp = “” | Select Computer, Username
    $temp.Computer = $c.name
    $temp.Username = $c.username
    $report += $temp
    }#foreach
    $report
    }#function

    Dump anything else from http://msdn.microsoft.com/en-us/library/windows/desktop/aa394102(v=vs.85).aspx in there if needed.

    Thanks for your method.

  15. djottings says:

    Thanks for your post. This is just what I want, but one quick question: what does the “” in line 43 of the second script do?
    Thanks

    • Boe Prox says:

      Thanks! Glad you like the post! The “” in the $temp = “” | Select Computer,SessionName, Username, Id, State, Type, Device is just creating an empty collection for me to use later on in the script. If you look at the contents of $temp after creating the collection, it will appear as:

      180)C:\Users\Boe\Downloads>$temp = “” | Select Computer,SessionName, Username, Id, State, Type, Device
      181)C:\Users\Boe\Downloads>$temp

      Computer :
      SessionName :
      Username :
      Id :
      State :
      Type :
      Device :

      Hope this helps…

  16. One more option with using your Get-WMIComputerSessions is to determine how long the explorer.exe process has been active for each user, which tells you how long the session has been active. Another process I typically check for when querying sessions is logon.scr, which tells me whether the session is actively being used or not, and if not, how long the user has been idle.

  17. patrickhoban says:

    I do not get anything when I run your Get-ComputerSessions against any of my servers. Any thoughts?

    • Boe Prox says:

      What OS are you running? From a command prompt, do you get anything when you type query and hit enter? If running an XP machine, most likely you will not be able to use this function as query.exe is a required piece of the function.

      Boe

  18. Pingback: Episode 131 – MVP Sean Kearney on the Mic « PowerScripting Podcast

  19. Pingback: Tweets that mention Quick-Hit: Find currently logged on users | Learn Powershell | Achieve More -- Topsy.com

Leave a comment