How to Configure Remote Desktop Services on Windows Server 2022
Remote Desktop Services (RDS) on Windows Server 2022 encompasses everything from simple single-server RDP access to full virtual desktop infrastructure with Remote Desktop Session Hosts, licensing servers, gateways, and RemoteApp programs. Whether you need to enable basic RDP for administrative access or deploy a multi-user RDS farm for application delivery, this guide covers the configuration steps using PowerShell and explains the key architectural concepts you need to understand to deploy RDS correctly.
The Difference Between RDP and RDS
Remote Desktop Protocol (RDP) is the protocol used for all remote desktop connections. Basic RDP access for administrators is always available on Windows Server (up to two concurrent admin sessions) without any RDS licensing. This is called Remote Administration mode and does not require the Remote Desktop Services role.
Remote Desktop Services is the full role you install when you need more than two concurrent users, when you want to publish RemoteApp programs, or when you need features like session brokering, gateway access, or RDS licensing management. RDS requires a licensing server and Client Access Licenses (CALs) for each user or device beyond the two free admin sessions.
Enabling Basic RDP for Administrative Access
For administrative RDP (not the full RDS role), enable Remote Desktop by modifying the registry key that controls access and configure the Windows Firewall rule to allow the connection.
# Enable Remote Desktop
Set-ItemProperty -Path "HKLM:SystemCurrentControlSetControlTerminal Server" `
-Name "fDenyTSConnections" -Value 0
# Verify the change
$rdpEnabled = (Get-ItemProperty "HKLM:SystemCurrentControlSetControlTerminal Server").fDenyTSConnections
Write-Host "RDP Denied: $rdpEnabled" # 0 = enabled, 1 = disabled
# Enable firewall rules for RDP
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"
# Confirm the firewall rule is enabled
Get-NetFirewallRule -DisplayGroup "Remote Desktop" |
Select-Object DisplayName, Enabled, Direction
Enabling Network Level Authentication (NLA)
Network Level Authentication (NLA) requires the user to authenticate before a full Remote Desktop session is established. Without NLA, the Windows login screen is rendered to the connecting client before authentication occurs, which consumes server resources and increases the attack surface. NLA is the recommended security configuration for all RDP deployments.
# Enable NLA via registry
Set-ItemProperty `
-Path "HKLM:SystemCurrentControlSetControlTerminal ServerWinStationsRDP-Tcp" `
-Name "UserAuthentication" -Value 1
# Verify NLA is enabled
(Get-ItemProperty "HKLM:SystemCurrentControlSetControlTerminal ServerWinStationsRDP-Tcp").UserAuthentication
# 1 = NLA enabled, 0 = NLA disabled
# Check using CIM (alternative method)
Get-CimInstance -ClassName Win32_TerminalServiceSetting -Namespace "RootCimV2TerminalServices" |
Select-Object UserAuthentication
Changing the Default RDP Port
The default RDP port is TCP 3389. While security through obscurity is not a substitute for proper hardening, changing the port reduces noise from automated scanners and brute-force bots. After changing the port, update the firewall rule to match.
# Change RDP listening port to 3390 (example)
$NewPort = 3390
Set-ItemProperty `
-Path "HKLM:SystemCurrentControlSetControlTerminal ServerWinStationsRDP-Tcp" `
-Name "PortNumber" -Value $NewPort -Type DWord
# Verify the change
(Get-ItemProperty "HKLM:SystemCurrentControlSetControlTerminal ServerWinStationsRDP-Tcp").PortNumber
# Update Windows Firewall — remove old rule and add new one
Remove-NetFirewallRule -DisplayName "Remote Desktop - User Mode (TCP-In)" -ErrorAction SilentlyContinue
New-NetFirewallRule `
-DisplayName "Remote Desktop Custom Port (TCP-In)" `
-Direction Inbound `
-Protocol TCP `
-LocalPort $NewPort `
-Action Allow `
-Profile Domain,Private
# Restart the RDP service for the port change to take effect
Restart-Service -Name TermService -Force
When connecting from the client side to a non-standard port, append the port to the server address in the RDP client: server-ip:3390.
Installing the Remote Desktop Services Role
To support more than two concurrent users, install the Remote Desktop Services role. In a full RDS deployment, multiple role services work together. For a simple single-server RDS deployment (all roles on one server), install the Session Host and Licensing roles together.
# Install the Remote Desktop Session Host role
Install-WindowsFeature -Name RDS-RD-Server -IncludeManagementTools
# Install the RD Licensing role (needed to manage CALs)
Install-WindowsFeature -Name RDS-Licensing -IncludeManagementTools
# Install both at once with management tools
Install-WindowsFeature -Name RDS-RD-Server, RDS-Licensing, `
RDS-Connection-Broker, RDS-Web-Access -IncludeManagementTools
# Check the result
Get-WindowsFeature | Where-Object { $_.Name -like "RDS*" -and $_.Installed }
RDS Licensing Modes
Windows Server 2022 RDS supports two licensing modes: Per User and Per Device. Per User requires one CAL per user account regardless of how many devices they connect from. Per Device requires one CAL per client device regardless of how many users connect from that device. Configure the licensing mode and license server address in the registry on each Session Host.
# Set licensing mode: 2 = Per Device, 4 = Per User
Set-ItemProperty `
-Path "HKLM:SYSTEMCurrentControlSetControlTerminal ServerRCMLicensing Core" `
-Name "LicensingMode" -Value 4 # 4 = Per User
# Set the license server address
Set-ItemProperty `
-Path "HKLM:SYSTEMCurrentControlSetServicesTermServiceParametersLicenseServers" `
-Name "SpecifiedLicenseServers" -Value "rds-license.yourdomain.com"
# Verify current licensing configuration
Get-WmiObject -Namespace root/cimv2 -Class Win32_TerminalServiceSetting |
Select-Object LicensingType, LicensingName
Configuring the Session Host
The Remote Desktop Session Host (RDSH) is the server where user sessions run. After installing the RDS-RD-Server role, configure session limits and behavior to prevent resource exhaustion.
# Configure session time limits via registry
# These settings apply to all users; per-user settings in Group Policy override these
# Set maximum idle session time (in milliseconds) — 30 minutes = 1800000
Set-ItemProperty `
-Path "HKLM:SOFTWAREPoliciesMicrosoftWindows NTTerminal Services" `
-Name "MaxIdleTime" -Value 1800000 -Type DWord
# Set maximum session time — 8 hours = 28800000
Set-ItemProperty `
-Path "HKLM:SOFTWAREPoliciesMicrosoftWindows NTTerminal Services" `
-Name "MaxConnectionTime" -Value 28800000 -Type DWord
# Set disconnected session time limit — 1 hour = 3600000
Set-ItemProperty `
-Path "HKLM:SOFTWAREPoliciesMicrosoftWindows NTTerminal Services" `
-Name "MaxDisconnectionTime" -Value 3600000 -Type DWord
Managing Active RDS Sessions
Use the query command-line tool and its PowerShell-friendly equivalents to view and manage active sessions on a Session Host.
# List all active sessions on the local server
query session
# or:
qwinsta
# List sessions on a remote server
query session /server:RDSH-01
# List sessions and user details
query user
quser
# Disconnect a session by session ID
logoff 3
# Disconnect a session on a remote server
logoff 3 /server:RDSH-01
# Send a message to a session
msg 3 "Server maintenance in 15 minutes. Please save your work."
# Send a message to all sessions
msg * "Server going down for maintenance at 10:00 PM."
# Reset (forcibly disconnect and delete) a session
reset session 3
rwinsta 3
Shadow Connections (Remote Control of Sessions)
Shadow connections allow an administrator to view or interact with another user’s active RDS session. This is useful for troubleshooting user issues without requiring the user to describe their problem. Shadow connections require the administrator to have appropriate permissions and the target session to be active.
# First, find the session ID of the user you want to shadow
query session /server:RDSH-01
# Shadow a session (view only — read-only mode)
mstsc /shadow:3 /v:RDSH-01 /noConsentPrompt
# Shadow with control (interactive mode — you can interact with their session)
mstsc /shadow:3 /v:RDSH-01 /control /noConsentPrompt
# Configure shadow policy via registry (0=disabled, 1=full control no consent,
# 2=full control with consent, 3=view only no consent, 4=view only with consent)
Set-ItemProperty `
-Path "HKLM:SOFTWAREPoliciesMicrosoftWindows NTTerminal Services" `
-Name "Shadow" -Value 2 -Type DWord # Full control with user consent
RemoteApp Setup Overview
RemoteApp allows individual applications to be published to users so they appear to run locally on the user’s desktop, even though they are executing on the Session Host. Users launch them from a shortcut or via the RD Web Access portal. Configuring RemoteApp requires the Session Host role to be installed and uses the Remote Desktop Services Manager console or PowerShell.
# Import the RemoteDesktop module
Import-Module RemoteDesktop
# Get the list of currently published RemoteApp programs
Get-RDRemoteApp -ConnectionBroker "rdbroker.yourdomain.com"
# Publish a new RemoteApp program (Notepad as an example)
New-RDRemoteApp `
-Alias "Notepad" `
-DisplayName "Notepad" `
-FilePath "C:WindowsSystem32notepad.exe" `
-ShowInWebAccess 1 `
-ConnectionBroker "rdbroker.yourdomain.com" `
-CollectionName "Office Apps"
# Remove a published RemoteApp
Remove-RDRemoteApp -Alias "Notepad" `
-ConnectionBroker "rdbroker.yourdomain.com" `
-CollectionName "Office Apps"
RD Gateway Overview
The Remote Desktop Gateway (RD Gateway) allows RDP connections from the internet over HTTPS (port 443) without exposing port 3389 directly to the internet. The gateway acts as an SSL-terminating proxy that wraps RDP traffic in HTTPS. This is the recommended way to provide remote access to RDS from outside the corporate network.
# Install the RD Gateway role service
Install-WindowsFeature -Name RDS-Gateway -IncludeManagementTools
# The RD Gateway requires a valid SSL certificate
# Import the SSL certificate (assumes PFX is already on the server)
$CertPassword = ConvertTo-SecureString "CertP@ss!" -AsPlainText -Force
Import-PfxCertificate -FilePath "C:Certsrdgateway.pfx" `
-CertStoreLocation "Cert:LocalMachineMy" `
-Password $CertPassword
# Get the thumbprint of the imported certificate
$Cert = Get-ChildItem -Path "Cert:LocalMachineMy" |
Where-Object { $_.Subject -like "*rdgateway*" }
$Cert.Thumbprint
# Configure the RD Gateway with the certificate thumbprint using netsh
# (PowerShell cmdlets for RD Gateway are limited; netsh and wmic are often needed)
# The GUI (RD Gateway Manager MMC) is the most reliable configuration tool for initial setup
Firewall Rules for RDS
A properly configured RDS deployment requires specific firewall rules on each role server. Here are the standard rules:
# Allow inbound RDP (port 3389) — for Session Hosts
New-NetFirewallRule -DisplayName "RDP Inbound" `
-Direction Inbound -Protocol TCP -LocalPort 3389 `
-Action Allow -Profile Domain
# Allow RD Gateway HTTPS (port 443)
New-NetFirewallRule -DisplayName "RD Gateway HTTPS" `
-Direction Inbound -Protocol TCP -LocalPort 443 `
-Action Allow -Profile Domain,Public
# Allow RD Connection Broker (port 3389 and 443 internally)
New-NetFirewallRule -DisplayName "RD Connection Broker" `
-Direction Inbound -Protocol TCP -LocalPort 3389,443,3388 `
-Action Allow -Profile Domain
# Allow RD Licensing (port 135 RPC, plus dynamic ports)
Enable-NetFirewallRule -DisplayGroup "Remote Desktop - RemoteFX"
# Verify all RDS-related firewall rules
Get-NetFirewallRule | Where-Object { $_.DisplayName -like "*Remote Desktop*" } |
Select-Object DisplayName, Enabled, Direction, Action
Granting RDP Access to Users
By default, only members of the local Administrators group can connect via RDP. To grant non-administrator users RDP access, add them to the Remote Desktop Users local group.
# Add a domain user to Remote Desktop Users group
Add-LocalGroupMember -Group "Remote Desktop Users" -Member "DOMAINjsmith"
# Add a local user
Add-LocalGroupMember -Group "Remote Desktop Users" -Member "localuser"
# Add multiple users at once
$RDPUsers = @("DOMAINjsmith", "DOMAINbjones", "DOMAINrdpgroup")
foreach ($user in $RDPUsers) {
Add-LocalGroupMember -Group "Remote Desktop Users" -Member $user -ErrorAction SilentlyContinue
}
# View current members of the Remote Desktop Users group
Get-LocalGroupMember -Group "Remote Desktop Users"
Configuring Remote Desktop Services correctly, from basic RDP hardening with NLA and firewall rules to a full RDS deployment with licensing, session management, and RemoteApp publishing, gives you a secure and scalable remote access platform on Windows Server 2022. Always pair RDS with a proper patch management strategy, use NLA everywhere, and consider RD Gateway for any public-facing RDS deployments instead of exposing port 3389 directly.