RDP failure triage script
A read-only RDP triage script pattern for DNS, TCP 3389, listener state, firewall evidence, sessions, and event logs.
Good For
- RDP outage triage
- VPN path checks
- Windows Server remote access
- firewall evidence
- helpdesk escalation
How to Use It
- Start from the same network path as the affected user so VPN, VLAN, and firewall differences are visible.
- Resolve the hostname and record the address that the client is actually trying to reach.
- Test TCP 3389 before changing firewall policy or Remote Desktop settings.
- Collect TermService state, listener/session output, Remote Desktop firewall rule state, and recent Terminal Services events.
- If TCP fails but the service is healthy, compare network path, VPN split tunnel, NSG/firewall policy, and host profile scope.
- Export the evidence to CSV or ticket notes before escalating to server, network, or identity owners.
Execution Modes
- local
- remote-single-host
- remote-host-list
- ad-filtered
Inputs and Outputs
Inputs
- computer name
- CSV or TXT server list
- Active Directory computer scope
- affected client network path
Outputs
- verbose-console
- csv
- operator-notes
Command Starter
Safe to run: read-only
# ---------------------------------------------------------------------
# Operator inputs
# ---------------------------------------------------------------------
$ComputerNames = @('server01.contoso.com')
$OutputPath = '.\rdp-failure-triage.csv'
# ---------------------------------------------------------------------
# Gather client-path and server-side RDP evidence
# ---------------------------------------------------------------------
$Results = foreach ($ComputerName in $ComputerNames) {
$Dns = Resolve-DnsName -Name $ComputerName -ErrorAction SilentlyContinue
$Tcp3389 = Test-NetConnection -ComputerName $ComputerName -Port 3389 -InformationLevel Quiet -WarningAction SilentlyContinue
try {
$ServerEvidence = Invoke-Command -ComputerName $ComputerName -ErrorAction Stop -ScriptBlock {
$TermService = Get-Service -Name TermService
$RemoteDesktopRules = @(Get-NetFirewallRule -DisplayGroup 'Remote Desktop' -ErrorAction SilentlyContinue |
Select-Object DisplayName, Enabled, Profile, Direction, Action)
$RecentEvents = @(Get-WinEvent -LogName 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational' -MaxEvents 20 -ErrorAction SilentlyContinue)
[pscustomobject]@{
TermServiceStatus = $TermService.Status
EnabledRdpRuleCount = @($RemoteDesktopRules | Where-Object Enabled -eq 'True').Count
RecentTerminalServicesEventCount = $RecentEvents.Count
}
}
[pscustomobject]@{
ComputerName = $ComputerName
ResolvedAddress = ($Dns.IPAddress -join ', ')
Tcp3389Open = [bool]$Tcp3389
TermService = $ServerEvidence.TermServiceStatus
EnabledRdpRules = $ServerEvidence.EnabledRdpRuleCount
RecentRdpEvents = $ServerEvidence.RecentTerminalServicesEventCount
}
}
catch {
[pscustomobject]@{
ComputerName = $ComputerName
ResolvedAddress = ($Dns.IPAddress -join ', ')
Tcp3389Open = [bool]$Tcp3389
TermService = $null
EnabledRdpRules = $null
RecentRdpEvents = $null
Error = $_.Exception.Message
}
}
}
$Results | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
$Results | Format-Table -AutoSizeValidation
- The target name resolves to the expected address from the affected client path.
- TCP 3389 reachability, service state, firewall rule state, and recent session events are all captured.
- The escalation note separates client path failure, server listener failure, policy failure, and identity/session failure.
Reporting
- export per-server RDP reachability and listener evidence to CSV
- attach Terminal Services event snippets to the incident ticket
- group failures by DNS, TCP path, service/listener, firewall profile, or session policy
Safety Notes
- This triage pass is read-only and should not enable RDP, change firewall rules, or alter user rights.
- Do not open TCP 3389 broadly without approval, scope review, and rollback planning.