Exchange Receive Connector’e TLS Sertifikası Atanması
Exchange Server’da, kimlik doğrulamalı SMTP istemci bağlantılarının TLS ile şifrelenmesi güvenli e-posta iletişimi için önemlidir. Özellikle IMAP veya POP istemcileri e-posta göndermek için Exchange’i SMTP sunucusu olarak kullandığında bu gereklidir.
İstemci şifrelenmemiş bir bağlantı üzerinden kimlik doğrulamaya çalıştığında şuna benzer bir hata alabilir:
The outgoing server (SMTP) smtp.example.com does not support the selected authentication method.
Çözüm, istemcinin STARTTLS ile güvenli kimlik doğrulaması yapması ve alıcı bağlayıcısının (receive connector) doğru TLS sertifika adıyla yapılandırılmasıdır. Örneğin Mozilla Thunderbird’de giden sunucu ayarlarında STARTTLS ve 587 portu kullanılabilir.
Sertifika güven/hata sorunları yaşanıyorsa, ilgili receive connector’a doğru sertifika atanmalıdır.
Manuel Adımlar
- Sertifikayı belirle. Sunucudaki sertifikaları listele ve kullanacağın sertifikanın thumbprint değerini not et:
Get-ExchangeCertificate | Select FriendlyName, Services, Thumbprint, NotAfter | ft -AutoSize
- Sertifikayı bir değişkene ata:
$cert = Get-ExchangeCertificate -Thumbprint
- TLS sertifika adını oluştur (issuer + subject bilgisinden):
$tlscertificatename = "$($cert.Issuer)$($cert.Subject)"
- Receive connector’a ata:
Set-ReceiveConnector "Client Frontend " -TlsCertificateName $tlscertificatename
Birden fazla sunucu veya connector varsa, bu adımların her biri için tekrarlanması gerekir.
Birden fazla sunucu veya connector varsa, bu adımların her biri için tekrarlanması gerekir.
Not: WARNING: The command completed successfully but no settings … have been modified mesajı bir hata değildir; ilgili connector’da zaten aynı sertifikanın atalı olduğu anlamına gelir.
Otomasyon Scripti
Aşağıdaki PowerShell scripti bu işlemi uçtan uca otomatikleştirir:
- Sertifikayı otomatik bulur: SMTP + IMAP + POP + IIS hizmetlerinin dördü birden atanmış ve süresi geçmemiş, en güncel (en geç dolacak) sertifikayı seçer. İstenirse
-Thumbprintile manuel de verilebilir. - Onay ekranı gösterir: Uygulamadan önce seçilen sertifikanın tüm detaylarını (FriendlyName, Issuer, Subject, geçerlilik tarihleri, kalan gün, atanmış domainler/SAN’lar, hizmetler) listeler ve onay ister.
- Sunucuları dinamik bulur:
Get-ExchangeServerile tüm sunucuları alır; her birindekiClient Frontend SUNUCUADIconnector’ını otomatik hedefler. - Güvenli çalışır:
-WhatIfile önizleme yapar, zaten doğru sertifika atanmış connector’lara dokunmaz ve her çalıştırmada tarih damgalı bir log dosyası bırakır.
Kullanım
# Önizleme (hiçbir değişiklik yapmaz)
.\Set-ClientFrontendTlsCert.ps1 -WhatIf
# Otomatik sertifika seçimi + onay ekranı
.\Set-ClientFrontendTlsCert.ps1
# Belirli bir thumbprint sabitle
.\Set-ClientFrontendTlsCert.ps1 -Thumbprint <THUMBPRINT>
# Sadece belirli sunucular
.\Set-ClientFrontendTlsCert.ps1 -Server MBX01,MBX02
# Onay ekranını atla (otomasyon / zamanlanmış görev)
.\Set-ClientFrontendTlsCert.ps1 -Force
Script
<#
.SYNOPSIS
Client Frontend Receive Connector'lara TLS sertifikasini otomatik atar.
.DESCRIPTION
Tum Exchange sunucularini bulur, her birindeki "Client Frontend <SERVER>"
receive connector'ini tespit eder ve secilen sertifikadan uretilen
TlsCertificateName degerini atar.
Sertifika belirtilmezse, SMTP + IMAP + POP + IIS hizmetlerinin dordu birden
atanmis ve suresi gecerli olan sertifika otomatik secilir. Birden fazla varsa
en gec dolacak (en guncel) olan tercih edilir.
Sertifika secildikten sonra, uygulama yapilmadan once tum detaylari
(FriendlyName, Issuer, Subject, gecerlilik tarihleri, atanmis domainler/SAN'lar,
hizmetler) bir onay ekraninda gosterilir ve kullanicidan onay istenir.
.PARAMETER Thumbprint
Kullanilacak sertifikanin thumbprint'i. Belirtilmezse otomatik secim yapilir.
.PARAMETER Server
Sadece belirli sunucular icin calistirmak istersen. Bos birakilirsa hepsi islenir.
.PARAMETER Force
Onay ekranini atlar ve dogrudan uygular. Otomasyon/zamanlanmis gorevlerde kullanilir.
.PARAMETER WhatIf
Degisiklikleri uygulamadan ne yapilacagini gosterir.
.EXAMPLE
.\Set-ClientFrontendTlsCert.ps1
Sertifikayi otomatik secer, onay sorar ve tum sunuculara uygular.
.EXAMPLE
.\Set-ClientFrontendTlsCert.ps1 -Thumbprint 1234567890ABCDEF1234567890ABCDEF12345678
.EXAMPLE
.\Set-ClientFrontendTlsCert.ps1 -WhatIf
Sadece onizleme, degisiklik yapmaz.
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param(
[Parameter(Mandatory = $false)]
[string]$Thumbprint,
[Parameter(Mandatory = $false)]
[string[]]$Server,
[Parameter(Mandatory = $false)]
[switch]$Force
)
$ErrorActionPreference = 'Stop'
# --- Log dosyasi ---
$logFile = Join-Path -Path $PSScriptRoot -ChildPath ("TlsCertUpdate_{0:yyyyMMdd_HHmmss}.log" -f (Get-Date))
function Write-Log {
param([string]$Message, [string]$Level = 'INFO')
$line = "{0} [{1}] {2}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Level, $Message
Write-Host $line
Add-Content -Path $logFile -Value $line
}
try {
# Tum forest'i gormek icin
Write-Log "Set-ADServerSettings -ViewEntireForest `$true"
Set-ADServerSettings -ViewEntireForest $true
# --- Sertifikayi sec ---
if ($Thumbprint) {
$cert = Get-ExchangeCertificate -Thumbprint $Thumbprint
if (-not $cert) { throw "Belirtilen thumbprint ile sertifika bulunamadi: $Thumbprint" }
Write-Log "Sertifika thumbprint ile secildi: $Thumbprint"
}
else {
Write-Log "Thumbprint verilmedi. SMTP + IMAP + POP + IIS atanmis, gecerli sertifika araniyor..."
$requiredServices = @('SMTP', 'IMAP', 'POP', 'IIS')
$cert = Get-ExchangeCertificate |
Where-Object {
$svc = [string]$_.Services
$_.NotAfter -gt (Get-Date) -and
(@($requiredServices | Where-Object { $svc -match $_ }).Count -eq $requiredServices.Count)
} |
Sort-Object NotAfter -Descending |
Select-Object -First 1
if (-not $cert) {
throw "SMTP + IMAP + POP + IIS dordu birden atanmis, gecerli sertifika bulunamadi. -Thumbprint ile manuel belirtin."
}
Write-Log "Otomatik secilen sertifika: '$($cert.FriendlyName)' | Thumbprint: $($cert.Thumbprint) | Bitis: $($cert.NotAfter)"
}
# Sertifika bitis uyarisi
$daysLeft = ($cert.NotAfter - (Get-Date)).Days
if ($daysLeft -lt 30) {
Write-Log "DIKKAT: Sertifikanin bitisine $daysLeft gun kaldi ($($cert.NotAfter))." 'WARN'
}
# TlsCertificateName degerini olustur: <I>issuer<S>subject
$tlsCertificateName = "<I>$($cert.Issuer)<S>$($cert.Subject)"
Write-Log "TlsCertificateName: $tlsCertificateName"
# --- Sertifikaya atanmis domainleri (SAN) topla ---
$domains = @()
if ($cert.CertificateDomains) {
$domains = @($cert.CertificateDomains | ForEach-Object { $_.ToString() })
}
# --- Onay ekrani ---
$sep = ('=' * 70)
Write-Host ""
Write-Host $sep -ForegroundColor Cyan
Write-Host " SECILEN SERTIFIKA - LUTFEN KONTROL EDIN" -ForegroundColor Cyan
Write-Host $sep -ForegroundColor Cyan
Write-Host (" FriendlyName : {0}" -f $cert.FriendlyName)
Write-Host (" Thumbprint : {0}" -f $cert.Thumbprint)
Write-Host (" Issuer : {0}" -f $cert.Issuer)
Write-Host (" Subject : {0}" -f $cert.Subject)
Write-Host (" Hizmetler : {0}" -f $cert.Services)
Write-Host (" Gecerli Bas. : {0}" -f $cert.NotBefore)
$color = if ($daysLeft -lt 30) { 'Yellow' } else { 'Green' }
Write-Host (" Bitis Tarihi : {0} ({1} gun kaldi)" -f $cert.NotAfter, $daysLeft) -ForegroundColor $color
Write-Host (" Self-Signed : {0}" -f $cert.IsSelfSigned)
Write-Host " Domainler / SAN:"
if ($domains.Count -gt 0) {
$domains | ForEach-Object { Write-Host (" - {0}" -f $_) }
}
else {
Write-Host " (domain bilgisi bulunamadi)"
}
Write-Host ""
Write-Host (" Uygulanacak TlsCertificateName:")
Write-Host (" {0}" -f $tlsCertificateName) -ForegroundColor Gray
Write-Host $sep -ForegroundColor Cyan
Write-Host ""
if (-not $Force) {
$answer = Read-Host "Bu sertifikayi Client Frontend connector'lara atamak istiyor musunuz? (E/H)"
if ($answer -notmatch '^(e|evet|y|yes)$') {
Write-Log "Kullanici islemi iptal etti." 'CANCEL'
Write-Host "Islem iptal edildi." -ForegroundColor Yellow
return
}
}
else {
Write-Log "-Force belirtildi, onay ekrani atlandi."
}
# --- Sunuculari al ---
$servers = Get-ExchangeServer
if ($Server) {
$servers = $servers | Where-Object { $_.Name -in $Server }
}
if (-not $servers) { throw "Islenecek Exchange sunucusu bulunamadi." }
Write-Log ("Islenecek sunucular: {0}" -f (($servers | Select-Object -ExpandProperty Name) -join ', '))
# --- Her sunucudaki Client Frontend connector'i guncelle ---
$summary = @()
foreach ($srv in $servers) {
$connectorId = "$($srv.Name)\Client Frontend $($srv.Name)"
try {
$connector = Get-ReceiveConnector -Identity $connectorId -ErrorAction Stop
# Zaten ayarli mi?
if ($connector.TlsCertificateName -eq $tlsCertificateName) {
Write-Log "[$($srv.Name)] Zaten dogru sertifika atanmis, atlaniyor." 'SKIP'
$summary += [pscustomobject]@{ Server = $srv.Name; Status = 'AlreadySet' }
continue
}
if ($PSCmdlet.ShouldProcess($connectorId, "TlsCertificateName ayarla")) {
Set-ReceiveConnector -Identity $connectorId -TlsCertificateName $tlsCertificateName
Write-Log "[$($srv.Name)] Sertifika atandi." 'OK'
$summary += [pscustomobject]@{ Server = $srv.Name; Status = 'Updated' }
}
else {
Write-Log "[$($srv.Name)] (WhatIf) Atanacakti." 'WHATIF'
$summary += [pscustomobject]@{ Server = $srv.Name; Status = 'WhatIf' }
}
}
catch {
Write-Log "[$($srv.Name)] HATA: $($_.Exception.Message)" 'ERROR'
$summary += [pscustomobject]@{ Server = $srv.Name; Status = "Error: $($_.Exception.Message)" }
}
}
Write-Log "----- OZET -----"
$summary | Format-Table -AutoSize | Out-String | ForEach-Object { Write-Host $_ }
Write-Log "Islem tamamlandi. Log: $logFile"
}
catch {
Write-Log "KRITIK HATA: $($_.Exception.Message)" 'FATAL'
throw
}
Notlar
- Script Exchange Management Shell üzerinde çalıştırılmalıdır.
- İlk çalıştırmada mutlaka
-WhatIfile önizleme yapılması önerilir. - Connector kimliği Client Frontend SUNUCUADI kalıbına göre kurulur. Farklı isimlendirme kullanan ortamlarda script buna göre uyarlanmalıdır.
- Sertifika ataması sonrası bazı ortamlarda ilgili transport servisinin yeniden başlatılması gerekebilir; bu adım mail akışını kesebileceğinden bilinçli olarak scripte dahil edilmemiştir.