İçeriğe atla
Sistem Günlüğü Teknik notlar ve Tecrübeler..
MICROSOFT EXCHANGE 7 dk okuma

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

  1. Sertifikayı belirle. Sunucudaki sertifikaları listele ve kullanacağın sertifikanın thumbprint değerini not et:
Get-ExchangeCertificate | Select FriendlyName, Services, Thumbprint, NotAfter | ft -AutoSize
  1. Sertifikayı bir değişkene ata:
$cert = Get-ExchangeCertificate -Thumbprint
  1. TLS sertifika adını oluştur (issuer + subject bilgisinden):
$tlscertificatename = "$($cert.Issuer)$($cert.Subject)"
  1. 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 -Thumbprint ile 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-ExchangeServer ile tüm sunucuları alır; her birindeki Client Frontend SUNUCUADI connector’ını otomatik hedefler.
  • Güvenli çalışır: -WhatIf ile ö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 -WhatIf ile ö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.

Yorum yaz

Üye olmadan yorum yazabilirsin. Yorumlar onaylandıktan sonra yayınlanır.