Search Tools Links Login

List RDP Sessions on Remote Servers in PowerShell


You can use this handy little script to find remote desktop sessions on all servers running in your Active Directory domain.

It's a fact of life as a sysadmin.  You RDP to a machine, leave a task running, and disconnect. Invariably, you forget that session, and it sits their disconnected. Being a good admin, there is a password policy that requires you to change your password every 90 days.  The time comes, and you change your password, as required.

Bam. Your account is locked out. Now you get to go find all those abandoned sessions, running under your old credentials.  Good times.  Wouldn't it be handy if you could simply run a script to find all your dead sessions?

We've all used the query session command to get a list of sessions on a remote server, then use the logoff command to remotely log off any dead sessions.  If you haven't you can read up on it here: Killing Disconnected Terminal Server Sessions from the Command Line.

The general flow of the script is thus:

I've pasted the script below, and I hope someone gets some use out of this. As always, if you have any questions, comments, or concerns regarding this, drop a note in the comments, or start a thread in the forums. It'd be super cool if someone could improve upon this!

#
# import the active directory module
#

import-module activedirectory

#
# set some variables
#

$Today=Get-Date
$SessionList="`n`nRDP Session List - " + $Today + "`n`n"
$CurrentSN=0

#
# Get a list of servers from Active Directory. Note that two different strings have been
# given. The first one will get all servers in Active Directory, while the second one
# (which is commented) will target all hosts in a particular OU.  The third option is
# for grabbing a list of machines (one per line) from a file.
#

write-progress -activity "Getting list of servers from Active Directory" -status "... please wait ..."

$Servers=get-adcomputer -filter {OperatingSystem -like "*server*"}
# $Servers=Get-adcomputer -filter * -searchbase "OU=servers,dc=dwlab02,dc=local"
# $Servers=Get-Content "c:\files\myfile.txt"

$NumberOfServers=$Servers.Count

#
# Iterate through the retrieved list to check RDP sessions on each machine
#

ForEach ($Server in $Servers) {

    $ServerName=$Server.Name
    Write-progress -activity "Checking RDP Sessions" -status "Querying $ServerName" -percentcomplete (($CurrentSN/$NumberOfServers)*100)

    #
    # Run qwinsta and grab the output
    #

    try
    {
        $queryResults = (qwinsta /server:$ServerName | foreach { (($_.trim() -replace "\s+",","))} | convertfrom-csv)

        #
        # get session info from the instance
        #

        ForEach($QueryResult in $QueryResults) {
            
            $RDPUser=$QueryResult.USERNAME
            $SessionType=$QueryResult.SESSIONNAME
            $SessionID=$QueryResult.ID
            $ReturnedCurrentState=$QueryResult.State

            If($ReturnedCurrentState -eq $null){ $CurrentState="Disconnected" } Else { $CurrentState="Active" }
            
            #
            # filter out the chaff
            #

            If (($RDPUser -ne $NULL) -and ($SessionType -ne "console") -and ($SessionType -ne "services") -and ($SessionType -ne "rdp-tcp") -and ($RDPUser -ne "65536")) {
                $SessionList=$SessionList + "`n" + $ServerName + " logged in by " + $RDPUser + " on " + $SessionType + ", session id $SessionID $CurrentState"
            }
        }

    }
    catch
    {
        $SessionList=$SessionList + "`n Unable to query " + $ServerName
        write-host "Unable to query $ServerName!" -foregroundcolor Red
    }
    
    $CurrentSN++
}


# Send the output the screen.


$SessionList + "`n`n"

About this post

Posted: 2016-02-17
By: dwirch
Viewed: 23,552 times

Categories

Scripting

Powershell

Windows

PowerShell Code Cache

Windows Server

Attachments

No attachments for this post


Loading Comments ...

Comments

dwirch posted this comment on 2016-04-27:

Watch out for line wrap in the script above!!

AnonymousCoward posted this comment on 2017-10-05:

Hello.

In order to get the try catch to work i needed to add ErrorAction

       $queryResults = (qwinsta /server:$ServerName | foreach { (($_.trim() -replace "\s+",","))} | convertfrom-csv -ErrorAction Stop)

Also is using computers from a txt file remove the .name

         $ServerName=$Server

AnonymousCoward posted this comment on 2018-04-30:

I notice when running this with PowerShell ISE (as administrator) on Windows Server 2012 R2, and calling the server list via a CSV import like so: 

$Servers = Import-CSV “Drive:\Filepatch\File_Name.csv”

That it runs without error, but then writes output that doesn't identify which machine the session is logged onto, making the output fairly useless to me. As an example, the output is a long series of items like this: 

 logged in by 2247 on username_redacted, session id Disc Disconnected
 logged in by username_redacted on rdp-tcp#16, session id 2249 Active
 logged in by username_redacted on >rdp-tcp#19, session id 2250 Active
 logged in by username_redacted on rdp-tcp#135, session id 2251 Active
 logged in by 2252 on username_redacted, session id Disc Disconnected

If you notice, it seems that the output variables are showing up in weird order for some lines. Notice the first line of the output shows "logged in by 2247" (which appears to be the session ID), "on username_redacted", while the second line shows "logged in by username_redacted", "on rdp-tcp#16, session ID 2249". 

I could ignore that part as long as I could get an idea of which servers had sessions on them, but the output doesn't mention the servername at all.

As a relative newb to all of this, I don't have much confidence in being able to spot the cause on my own, but looking at this part: 

ForEach($QueryResult in $QueryResults) {

            $RDPUser=$QueryResult.USERNAME
            $SessionType=$QueryResult.SESSIONNAME
            $SessionID=$QueryResult.ID
            $ReturnedCurrentState=$QueryResult.State

I see username, sessionname, result ID, and result state, but I don't see a server name variable there. 

Any help at all would be appreciated. 

dwirch posted this comment on 2018-05-01:

$ServerName holds the name of the server, but I am not sure why your CSV is not working.  Maybe there are multiple values in there? Have you tried using just a straight text file, with one machine name per line?

AnonymousCoward posted this comment on 2019-11-29:

yes

AnonymousCoward posted this comment on 2020-07-25:

Hello, I have the same problem with the username sometimes ending up on the wrong place. It seems to have something to do with Disconnected sessions.

When you enter this command manually; qwinsta /server:$ServerName the first column is sometimes empty, the scripts doesn't take that into account.

I have changed a few lines to fix this:

#Before the Foreach

$queryResults =  (qwinsta /server:$ServerName) | Select-Object -Skip 1

#In the Foreach

 $RDPUser=$($QueryResult.substring(19,22)).trim()
 $SessionType=$($QueryResult.substring(1,18)).trim()
 $SessionID=$($QueryResult.substring(41,5)).trim()
 $ReturnedCurrentState=$($QueryResult.substring(48,8)).trim()

I also change this If statement else it doesn't work anymore:

 If($ReturnedCurrentState -eq "Active"){ $CurrentState="Active" } Else { $CurrentState="Disconnected" }

And in this if statement there seems to be a typo:
If (($RDPUser -ne $NULL) -and ($SessionType -ne "console") -and ($SessionType -ne "services") -and ($SessionType -ne "rdp=tcp")

Changed this section "($SessionType -ne "rdp=tcp")" to  ($SessionType -ne "rdp-tcp")

I hope this helps anybody.

dwirch posted this comment on 2020-07-25:

Thanks for your contribution. I've fixed the typo that you mentioned. Good catch!

You must be logged in to make a comment.