31 дек. 2025

Один из способов восстановления автоматизации развертывания сертификатов Lets Encrypt на Win RDS 2025.

WIN RDS 2025 + Lets Encrypt UPDATED!

Классика

А чем же плохи прежние сертификаты и решения?

Для автоматизации получения SSL сертификата Let’s Encrypt в Windows можно применить Windows ACME Simple (WACS). WACS позволяет выбрать сайт IIS и автоматически выпустить и привязать к нему SSL сертификат Let’s Encrypt, создает задание в планировщике, и обновляет сертификат и привязку к IIS.

Среди прочих скриптов ACME имеется скрипт для автоматического импорта Let’s Encrypt сертификата в WinRDS. Основная проблема в том, что не подходит для автоматизации, и с ним каждые два месяца нужно работать руками. Известный в сети пользователь Антон доработал его, и куча народа успешно работала с ImportRDGateway_Cert_From_IIS.ps1

Кто опять всё сломал?

Пока одна половина интернета ищет, почему роли RDS после обновления на свежий билд не подхватывают сертификат от Let's Encrypt, хотя в IIS то всё обновилось! — вторая половина пилит скрипты и точит костыли ;)

Всё потому, что легендарный ImportRDGateway_Cert_From_IIS.ps1 окончательно перестал работать на последних билдах на Windows Server 2025, и, разумеется, никаких предупреждений от МС никто не получал. Современный Set-RDCertificate стал капризным: ему подавай физический PFX, правильную цепочку (Chain) и экспортируемый закрытый ключ.

CIM + Win32_TSGatewayServer  — капитулирен
Set-Item  RDS:\GatewayServer  — капитулирен
netsh http sslcert  — капитулирен

Решение

#WorkAround, оно же "костыли" © :)

Мы, ясен красен, будем использовать win-acme для выпуска и подготовки PFX, а кастомный скрипт для его деплоя.

Поехали!


1. Как настроить win-acme (WACS) под этот скрипт

Когда wacs.exe --renew запускается, он:
- Проверяет, не пора ли обновить серт
- Если пора — выпускает новый
- Обновляет IIS (это у нас уже работает)
- Запускает наш скрипт (вот это мы добавим)

последняя версия WACS на гитхаб

Чтобы не запутаться в интерфейсе wacs.exe, вот чек-лист настроек для Renewal (меню E — Edit):

  1. Store Step 1: CertificateStore (основное хранилище, это для IIS, чтобы сайт RDWEB в IIS работал).

  2. Store Step 2: PfxFile — это то, что мы добавляем для workaround.

    • Path: Path:\Folder-DEFstore-PFX

    • Password: твой фиксированный пароль (который ты вписал в скрипт как $PfxPassword = "ВашСложныйПароль" ).

  3. Installation Step 1: IIS (обновляет биндинги на 443 порту).

  4. Installation Step 2: Run script — наш финал.

В младших версиях WACS нужно было писать так:

  • Executable: powershell.exe

  • Parameters: -ExecutionPolicy Bypass -File "Path:\Script.ps1" -CertThumbprint "{CertThumbprint}"

В старших версиях WACS нужно писать так:

  • Script: Path:\Script.ps1

  • Parameters: -CertThumbprint "{CertThumbprint}"

Почему в параметрах остался {CertThumbprint}?

Хотя мы берем PFX из файла, нам всё равно нужен отпечаток (Thumbprint) нового сертификата, чтобы:

  1. Записать его в лог (для сверки).

  2. Обновить RDP Listener через WMI (он принимает именно отпечаток, а не файл).

При создании или редактировании Renewal (меню E) в win-acme, убедитесь, что PfxFile выбран в дополнение к основному хранилищу Win и задайте фиксированный пароль, можно сохранить его в Vault

А раз у нас теперь есть стабильный файл PFX с известным паролем, мы обходим все капризы хранилища сертификатов Windows


2. Код скрипта

Мы немного потестировали это, ломаться тут особо нечему до следующего обновления МС :) Пока этот вариант максимально стабилен для Windows Server 2025. Сохраним его как Path:\Script.ps1

param(
    [Parameter(Mandatory=$true)]
    [string]$CertThumbprint # Передается от win-acme, используем для логов и WMI
)

