When administering Windows servers, you'll often need to forcibly disconnect Remote Desktop sessions - whether for maintenance, security reasons, or simply reclaiming system resources. While the graphical Terminal Services Manager works for one-off cases, automation requires command-line solutions.
Windows provides these built-in commands:
qwinsta - lists all sessions
rwinsta - resets a specific session
The challenge lies in parsing qwinsta's tabular output to extract session IDs for automated processing.
Here's a robust PowerShell function to handle this:
function Disconnect-RDPSessions {
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter()]
[string]$ComputerName = $env:COMPUTERNAME
)
try {
$sessions = qwinsta /server:$ComputerName |
Where-Object { $_ -notmatch '^ SESSIONNAME' } |
ForEach-Object {
$session = ($_ -split '\s+')
[PSCustomObject]@{
SessionName = $session[1]
Username = $session[2]
ID = $session[3]
State = $session[4]
Type = $session[5]
Device = $session[6]
}
}
$activeSessions = $sessions | Where-Object { $_.State -eq 'Active' }
foreach ($session in $activeSessions) {
if ($PSCmdlet.ShouldProcess("Session ID $($session.ID) ($($session.Username))", "Disconnect")) {
rwinsta $session.ID /server:$ComputerName | Out-Null
}
}
return $activeSessions.Count
}
catch {
Write-Error "Failed to disconnect sessions: $_"
return -1
}
}
For applications requiring .NET integration:
using System;
using System.Diagnostics;
class RDPManager {
static void Main(string[] args) {
var startInfo = new ProcessStartInfo {
FileName = "qwinsta",
Arguments = "",
RedirectStandardOutput = true,
UseShellExecute = false
};
using (var process = Process.Start(startInfo)) {
string output = process.StandardOutput.ReadToEnd();
foreach (string line in output.Split('\n')) {
if (line.Contains("Active")) {
string[] parts = line.Split(new[] { ' ' },
StringSplitOptions.RemoveEmptyEntries);
int sessionId = int.Parse(parts[2]);
Process.Start("rwinsta", sessionId.ToString());
}
}
}
}
}
For legacy systems or quick scripts:
@echo off
setlocal enabledelayedexpansion
for /f "tokens=1-7 delims= " %%a in ('qwinsta ^| find "Active"') do (
echo Disconnecting session ID: %%c
rwinsta %%c
)
- Administrator privileges are required
- Some system sessions (like console) cannot be disconnected
- User data may be lost when sessions are forcibly terminated
- Consider warning logged-in users before mass disconnects
When administering Windows systems, you may need to programmatically disconnect active Remote Desktop sessions. Windows provides several built-in commands like qwinsta
(query session) and rwinsta
(reset session) that can help with this task. However, parsing their output can be challenging in scripts.
Here's a complete PowerShell script to disconnect all RDP sessions:
# Get all active sessions (excluding console and services)
$sessions = qwinsta | Where-Object { $_ -match 'rdp' -and $_ -notmatch 'services' -and $_ -notmatch 'console' }
# Extract session IDs
$sessionIds = $sessions | ForEach-Object { ($_ -split '\s+')[2] }
# Disconnect each session
foreach ($id in $sessionIds) {
rwinsta $id
Write-Host "Disconnected session ID: $id"
}
For those working with C#, here's how to accomplish the same task:
using System;
using System.Diagnostics;
class Program {
static void Main() {
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c qwinsta | find \"rdp\"";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.Start();
string output = process.StandardOutput.ReadToEnd();
string[] lines = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines) {
string[] parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length > 2) {
string sessionId = parts[2];
Process.Start("rwinsta", sessionId).WaitForExit();
Console.WriteLine($"Disconnected session: {sessionId}");
}
}
}
}
For simple batch scripting:
@echo off
for /f "tokens=2 delims= " %%a in ('qwinsta ^| find "rdp"') do (
rwinsta %%a
echo Disconnected session: %%a
)
When implementing these solutions, consider:
- Running scripts with administrative privileges
- Handling special cases like disconnected sessions
- Logging actions for audit purposes
- Adding error handling for robustness
You can also use WMI for more control:
Get-WmiObject -Class Win32_Process -Filter "Name='rdpclip.exe'" | ForEach-Object { $_.Terminate() }
Or the TSAdmin COM object:
$tsSessionMgr = New-Object -ComObject "Microsoft.TS.TSManager"
$tsSessionMgr.GetSessions() | Where-Object { $_.State -eq 0 } | ForEach-Object { $tsSessionMgr.DisconnectSession($_.SessionID) }