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

  1. Start from the same network path as the affected user so VPN, VLAN, and firewall differences are visible.
  2. Resolve the hostname and record the address that the client is actually trying to reach.
  3. Test TCP 3389 before changing firewall policy or Remote Desktop settings.
  4. Collect TermService state, listener/session output, Remote Desktop firewall rule state, and recent Terminal Services events.
  5. If TCP fails but the service is healthy, compare network path, VPN split tunnel, NSG/firewall policy, and host profile scope.
  6. 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 -AutoSize

Validation

  • 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.