# --- КОНФИГУРАЦИЯ ---
$SourcePfx = "Path:\cert.pfx" # Путь, который настроили в win-acme
$PfxPassword = "ВашСложныйПароль" # Пароль, который настроили в win-acme
$ExportPath = "Path:\Export" # Папка для архива
$LogPath = "Path:\CertLogs"

# Подготовка папок
foreach ($Path in @($LogPath, $ExportPath)) {
    if (!(Test-Path $Path)) { New-Item -ItemType Directory -Path $Path -Force | Out-Null }
}

$LogFile = Join-Path $LogPath ("RDS_Update_" + (Get-Date -Format 'yyyyMMdd') + ".log")

function Write-Log {
    param([string]$Message, [string]$Level = "INFO")
    $TimeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $LogEntry = "[$TimeStamp] [$Level] $Message"
    $LogEntry | Out-File -FilePath $LogFile -Append -Encoding UTF8
    $Color = "White"
    if ($Level -eq "ERROR") { $Color = "Red" }
    elseif ($Level -eq "SUCCESS") { $Color = "Green" }
    Write-Host $LogEntry -ForegroundColor $Color
}

Write-Log "=== Запуск RDS-автоматизации (Direct PFX Mode) ==="

try {
    Import-Module RemoteDesktop -ErrorAction Stop
    $ActiveBroker = (Get-RDServer | Where-Object { $_.Roles -contains "RDS-CONNECTION-BROKER" } | Select-Object -First 1).Server
    
    # 1. Проверка файла от win-acme
    if (!(Test-Path $SourcePfx)) { throw "Исходный PFX не найден в $SourcePfx. Проверьте настройки Store в win-acme." }
    
    # 2. Архивируем для истории
    $Timestamp = Get-Date -Format "yyyyMMdd_HHmm"
    $ArchivedPfx = Join-Path $ExportPath ("RDS_Cert_" + $Timestamp + ".pfx")
    $PassFile = Join-Path $ExportPath ("RDS_Cert_" + $Timestamp + "_pass.txt")
    
    Copy-Item $SourcePfx $ArchivedPfx -Force
    $PfxPassword | Out-File $PassFile -Encoding UTF8
    Write-Log "Архивная копия создана в $ExportPath"

    # 3. Снятие снимка ролей
    $Roles = @("RDPublishing", "RDWebAccess", "RDGateway", "RDRedirector")
    $Snapshot = @{}
    foreach ($Role in $Roles) {
        $curr = Get-RDCertificate -Role $Role -ConnectionBroker $ActiveBroker -ErrorAction SilentlyContinue
        if ($curr) { $Snapshot[$Role] = $curr.Thumbprint }
    }

    # 4. Импорт в RDS
    $SecurePassword = ConvertTo-SecureString $PfxPassword -AsPlainText -Force
    foreach ($Role in $Snapshot.Keys) {
        try {
            Write-Log ("Обновление роли: " + $Role)
            Set-RDCertificate -Role $Role -ImportPath $SourcePfx -Password $SecurePassword -ConnectionBroker $ActiveBroker -Force -ErrorAction Stop
            Write-Log ("Успешно: " + $Role) -Level "SUCCESS"
        } catch {
            Write-Log ("ОШИБКА в " + $Role + " : " + $_.Exception.Message) -Level "ERROR"
            throw "TriggerRollback"
        }
    }

    # 5. Обновление RDP Listener через WMI
    $WMIPath = (Get-WmiObject -class "Win32_TSGeneralSetting" -Namespace "root\cimv2\terminalservices" | Where-Object {$_.TerminalName -eq "RDP-Tcp"}).__path
    if ($WMIPath) {
        Set-WmiInstance -Path $WMIPath -argument @{SSLCertificateSHA1Hash=$CertThumbprint} | Out-Null
        Write-Log "RDP Listener (WMI) обновлен." -Level "SUCCESS"
    }

    Write-Log "=== ВСЕ СЛУЖБЫ ОБНОВЛЕНЫ УСПЕШНО ===" -Level "SUCCESS"

} catch {
    Write-Log ("Критический сбой: " + $_.ToString()) -Level "ERROR"
    exit 1
}

3. Настройка планировщика

