Disconnect sessions from servers (cmd/Posh)

  • Mission: disconnect stale sessions from servers with the aid of a script

  • Symptoms
    • User connected to remote desktop and did not logoff after finish the job
    • Session stays connected and consuming/wasting ressources
    • For some servers you have multiple stale connected sessions and the ressources being wasted are considerably important

  • Prerequisites
    • Have Active Directory module installed
    • Run the script with a credential with admin privileges to the target servers

Single server

From an elevated powershell run the following to query the connected session

qwinsta /server:[Server_Name]

You should have a result like this

Take note of the session number you want to disconnect.

You can see different states for the connections. When a state is tagged as Active probably there is someone connected and working on the server. If the state is being displayed as Disc the person connected to the server probably forgot to logoff and have clicked on close from the RDP header.

In this case you can run rwinsta which will force logoff for this Disc session

rwinsta /server:[Server_Name] [Session_Number]

For instance, if we want to disconnect the session ID 26 displayed on the image above

rwinsta /server:[Server_Name] 26

Multiple Servers

With the help of a powershell script you can easily force a logoff for Disc sessions

Firstly create a variable containing all the servers you wish to have the sessions disconnected. In the example I’ll get all computer objects on Active Directory that have Servers on its descriptions. But you can use a Get-Content and have a text file containing all the servers you want in it.

$Servers = Get-ADComputer -Filter * -Properties OperatingSystem | ? { $_.OperatingSystem -match "Server" } | Select -ExpandProperty Name

Then, inside a ForEach, the following commands will query the sessions, validate their states and disconnect those tagged with Disc

ForEach ($Server in $Servers) {
# Query for RDP sessions on the server
$c = qwinsta /server:$Server | where {$_.gettype().equals([string])}
# Convert qwinsta results on powershell readable data
$starters = New-Object psobject -Property @{"SessionName" = 0; "Username" = 0; "ID" = 0; "State" = 0; "Type" = 0; "Device" = 0;};
foreach($line in $c) {
        if($line.trim().substring(0, $line.trim().indexof(" ")) -eq "SESSIONNAME") {
            $starters.Username = $line.indexof("USERNAME");
            $starters.ID = $line.indexof("ID");
            $starters.State = $line.indexof("STATE");
            $starters.Type = $line.indexof("TYPE");
            $starters.Device = $line.indexof("DEVICE");
            continue;
            }
    $o = New-Object psobject -Property @{
            "ServerName" = $Server
            ;"SessionNAme" = $line.trim().substring(0, $line.trim().indexof(" ")).trim(">")
            ;"Username" = $line.Substring($starters.Username, $line.IndexOf(" ", $starters.Username) - $starters.Username)
            ;"ID" = $line.Substring($line.IndexOf(" ", $starters.Username), $starters.ID - $line.IndexOf(" ", $starters.Username) + 2).trim()
            ;"State" = $line.Substring($starters.State, $line.IndexOf(" ", $starters.State)-$starters.State).trim()
            ;"Type" = $line.Substring($starters.Type, $starters.Device - $starters.Type).trim()
            ;"Device" = $line.Substring($starters.Device).trim()
            }
# Disconnect all sessions tagged as Disc
    if($o.State -eq "Disc"){
        if(!($o.Username -eq "")){
            $Username = $o.Username
            $ID = $o.ID
            Write-Host "   "$CountSession " - Server $Server - Closing $Username on session " $o.ID
            rwinsta.exe $ID /server:$Server
            $CountSession ++
            }
        }
}}

The full script

# Create a list (variable) containing all servers from Active Directory
$Servers = Get-ADComputer -Filter * -Properties OperatingSystem | ? { $_.OperatingSystem -match "Server" } | Select -ExpandProperty Name
# ForEach to be run against each server inside the variable $Servers
ForEach ($Server in $Servers) {
# Query for RDP sessions on the server
$c = qwinsta /server:$Server | where {$_.gettype().equals([string])}
# Convert qwinsta results on powershell readable data
$starters = New-Object psobject -Property @{"SessionName" = 0; "Username" = 0; "ID" = 0; "State" = 0; "Type" = 0; "Device" = 0;};
foreach($line in $c) {
        if($line.trim().substring(0, $line.trim().indexof(" ")) -eq "SESSIONNAME") {
            $starters.Username = $line.indexof("USERNAME");
            $starters.ID = $line.indexof("ID");
            $starters.State = $line.indexof("STATE");
            $starters.Type = $line.indexof("TYPE");
            $starters.Device = $line.indexof("DEVICE");
            continue;
            }
    $o = New-Object psobject -Property @{
            "ServerName" = $Server
            ;"SessionNAme" = $line.trim().substring(0, $line.trim().indexof(" ")).trim(">")
            ;"Username" = $line.Substring($starters.Username, $line.IndexOf(" ", $starters.Username) - $starters.Username)
            ;"ID" = $line.Substring($line.IndexOf(" ", $starters.Username), $starters.ID - $line.IndexOf(" ", $starters.Username) + 2).trim()
            ;"State" = $line.Substring($starters.State, $line.IndexOf(" ", $starters.State)-$starters.State).trim()
            ;"Type" = $line.Substring($starters.Type, $starters.Device - $starters.Type).trim()
            ;"Device" = $line.Substring($starters.Device).trim()
            }
# Disconnect all sessions tagged as Disc
    if($o.State -eq "Disc"){
        if(!($o.Username -eq "")){
            $Username = $o.Username
            $ID = $o.ID
            Write-Host "   "$CountSession " - Server $Server - Closing $Username on session " $o.ID
            rwinsta.exe $ID /server:$Server
            $CountSession ++
            }
        }
}}

About me

Over 20 years working with IT for multiple fields (logistics, Olympic games, oil and gas, insurance, pharmaceuticals, etc).

Sometimes find solutions on the internet can be challenging. That’s why I decided to create techmission.ca, where I’ll gather some solutions I have to apply on my environments as I receive my “missions” (that’s the way I name client’s requests).

Hope the solutions published here can help you guys as it helps me 🙂

Featured Posts