Get logged on users and sessions

There are several ways to get a list of currently logged on users on a system, but only a few return the things that I like to know. In case of my servers, I’d like to know which users are connected to which session.

One way to do so is by:

Import-Module RemoteDesktop

but this doesn’t give a consistent return (on some of my 2012 R2 servers it doesn’t return anything, even though users are logged on to the system and RDS is setup) and it doesn’t include the 0 session user(s)


WMI can also do the job, but by default will give a lot of unnecessary information

Get-WmiObject Win32_LoggedOnUser | Select Antecedent -Unique | %{"{0}\{1}" -f $_.Antecedent.ToString().Split('"')[1],$_.Antecedent.ToString().Split('"')[3]}

(It’ll return DWM-1, DWM-2, DWM-3, IUSR, SYSTEM and more things I don’t need to know or work with) To filter most unwanted items, you’d get a big command like:

Get-WmiObject Win32_LoggedOnUser | Select Antecedent -Unique | Where-Object { $_.Antecedent.ToString().Split('"')[1] -ne $env:COMPUTERNAME -and $_.Antecedent.ToString().Split('"')[1] -ne "Window Manager" -and $_.Antecedent.ToString().Split('"')[3] -notmatch $env:COMPUTERNAME } | %{"{0}\{1}" -f $_.Antecedent.ToString().Split('"')[1],$_.Antecedent.ToString().Split('"')[3]}

This’ll return a list of all users (including administrator), but no sessions:


So until now the first command would be the best; but since it’s pretty inconsistent wether it indeed returns a list of users, I thought of ‘misusing’ another command for this purpose. The Get-process command. Since every logged in user has several processes in their name, this might be the best approach:

Get-Process -IncludeUserName | Select-Object UserName,SessionId | Where-Object { $_.UserName -ne $null } | Sort-Object UserName -Unique

This will return a list of all users, but users that are connected to multiple sessions, will only show in one this way. To get the list of users based on the session and filter out the accounts like DWM-1 to 3 etc, the following command  The Where-Object { $_.UserName -ne $null } part will make sure the UserName field is filled when walking through it, otherwise you’d get lots of errors on not being able to call a method on a mull-valued expression. Thus to rule these out, this part is added.

Get-Process -IncludeUserName | Select-Object UserName,SessionId | Where-Object { $_.UserName -ne $null -and $_.UserName.StartsWith("DOMAIN OR COMPUTERNAME") } | Sort-Object SessionId -Unique

This will return an object with UserName and SessionID for that user. Once multiple users are connected to the same session (like session 0), the filter for the domain name or computer name is needed to get the list of names you’d be interested in. Here is a screenshot of the result of the last command:


The IncludeUserName switch has been added since Powershell 4.0, thus older versions will not be able to use this switch. Also the switch requires this command to be ran elevated; otherwise you’d get an error.

In the end I will definitely use the Get-Process command to get a consistent list of logged on users on my servers.

Edit: By the way, if you’re about to run this on a remote computer, wrap an Invoke-Command around it. Because if you include the -ComputerName switch, the -IncludeUserName switch can’t be combined. Next to that, the Get-Process command with -ComputerName will return all processes as running on session 0.

Thus if you are to use it on a remote computer, use a command like:

Invoke-Command -ComputerName "COMPUTERNAME" -ScriptBlock { Get-Process -IncludeUserName | Select-Object UserName,SessionId | Where-Object { $_.UserName -ne $null -and $_.UserName.StartsWith("DOMAIN OR COMPUTERNAME") } | Sort-Object SessionId -Unique } | Select-Object UserName,SessionId

Note that in the end there’s an extra Select-Object, because the Invoke-Command will add 2 extra properties to the result; PSComputerName and RunspaceId. You can also add credentials to this command and other parameters, depending on your needs.



3 thoughts on “Get logged on users and sessions

  1. I did not like the domain name or machine name part as this give the need for changing the code for your environment. Any user that has a console or some form of RDP connection either being a full desktop or just a launched remote app has either explorer or rdpshell as one of the processes. All other accounts don’t.
    Get-Process -IncludeUserName | Where-Object { $_.UserName -ne $null -and ($_.ProcessName -eq ‘explorer’ -or $_.ProcessName -eq ‘rdpshell’)} | Select-Object UserName,SessionId | Sort-Object SessionId -Unique


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s