Важно: в win-acme прописываем запуск скрипта с аргументом {CertThumbprint}. WACS подставит актуальный отпечаток при каждом обновлении.

Почему это работает лучше старых решений?

  1. Автономность: Мы не зависим от прав экспорта закрытого ключа из хранилища Windows — берем готовый файл.

  2. Безопасность: Скрипт сохраняет историю (PFX + пароль) в защищенную папку. Если что-то пойдет не так, у вас всегда есть бэкап для ручного отката.

  3. WMI: Скрипт корректно «подпинывает» Listener, избавляя от предупреждений при подключении.

  4. Никаких проблем с экспортом: Мы не трогаем закрытый ключ в реестре/хранилище напрямую.

  5. Гарантированная цепочка: win-acme при создании PFX-файла всегда включает в него всю цепочку Let's Encrypt корректно.

  6. Простота: Скрипт становится короче и надежнее.

Почему это сработает:

  • Мы больше не просим Windows "экспортировать" закрытый ключ — мы берем файл, который win-acme создал сразу с ключом.

  • Командлет Set-RDCertificate обожает работать с физическими файлами и паролями.

  • В папке Export будет вестись история всех сертификатов с паролями.

Итог:

  1. Вы запускаете wacs.exe, он обновляет IIS.

  2. Следующим шагом он дёргает этот скрипт.

  3. Скрипт генерирует уникальный PFX, пасс известен админу и хранится в Vault Acme

  4. Если что-то с раскаткой PFX идёт не так, файлы остаются для ручного восстановления.

  5. RDS легитимно получает новый сертификат

Когда в настройках win-acme указан запуск скрипта с параметром {CertThumbprint}, не нужно больше ничего вводить вручную.

Как это работает:

  1. Наступает срок обновления сертификата.

  2. wacs.exe по команде планировщика связывается с Let's Encrypt и получает новый сертификат.

  3. У этого нового сертификата уже есть свой уникальный отпечаток (Thumbprint).

  4. win-acme сам подставляет этот новый отпечаток вместо переменной {CertThumbprint} и запускает наш скрипт.

В планировщике, возможно, понадобится -ExecutionPolicy Bypass -File, но это ещё с прошлого раза должно быть.

И каждые три месяца win-acme будет сам «вычислять», какой там сейчас актуальный отпечаток, и передавать его в скрипт. Наша задача — только один раз настроить этот "Installation Step".


Если не до конца понятно, закрепим, как это настроить в интерфейсе win-acme (wacs.exe):

  1. Запускаем в терминале от админа .\wacs.exe.

  2. A (Manage renewals).

  3. Выбираем свой сертификат.

  4. E (Edit renewal).

  5. Соглашаемся со старыми настройками WACS с того раза, когда все ещё работало, и прощелкиваем (Enter) до шага Installation steps. Или настраиваем в первый раз.

  6. Там уже должен быть IIS. Выбери добавить еще один шаг (обычно это пункт Add installation step).

  7. И вот тут уже резвимся: укажем, где лежит PS1 скрипт и потом укажем параметры его запуска

    -CertThumbprint "{CertThumbprint}"
  8. После этого win-acme спросит, нужно ли добавить еще один шаг. No (или Enter)

  9. Save изменения (обычно это происходит автоматически при выходе в главное меню после завершения правок)

Всё. Больше руками ничего делать не придется. Раз в три месяца сертификат обновится, win-acme подставит новый отпечаток, скрипт его подхватит, создаст новый PFX в папке экспорта и обновит все роли RDS.

Ура, товарищи!

Докрутим гайки на ваших RDS фермах!

Оставляйте заявку на нашем сайте administrators.ru, или свяжитесь с нами удобным образом:

Подписывайтесь и следите за нашими анонсами в нашем телеграм канале @RuAdminGuild!

А ещё мы предлагаем бесплатный экспресс-аудит текущих процессов и систем.

На нашем сайте есть инструменты для самопроверки. Не по всем направлениям, конечно, но можно начать с тех чек-листов, которые уже есть.

Прохождение каждого чек-листа занимает всего несколько минут, приглашаем вас проверить, где вы уже защищены.

читать другие статьи

==

Мы не скрываем, что в подготовке материалов нам помогали нейросети.

Craftum Сайт создан на Craftum