We're headed to GridSecCon 2024, October 22-25 in Minneapolis, MN! Learn more here
Schedule a Demo
Blog July 6, 2021 Certificates, PowerShell, RDP

Register TLS certificate with Remote Desktop Service using PowerShell

by Vadims Podāns

Hello everyone! This is a quick blog post that provides information on how to register TLS certificate with Remote Desktop Services (RDS).

Starting with Windows Server 2008 R2 it became extremely easy to deploy RDS certificates to AD hosts from private CA using group policies and Microsoft CA. Since then RDS over TLS should be a baseline configuration in any Active Directory environment. If for some reason certificate is not configured using GPO an autogenerated self-signed certificate is used which raises warning dialogs to connecting users. With GPO, you don’t have to care about certificate lifecycle management (such as installation, configuration, renewal) and everything works without popping warning dialogs, because GPO certificates are issued by a centrally managed enterprise CA.

However, it is not always possible to use GPO. RDS Certificate GPO is simple in configuration and this puts limitations to settings:

  • certificate is issued against RDS host name only
  • requires that all connecting clients trust enterprise CA certificate

There are legitimate scenarios when administrators need a custom certificate with possibly additional names included in Subject Alternative Names (SAN) certificate extension or use 3rd party CA. Prior to Windows Server 2012 you could install a 3rd party certificate and associate with Remote Desktop Services using Remote Desktop Session Host Configuration MMC snap-in:

This MMC was gone in Windows Server 2012 and subsequent OS versions and never was available on client operating systems. This makes RDS configuration to use custom certificate installed in certificate store a bit complicated. Fortunately, there are automation means using WMI Win32_TSGeneralSetting class as follows:

$path = (Get-WmiObject-class "Win32_TSGeneralSetting" -Namespace root\cimv2\terminalservices -Filter "TerminalName='RDP-tcp'").__path
Set-WmiInstance -Path $path -argument @{SSLCertificateSHA1Hash="$Thumbprint"}

First line retrieves path to RDS connection. By default, it is “RDP-tcp”. Specify custom RDS connection name if non-default connection must be configured. In the second line, specify a TLS certificate SHA1 thumbprint. It must be exactly 40 hexadecimal character long string without spaces and control characters. For example, “09d1a73113ceeae873d005a80e62699aa2d0bf05”. You don’t need to restart anything, setting is applied immediately to any new connection. Existing connections are not affected. This script can be used on client operating systems as well.

Just to clarify certificate requirements to comply with RDS:

  1. The certificate is installed into computer’s “Personal” certificate store.
  2. The certificate has a corresponding private key.
  3. The “Enhanced Key Usage” extension has a value of either “Server Authentication” or “Remote Desktop Authentication” (1.3.6.1.4.1.311.54.1.2). Certificates with no “Enhanced Key Usage” extension can be used as well.

Happy scripting with PowerShell!

Related Resources

  • Blog People sitting in a large room full of computers
    March 7, 2024

    Why you are getting it wrong with Certificate Lifecycle Management

    Certificate Management, Certificates, CLM
  • Blog
    March 7, 2024

    PKI Insights – Avoiding PenTest Pitfalls

    Certificates, PKI, PKI Insights
  • Blog
    February 6, 2024

    PKI Insights Recap – Microsoft Intune Cloud PKI

    BYOD, Certificates, Cloud, Enrollment, NDES

Vadims Podāns

PKI Software Architect

View All Posts by Vadims Podāns

Comments

  • There’s a typo in the command I think:

    $path = (Get-WmiObject -class “Win32_TSGeneralSetting” -Namespace root\cimv2\terminalservices -Filter “TerminalName=’RDP-tcp’”).__path
    Set-WmiInstance -Path $path -argument @{SSLCertificateSHA1Hash=”$Thumprint”}

    Last variable should be: $Thumbprint ?

  • This is very interesting. Finally PKI Solutions is taking interest on this one.

    I started studying this subject back in 2019 and even created an issue into GitHub regarding this (https://github.com/PKISolutions/PSPKI/issues/64). At that time Mr. Podāns resolved that as a non-issue.

    Later in October 2020 I presented a full solution for handling RDP certificates with a modified PSPKI-library. My code is publicly available at https://github.com/HQJaTu/RDP-cert-tools for anybody to use. As my work is a fork, I’d rather have authors of PSPKI to reconsider and drive their development efforts for fully supporting the use case of RDP certificates. At that point my fork wouldn’t be needed.

    • I’ve reviewed your inquiry once again and I still consider your use case a not common scenario which should be implemented in PSPKI framework at this point, unfortunately.

        • Hi Hari Turkia, your solution is the exact one I was searching for! Due to self singed cert on every RDP endpoint, the vulnerability scanner too give the critical warning.
          I tested your script in one of the windows 10, and it worked properly. Now I want to do the same on 2k +system in network, however, I do not want to install PS v7 in each one of them 🙂 any solution to do this in “remote” system without installing ps 7 and pspki modules first?

          Thanks
          AB

  • Why not simply
    wmic /namespace:\\root\cimv2\TerminalServices PATH Win32_TSGeneralSetting Set SSLCertificateSHA1Hash=”THUMBPRINT” or even drop the thumbprint in the registry at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\ SSLCertificateSHA1Hash although the format of the thumbprint is different.

    • I personally don’t like wmic tool. And your WMI query is missing RDP connection in filter.

    • If ignoring any possible issues with WMIC, how do you automate importing a PEM X.509?

      Btw. with Powershell command would be something like:
      $tsSetting = Get-CimInstance -ClassName ‘Win32_TSGeneralSetting’ -Namespace ‘root\cimv2\terminalservices’
      Set-CimInstance -CimInstance $tsSetting -Property @{SSLCertificateSHA1Hash=THUMBPRINT}

      • Importing plain PEM without private key makes no sense. You need a PFX to import the certificate with private key. Or even better — generate the CSR on a machine (this will generate and store private key on a machine, so you don’t need to deal with PFX) and then install response against pending request.

  • How to activate the RDS license with this gwmi, I tried many without GUI but no luck. Like I’m having Licensed Server ID and Client access license keys which I’m using to activate my rds per user type of license activation. Below are the steps I’m followed for manual activation with these keys:
    1) From RDS License manager, right-click “Activate License” and select connection method as “Web-Browser” and then entering License server ID key and clicking next to activate license
    2) next window it asking to enter license for client Access, so entering license for Client Access License.
    3) Then it completed the activation. Final is making configuration, from RDS license manager, right the host and click “Review Configuration” and need to allow to Active group to add this computer is final settings i made.

    Could you please suggest any other way to automate this process using PowerShell?

  • How we can allow the external RDP connection to the server by a published/installed SSL certificate to encrypt it?

Leave a Reply

Your email address will not be published. Required fields are marked *