Skip Ribbon Commands
Skip to main content

Ondrej Sevecek's English Pages


Engineering and troubleshooting by Directory Master!
MCM: Directory

Quick Launch

Ondrej Sevecek's English Pages > Posts > Assign RDP server certificate by using PowerShell
January 31
Assign RDP server certificate by using PowerShell

The following script finds the best certificate for RDP in the local machine certificate Personal (MY) store and assigns it for the use by the RDP server. Note that it prefers the Remote Desktop Authentication EKU (Enhanced Key Usage, The certificate must be valid and have private key available, the script selects the certificate which is valid for the longest time. The script also makes sure that the Network Service account is granted read permission to the certificate private key.

[object[]] $validCerts = dir cert:\LocalMachine\My | ? { $_.HasPrivateKey -and $_.NotBefore -le ([DateTime]::Now) -and $_.NotAfter -gt ([DateTime]::Now)} | sort -Descending NotAfter
$certRDP = $null
$certTLS = $null

if ($validCerts.Length -gt 0) { foreach ($oneValidCert in $validCerts) {

  [string[]] $ekus = $oneValidCert.Extensions[''].EnhancedKeyUsages | select -Expand Value
  if (($ekus -contains '') -and ([object]::Equals($certRDP, $null))) {

    $certRDP = $oneValidCert
    Write-Host ('Found best RDP certificate: {0} | {1} | {2}' -f $certRDP.Subject, $certRDP.NotAfter.ToString('yyyy-MM-dd HH:mm:ss'), $certRDP.Thumbprint)

  } elseif (($ekus -contains '') -and ([object]::Equals($certTLS, $nullo))) {

    $certTLS = $oneValidCert
    Write-Host ('Found best TLS certificate: {0} | {1} | {2}' -f $certTLS.Subject, $certTLS.NotAfter.ToString('yyyy-MM-dd HH:mm:ss'), $certTLS.Thumbprint)

$certBest = $null

if (-not ([object]::Equals($certRDP, $null))) {

  $certBest = $certRDP

} elseif (-not ([object]::Equals($certTLS, $null))) {

  $certBest = $certTLS

if ([object]::Equals($certBest, $null)) {

  throw ('Cannot find any suitable RDP certificate')

$thumbBytes = New-Object byte[] 20
for ($i = 0; $i -lt 20; $i ++) {

  $oneByte = $certBest.Thumbprint.SubString(($i * 2), 2)
  $thumbBytes[$i] = [Convert]::ToByte($oneByte, 16)

Write-Host ('Selected: thumbprint = {0} | {1}' -f $certBest.Thumbprint, ([BitConverter]::ToString($thumbBytes)))
Write-Host ('Selected: subject = {0}' -f $certBest.Subject)
Write-Host ('Selected: SAN = {0}' -f ($certBest.DnsNameList -join ','))
Write-Host ('Selected: expires = {0}' -f $certBest.NotAfter.ToString('yyyy-MM-dd HH:mm:ss'))
Write-Host ('Selected: issuer = {0}' -f $certBest.Issuer)

Remove-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations' SelfSignedCertifi -Force -EA SilentlyContinue
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' SSLCertificateSHA1Hash $thumbBytes -Type Binary

# Note: RDP requires the private key to be accessible by Network Service
certutil -repairstore my $certBest.Thumbprint 'D:P(A;;0x80120089;;;NS)(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)'

Restart-Service SessionEnv -Force


There are no comments for this post.

Add Comment

Sorry comments are disable due to the constant load of spam *

This simple antispam field seems to work well. Just put here the number.


You do not need to provide any value this column. It will automatically fill with the name of the article itself.

Author *

Body *