How to Configure Remote Desktop Services on Windows Server 2025
Remote Desktop Services (RDS) on Windows Server 2025 provides far more than simple remote access to a server desktop. It is a full application delivery and virtual desktop platform capable of hosting multi-session Remote Desktop Session Host (RDSH) farms, publishing individual RemoteApp programs to clients, providing secure external access through an RD Gateway, and enforcing licensing compliance with per-device or per-user Client Access Licences (CALs). Whether you need a single-server RDS deployment for a small team or a multi-role farm behind a load balancer, Windows Server 2025 supports the scenario with both a graphical Server Manager wizard and fully scriptable PowerShell cmdlets. This guide covers the complete configuration path from enabling basic RDP through to a functional RDS deployment with licensing, RemoteApp publishing, and NLA enforcement.
Prerequisites
- Windows Server 2025 Standard or Datacenter edition (Desktop Experience recommended for full RDS role)
- An elevated Windows PowerShell 5.1 session
- Static IP address and hostname already configured (see the initial configuration guide)
- Active Directory domain (required for the full RDS role deployment; basic RDP works in workgroup)
- RDS CAL licences (per-device or per-user) for production deployments
- A TLS certificate (self-signed acceptable for lab; trusted CA certificate required for production)
Step 1 — Enable Basic RDP via PowerShell
Before deploying the full RDS role, you may simply need to enable the RDP protocol for remote administration. This allows up to two concurrent administrative sessions without a Remote Desktop Session Host licence.
# Enable RDP by setting the registry value to 0 (0 = allow, 1 = deny)
Set-ItemProperty `
-Path "HKLM:SystemCurrentControlSetControlTerminal Server" `
-Name "fDenyTSConnections" `
-Value 0
# Enforce Network Level Authentication (NLA)
# Prevents unauthenticated connections — requires valid credentials before session is created
Set-ItemProperty `
-Path "HKLM:SystemCurrentControlSetControlTerminal ServerWinStationsRDP-Tcp" `
-Name "UserAuthentication" `
-Value 1
# Enable the RDP firewall rule group on all profiles
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"
# Set the Terminal Services service to start automatically
Set-Service -Name "TermService" -StartupType Automatic
Start-Service -Name "TermService"
# Verify RDP is enabled
(Get-ItemProperty "HKLM:SystemCurrentControlSetControlTerminal Server").fDenyTSConnections
Step 2 — Change the RDP Listening Port (Optional)
Changing RDP from its default port 3389 to a non-standard port reduces the volume of automated brute-force attacks in internet-facing scenarios. This alone is not a security control but reduces noise.
# Change the RDP port — replace 3390 with your chosen port
$newPort = 3390
Set-ItemProperty `
-Path "HKLM:SystemCurrentControlSetControlTerminal ServerWinStationsRDP-Tcp" `
-Name "PortNumber" `
-Value $newPort
# Update the firewall rule for the new port
New-NetFirewallRule `
-DisplayName "Custom RDP Port $newPort" `
-Direction Inbound `
-Protocol TCP `
-LocalPort $newPort `
-Action Allow `
-Profile Domain,Private
# Disable the default RDP firewall rule on port 3389
Disable-NetFirewallRule -DisplayGroup "Remote Desktop"
# Restart the Terminal Services service to apply the new port
Restart-Service TermService
# Verify
netstat -ano | findstr :$newPort
Step 3 — Install the RDS Role Components via Server Manager
A full Remote Desktop Services deployment requires multiple role services that are ideally installed through the Server Manager RDS wizard, which understands their interdependencies. For automation, use PowerShell.
Install via Server Manager (GUI)
- Open Server Manager → Manage → Add Roles and Features
- Choose Remote Desktop Services installation (not Role-based or feature-based)
- Select Quick Start for a single-server deployment
- Select Session-based desktop deployment
- Complete the wizard — it installs RD Connection Broker, RD Web Access, and RD Session Host automatically
Install via PowerShell
# Install all RDS role services for a single-server deployment
$rdsFeatures = @(
"RDS-RD-Server", # Remote Desktop Session Host (RDSH)
"RDS-Connection-Broker", # RD Connection Broker
"RDS-Web-Access", # RD Web Access
"RDS-Licensing", # Remote Desktop Licensing
"RDS-Gateway" # RD Gateway (optional — for external access)
)
Install-WindowsFeature `
-Name $rdsFeatures `
-IncludeManagementTools `
-Verbose
# A restart is required after installing RDS-RD-Server
Restart-Computer -Force
Step 4 — Configure the RDS Deployment
After the restart, use the RemoteDesktop module to configure the deployment. This module is installed automatically with the RDS role.
# Import the RDS management module
Import-Module RemoteDesktop
# Create a new RDS deployment on the local server
# Replace SRVRDSH01.corp.example.com with your actual server FQDN
$serverFQDN = "SRVRDSH01.corp.example.com"
New-RDSessionDeployment `
-ConnectionBroker $serverFQDN `
-WebAccessServer $serverFQDN `
-SessionHost $serverFQDN
# Verify the deployment
Get-RDServer -ConnectionBroker $serverFQDN
# List all servers in the deployment by role
Get-RDServer -ConnectionBroker $serverFQDN -Role RDS-RD-SERVER
Get-RDServer -ConnectionBroker $serverFQDN -Role RDS-WEB-ACCESS
Get-RDServer -ConnectionBroker $serverFQDN -Role RDS-LICENSING
Step 5 — Configure Remote Desktop Licensing
The RD Session Host will operate in a 120-day grace period without a licence server configured. After the grace period, users cannot connect. Configure the licence server and mode before production deployment.
# Set the licensing mode: PerDevice or PerUser
# PerDevice: one CAL consumed per unique client device
# PerUser: one CAL consumed per unique user account (requires AD)
Set-RDLicenseConfiguration `
-ConnectionBroker $serverFQDN `
-LicenseServer $serverFQDN `
-Mode PerUser `
-Force
# Verify
Get-RDLicenseConfiguration -ConnectionBroker $serverFQDN
# Check the licence server activation status and available CALs
Get-RDLicenseKeyPack
# Activate the licence server (requires internet access to Microsoft activation servers)
# This can also be done via the RD Licensing Manager MMC snap-in
Invoke-CimMethod `
-ClassName Win32_TSLicenseServer `
-MethodName ActivateServer `
-Namespace "ROOTCIMV2TerminalServices"
Step 6 — Create an RDS Session Collection
An RDS Session Collection defines the Session Hosts available to users, the connection settings, and which users or groups are permitted access.
# Create a new session collection
New-RDSessionCollection `
-ConnectionBroker $serverFQDN `
-CollectionName "General Desktop" `
-SessionHost $serverFQDN `
-CollectionDescription "Standard desktop for all domain users"
# Configure collection settings
Set-RDSessionCollectionConfiguration `
-ConnectionBroker $serverFQDN `
-CollectionName "General Desktop" `
-UserGroup "CORPDomain Users" `
-DisconnectedSessionLimitMin 60 `
-IdleSessionLimitMin 120 `
-AutomaticReconnectionEnabled $true `
-TemporaryFoldersDeletedOnExit $true `
-SecurityLayer SSL `
-AuthenticationType Required
# Verify the collection
Get-RDSessionCollection -ConnectionBroker $serverFQDN
Get-RDSessionCollectionConfiguration -ConnectionBroker $serverFQDN -CollectionName "General Desktop"
Step 7 — Publish RemoteApp Programs
RemoteApp allows individual applications to be published from the Session Host so that they appear to run locally on the client device rather than inside a full remote desktop session.
# List all applications already available for publishing
Get-RDAvailableApp -ConnectionBroker $serverFQDN -CollectionName "General Desktop"
# Publish a RemoteApp — Notepad (for testing)
New-RDRemoteApp `
-ConnectionBroker $serverFQDN `
-CollectionName "General Desktop" `
-DisplayName "Notepad" `
-FilePath "C:WindowsSystem32notepad.exe" `
-Alias "notepad"
# Publish a line-of-business application
New-RDRemoteApp `
-ConnectionBroker $serverFQDN `
-CollectionName "General Desktop" `
-DisplayName "Company CRM" `
-FilePath "C:Program FilesCompanyCRMcrm.exe" `
-Alias "company-crm" `
-CommandLineSetting DoNotAllow `
-RequiredCommandLine ""
# List published RemoteApps
Get-RDRemoteApp -ConnectionBroker $serverFQDN -CollectionName "General Desktop"
# Remove a published RemoteApp
Remove-RDRemoteApp `
-ConnectionBroker $serverFQDN `
-CollectionName "General Desktop" `
-Alias "notepad" `
-Force
Step 8 — Configure RD Gateway for External Access
The RD Gateway role allows external clients to securely connect to internal RDS resources over HTTPS (port 443) without requiring a VPN. It uses SSL/TLS to encrypt all traffic.
# Install the RD Gateway role if not already installed
Install-WindowsFeature RDS-Gateway -IncludeManagementTools
# Import the RD Gateway module
Import-Module RemoteDesktopServices
# Create a Connection Authorization Policy (CAP)
# CAP defines who can connect through the gateway
New-Item -Path "RDS:GatewayServerCAP" -Name "AllowDomainUsers" -UserGroups "CORPDomain Users@CORP" -AuthMethod 1
# Create a Resource Authorization Policy (RAP)
# RAP defines which internal servers the user can reach through the gateway
New-Item -Path "RDS:GatewayServerRAP" `
-Name "AllowInternalServers" `
-UserGroups "CORPDomain Users@CORP" `
-ComputerGroupType 2
# Bind the SSL certificate to the RD Gateway
# First, get the thumbprint of your certificate
$cert = Get-ChildItem Cert:LocalMachineMy | Where-Object { $_.Subject -like "*rdgateway.example.com*" }
Set-Item -Path "RDS:GatewayServerSSLCertificateThumbprint" -Value $cert.Thumbprint
# Configure the deployment to use the gateway
Set-RDDeploymentGatewayConfiguration `
-ConnectionBroker $serverFQDN `
-GatewayMode Custom `
-GatewayExternalFQDN "rdgateway.example.com" `
-LogonMethod Password `
-UseCachedCredentials $true `
-BypassLocal $true `
-Force
Step 9 — Assign a Certificate for RDP Connections
A trusted TLS certificate eliminates the certificate warning users see when connecting. Assign it to the RD Session Host and Connection Broker roles.
# Create a self-signed certificate for lab/testing use
$selfSignedCert = New-SelfSignedCertificate `
-DnsName $serverFQDN `
-CertStoreLocation "Cert:LocalMachineMy" `
-NotAfter (Get-Date).AddYears(2) `
-KeyUsage DigitalSignature, KeyEncipherment `
-KeyAlgorithm RSA `
-KeyLength 2048
Write-Host "Certificate thumbprint: $($selfSignedCert.Thumbprint)"
# Apply the certificate to all RDS roles on this server
Set-RDCertificate `
-ConnectionBroker $serverFQDN `
-Role RDRedirector `
-Thumbprint $selfSignedCert.Thumbprint `
-Force
Set-RDCertificate `
-ConnectionBroker $serverFQDN `
-Role RDPublishing `
-Thumbprint $selfSignedCert.Thumbprint `
-Force
Set-RDCertificate `
-ConnectionBroker $serverFQDN `
-Role RDWebAccess `
-Thumbprint $selfSignedCert.Thumbprint `
-Force
# For a production CA-issued certificate, import it first then use its thumbprint:
# Import-PfxCertificate -FilePath "C:Certsrdp.pfx" -CertStoreLocation "Cert:LocalMachineMy" -Password (Read-Host -AsSecureString)
Conclusion
Windows Server 2025 Remote Desktop Services delivers a mature, feature-rich platform for hosted desktops and RemoteApp delivery. Starting with basic RDP enabled for administrative access, you can grow the deployment incrementally — adding the Session Host, Connection Broker, Web Access portal, Gateway for external users, and a proper RDS licence server as your requirements evolve. The RemoteDesktop PowerShell module makes every aspect of this configuration scriptable and repeatable, which is essential when managing multiple Session Host servers in a farm or maintaining consistent configuration across development, staging, and production environments. Always enforce Network Level Authentication, apply a trusted TLS certificate, configure the Gateway for any external access, and audit user session activity through the RD Licensing Manager and Event Viewer to maintain a secure and compliant RDS deployment.