А чем же плохи прежние сертификаты и решения?
Для автоматизации получения 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, а кастомный скрипт для его деплоя.
Поехали!
Когда wacs.exe --renew запускается, он:
- Проверяет, не пора ли обновить серт
- Если пора — выпускает новый
- Обновляет IIS (это у нас уже работает)
- Запускает наш скрипт (вот это мы добавим)последняя версия WACS на гитхаб
Чтобы не запутаться в интерфейсе wacs.exe, вот чек-лист настроек для Renewal (меню E — Edit):
Store Step 1: CertificateStore (основное хранилище, это для IIS, чтобы сайт RDWEB в IIS работал).
Store Step 2: PfxFile — это то, что мы добавляем для workaround.
Path: Path:\Folder-DEFstore-PFX
Password: твой фиксированный пароль (который ты вписал в скрипт как $PfxPassword = "ВашСложныйПароль" ).
Installation Step 1: IIS (обновляет биндинги на 443 порту).
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) нового сертификата, чтобы:
Записать его в лог (для сверки).
Обновить RDP Listener через WMI (он принимает именно отпечаток, а не файл).
При создании или редактировании Renewal (меню E) в win-acme, убедитесь, что PfxFile выбран в дополнение к основному хранилищу Win и задайте фиксированный пароль, можно сохранить его в Vault
А раз у нас теперь есть стабильный файл PFX с известным паролем, мы обходим все капризы хранилища сертификатов Windows
Мы немного потестировали это, ломаться тут особо нечему до следующего обновления МС :) Пока этот вариант максимально стабилен для 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
}Важно: в win-acme прописываем запуск скрипта с аргументом {CertThumbprint}. WACS подставит актуальный отпечаток при каждом обновлении.
Автономность: Мы не зависим от прав экспорта закрытого ключа из хранилища Windows — берем готовый файл.
Безопасность: Скрипт сохраняет историю (PFX + пароль) в защищенную папку. Если что-то пойдет не так, у вас всегда есть бэкап для ручного отката.
WMI: Скрипт корректно «подпинывает» Listener, избавляя от предупреждений при подключении.
Никаких проблем с экспортом: Мы не трогаем закрытый ключ в реестре/хранилище напрямую.
Гарантированная цепочка: win-acme при создании PFX-файла всегда включает в него всю цепочку Let's Encrypt корректно.
Простота: Скрипт становится короче и надежнее.
Мы больше не просим Windows "экспортировать" закрытый ключ — мы берем файл, который win-acme создал сразу с ключом.
Командлет Set-RDCertificate обожает работать с физическими файлами и паролями.
В папке Export будет вестись история всех сертификатов с паролями.
Вы запускаете wacs.exe, он обновляет IIS.
Следующим шагом он дёргает этот скрипт.
Скрипт генерирует уникальный PFX, пасс известен админу и хранится в Vault Acme
Если что-то с раскаткой PFX идёт не так, файлы остаются для ручного восстановления.
RDS легитимно получает новый сертификат
Когда в настройках win-acme указан запуск скрипта с параметром {CertThumbprint}, не нужно больше ничего вводить вручную.
Как это работает:
Наступает срок обновления сертификата.
wacs.exe по команде планировщика связывается с Let's Encrypt и получает новый сертификат.
У этого нового сертификата уже есть свой уникальный отпечаток (Thumbprint).
win-acme сам подставляет этот новый отпечаток вместо переменной {CertThumbprint} и запускает наш скрипт.
В планировщике, возможно, понадобится -ExecutionPolicy Bypass -File, но это ещё с прошлого раза должно быть.
И каждые три месяца win-acme будет сам «вычислять», какой там сейчас актуальный отпечаток, и передавать его в скрипт. Наша задача — только один раз настроить этот "Installation Step".
Запускаем в терминале от админа .\wacs.exe.
A (Manage renewals).
Выбираем свой сертификат.
E (Edit renewal).
Соглашаемся со старыми настройками WACS с того раза, когда все ещё работало, и прощелкиваем (Enter) до шага Installation steps. Или настраиваем в первый раз.
Там уже должен быть IIS. Выбери добавить еще один шаг (обычно это пункт Add installation step).
И вот тут уже резвимся: укажем, где лежит PS1 скрипт и потом укажем параметры его запуска
-CertThumbprint "{CertThumbprint}"После этого win-acme спросит, нужно ли добавить еще один шаг. No (или Enter)
Save изменения (обычно это происходит автоматически при выходе в главное меню после завершения правок)
Всё. Больше руками ничего делать не придется. Раз в три месяца сертификат обновится, win-acme подставит новый отпечаток, скрипт его подхватит, создаст новый PFX в папке экспорта и обновит все роли RDS.
Докрутим гайки на ваших RDS фермах!
Оставляйте заявку на нашем сайте administrators.ru, или свяжитесь с нами удобным образом:
звоните на +7-98-98-11-13-98 (тап),
пишите на get1@administrators.ru
Подписывайтесь и следите за нашими анонсами в нашем телеграм канале @RuAdminGuild!
На нашем сайте есть инструменты для самопроверки. Не по всем направлениям, конечно, но можно начать с тех чек-листов, которые уже есть.
Прохождение каждого чек-листа занимает всего несколько минут, приглашаем вас проверить, где вы уже защищены.==
Мы не скрываем, что в подготовке материалов нам помогали нейросети.