PowerShell ile IIS Yönetimi: WebAdministration Modülü
IIS’i GUI üzerinden yönetmek, birkaç sunucu için idare eder. Ama elinizde 20-30 sunucu varsa ve hepsinde aynı site yapılandırmasını uygulamanız gerekiyorsa, o güzel grafik arayüzü size sadece vakit kaybettirir. İşte tam bu noktada PowerShell’in WebAdministration modülü devreye giriyor ve hayatı gerçekten kolaylaştırıyor.
Bu yazıda günlük IIS yönetiminde kullandığım PowerShell komutlarını, gerçek senaryolar üzerinden paylaşacağım. Teorik anlatımdan çok, “bunu neden yapıyoruz ve nasıl yapıyoruz” odaklı gideceğiz.
WebAdministration Modülünü Tanımak
Modülü yüklemek için önce IIS’in kurulu olması gerekiyor. Windows Server’da IIS rolü kuruluyken WebAdministration modülü zaten gelir. Ama her şeyden önce modülün orada olup olmadığını kontrol etmek iyi bir alışkanlık:
# Modülün varlığını kontrol et
Get-Module -ListAvailable -Name WebAdministration
# Modülü içe aktar
Import-Module WebAdministration
# IIS sürücüsüne geç - bu çok kullanışlı bir özellik
cd IIS:
dir
IIS: sürücüsü, WebAdministration modülünün sunduğu en güzel şeylerden biri. Dosya sistemi gibi gezinebiliyorsunuz: IIS:Sites, IIS:AppPools, IIS:SslBindings gibi. Bunu ilk keşfettiğimde gerçekten etkilenmiştim, çünkü kavramsal olarak çok sezgisel.
Modülü yükledikten sonra mevcut durumu görmek için temel komutlara bakalım:
# Tüm siteleri listele
Get-Website
# Tüm uygulama havuzlarını listele
Get-WebConfiguration /system.applicationHost/applicationPools/add
# Alternatif - daha temiz çıktı
Get-ChildItem IIS:AppPools
Yeni Site Oluşturma ve Yapılandırma
Diyelim ki yeni bir web uygulaması deploy edeceksiniz. Genellikle şu adımları izleriz: uygulama havuzu oluştur, siteyi oluştur, binding’leri ayarla, izinleri ver. Bunu GUI’den yapmak 5 dakika sürer, script ile 5 saniye.
# Uygulama havuzu oluşturma
New-WebAppPool -Name "MyApp_Pool"
# Havuz ayarlarını yapılandır
Set-ItemProperty IIS:AppPoolsMyApp_Pool -Name processModel.userName -Value "IIS AppPoolMyApp_Pool"
Set-ItemProperty IIS:AppPoolsMyApp_Pool -Name managedRuntimeVersion -Value "v4.0"
Set-ItemProperty IIS:AppPoolsMyApp_Pool -Name managedPipelineMode -Value "Integrated"
# .NET Core uygulamaları için runtime'ı boş bırakıyoruz
Set-ItemProperty IIS:AppPoolsMyApp_Pool -Name managedRuntimeVersion -Value ""
# Yeni web sitesi oluştur
New-Website -Name "MyApp" `
-Port 80 `
-PhysicalPath "C:inetpubmyapp" `
-ApplicationPool "MyApp_Pool" `
-HostHeader "myapp.sirketim.com"
# Sitenin durumunu kontrol et
Get-Website -Name "MyApp"
Burada dikkat edilmesi gereken bir nokta var: -HostHeader parametresini kullanmadan site oluşturursanız, IIS tüm gelen 80 portundaki trafiği bu siteye yönlendirir. Birden fazla site varsa bu ciddi sorunlara yol açar. Her zaman host header belirtin.
SSL Binding Ekleme
HTTPS olmadan production’a site açmak artık kabul edilemez bir durum. Sertifika yönetimi ve SSL binding işlemlerini PowerShell ile nasıl yapacağınızı görelim:
# Önce sertifikaları listele
Get-ChildItem Cert:LocalMachineMy | Select-Object Subject, Thumbprint, NotAfter
# Wildcard veya spesifik sertifika bul
$cert = Get-ChildItem Cert:LocalMachineMy |
Where-Object { $_.Subject -like "*myapp.sirketim.com*" }
# HTTPS binding ekle
New-WebBinding -Name "MyApp" `
-Protocol "https" `
-Port 443 `
-HostHeader "myapp.sirketim.com" `
-SslFlags 1
# Sertifikayı binding ile ilişkilendir
$binding = Get-WebBinding -Name "MyApp" -Protocol "https"
$binding.AddSslCertificate($cert.Thumbprint, "My")
# HTTP'den HTTPS'e yönlendirme için URL Rewrite kuralı
# (URL Rewrite modülünün kurulu olduğunu varsayıyoruz)
Add-WebConfigurationProperty -PSPath "IIS:SitesMyApp" `
-Filter "system.webServer/rewrite/rules" `
-Name "." `
-Value @{
name = "HTTP to HTTPS"
stopProcessing = "True"
match = @{ url = "(.*)" }
conditions = @{ logicalGrouping = "MatchAll" }
action = @{ type = "Redirect"; redirectType = "Permanent"; url = "https://{HTTP_HOST}/{R:1}" }
}
SNI (Server Name Indication) için -SslFlags 1 kullanmak önemli. Aynı IP üzerinde birden fazla SSL sitesi barındırıyorsanız bu zorunlu hale geliyor.
Uygulama Havuzu Yönetimi
Uygulama havuzları IIS’in kalbinde yer alır. Geri dönüşüm ayarları, kimlik bilgileri, süreç modeli gibi parametreleri doğru yapılandırmak performans ve güvenlik açısından kritik.
# Belirli bir havuzun tüm ayarlarını görüntüle
Get-Item IIS:AppPoolsMyApp_Pool | Select-Object *
# Recycling ayarlarını yapılandır
# Belirli saatlerde geri dönüşüm (örneğin gece 02:00)
$recycleTime = [Microsoft.Web.Administration.ScheduleCollection]::new()
Clear-ItemProperty IIS:AppPoolsMyApp_Pool -Name recycling.periodicRestart.schedule
Add-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" `
-Filter "system.applicationHost/applicationPools/add[@name='MyApp_Pool']/recycling/periodicRestart/schedule" `
-Name "." `
-Value @{ value = "02:00:00" }
# Otomatik geri dönüşümü kapatma (bazı uygulamalar için gerekli)
Set-ItemProperty IIS:AppPoolsMyApp_Pool `
-Name recycling.periodicRestart.time `
-Value "00:00:00"
# Havuzu durdur, başlat, yeniden başlat
Stop-WebAppPool -Name "MyApp_Pool"
Start-WebAppPool -Name "MyApp_Pool"
Restart-WebAppPool -Name "MyApp_Pool"
# Tüm durdurulmuş havuzları başlat
Get-ChildItem IIS:AppPools |
Where-Object { $_.State -eq "Stopped" } |
ForEach-Object { Start-WebAppPool $_.Name }
Bir gerçek dünya senaryosu: Geçen yıl bir e-ticaret sitesinde gece yarısı tüm uygulama havuzlarının durduğunu gördük. Alarm geldi, müdahale ettik. Sorunun ne olduğunu araştırırken toplu başlatma scripti hayat kurtardı. Sabah mesaiye gelenlerin haberi bile olmadı.
Web.config Yönetimi
Web.config dosyalarını doğrudan düzenlemek yerine PowerShell komutlarıyla yönetmek, hem tutarlılık sağlar hem de hataların önüne geçer. XML formatında yapılan manuel düzenlemelerde bir virgül, bir etiket hatası sitenizi çökertebilir.
# Connection string ekle veya güncelle
Set-WebConfigurationProperty `
-PSPath "IIS:SitesMyApp" `
-Filter "connectionStrings/add[@name='DefaultConnection']" `
-Name "." `
-Value @{
name = "DefaultConnection"
connectionString = "Server=sql01;Database=MyAppDB;Integrated Security=True;"
providerName = "System.Data.SqlClient"
}
# AppSettings değeri ekle
Set-WebConfigurationProperty `
-PSPath "IIS:SitesMyApp" `
-Filter "appSettings" `
-Name "." `
-Value @{ key = "Environment"; value = "Production" }
# Mevcut bir appSettings değerini oku
Get-WebConfigurationProperty `
-PSPath "IIS:SitesMyApp" `
-Filter "appSettings/add[@key='Environment']" `
-Name "value"
# Özel hata sayfası ekle
Set-WebConfiguration `
-PSPath "IIS:SitesMyApp" `
-Filter "system.web/customErrors" `
-Value @{ mode = "On"; defaultRedirect = "/error.html" }
Sertifika Sona Erme Takibi
Bu senaryo çok yaşandı, çok canlar yandı. Production’da SSL sertifikası doldu, site HTTPS üzerinden erişilemez hale geldi, telefon yağmuruna tutuldunuz. Önleyici bir script şöyle olabilir:
# 30 gün içinde sona erecek sertifikaları bul ve raporla
$threshold = (Get-Date).AddDays(30)
$expiringSoon = Get-ChildItem Cert:LocalMachineMy |
Where-Object { $_.NotAfter -lt $threshold -and $_.NotAfter -gt (Get-Date) }
if ($expiringSoon.Count -gt 0) {
$report = $expiringSoon | ForEach-Object {
[PSCustomObject]@{
Subject = $_.Subject
Thumbprint = $_.Thumbprint
ExpiresOn = $_.NotAfter
DaysLeft = ($_.NotAfter - (Get-Date)).Days
}
}
# Hangi siteler bu sertifikaları kullanıyor?
foreach ($cert in $expiringSoon) {
$sites = Get-ChildItem IIS:SslBindings |
Where-Object { $_.CertificateHash -eq $cert.Thumbprint }
Write-Warning "Sertifika '$($cert.Subject)' $($cert.NotAfter) tarihinde sona eriyor!"
Write-Warning "Etkilenen siteler: $($sites.Sites -join ', ')"
}
# E-posta bildirimi göndermek isterseniz
# Send-MailMessage -To "[email protected]" -Subject "SSL Sertifika Uyarısı" ...
}
Bu scripti Task Scheduler’a günlük çalışacak şekilde ekleyin. Sertifika yenilemeyi unutmanız mümkün olmaz.
Toplu Yapılandırma Dağıtımı
Birden fazla sunucuda aynı yapılandırmayı uygulamak gerçek bir sysadmin senaryosu. Örneğin 10 web sunucusuna aynı anda yeni bir site deploy etmeniz gerekiyor:
# Sunucu listesi
$servers = @("web01", "web02", "web03", "web04", "web05")
# Her sunucuda çalıştırılacak script bloğu
$deployScript = {
param($siteName, $physicalPath, $appPoolName, $port, $hostHeader)
Import-Module WebAdministration
# Dizin oluştur
if (-not (Test-Path $physicalPath)) {
New-Item -ItemType Directory -Path $physicalPath -Force
}
# Uygulama havuzu oluştur (yoksa)
if (-not (Test-Path "IIS:AppPools$appPoolName")) {
New-WebAppPool -Name $appPoolName
Set-ItemProperty "IIS:AppPools$appPoolName" `
-Name managedRuntimeVersion `
-Value ""
}
# Site oluştur (yoksa)
if (-not (Get-Website -Name $siteName)) {
New-Website -Name $siteName `
-Port $port `
-PhysicalPath $physicalPath `
-ApplicationPool $appPoolName `
-HostHeader $hostHeader
Write-Output "[$env:COMPUTERNAME] Site '$siteName' oluşturuldu."
} else {
Write-Output "[$env:COMPUTERNAME] Site '$siteName' zaten mevcut."
}
}
# Parametreler
$params = @{
siteName = "NewApp"
physicalPath = "C:inetpubnewapp"
appPoolName = "NewApp_Pool"
port = 80
hostHeader = "newapp.sirketim.com"
}
# Tüm sunucularda çalıştır
$results = Invoke-Command -ComputerName $servers `
-ScriptBlock $deployScript `
-ArgumentList $params.Values
$results | Format-Table PSComputerName, * -AutoSize
Bu yaklaşımın güzelliği: Invoke-Command paralel çalışır, yani 10 sunucuya aynı anda komutu gönderir. Sırayla yapıyor olsaydınız aldığınız süre 10 katına çıkardı.
IIS Log Analizi
IIS logları sorun giderme için altın değerinde. PowerShell ile logları analiz etmek, log yönetim aracı satın almak zorunda kalmadan büyük içgörüler sağlayabilir:
# Son 1 saatin loglarını analiz et
$logPath = "C:inetpublogsLogFilesW3SVC1"
$oneHourAgo = (Get-Date).AddHours(-1)
# Son log dosyasını bul
$latestLog = Get-ChildItem $logPath -Filter "*.log" |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1
# Log satırlarını parse et
$logEntries = Get-Content $latestLog.FullName |
Where-Object { $_ -notmatch "^#" } | # Başlık satırlarını atla
ForEach-Object {
$parts = $_ -split " "
[PSCustomObject]@{
Date = $parts[0]
Time = $parts[1]
ClientIP = $parts[8]
Method = $parts[5]
URI = $parts[6]
StatusCode = $parts[12]
TimeTaken = [int]$parts[17]
}
}
# HTTP 500 hatalarını listele
Write-Host "=== Son 1 Saatin 500 Hataları ===" -ForegroundColor Red
$logEntries | Where-Object { $_.StatusCode -eq "500" } |
Select-Object Time, ClientIP, Method, URI, StatusCode |
Format-Table -AutoSize
# En yavaş istekler (ms cinsinden)
Write-Host "`n=== En Yavaş 10 İstek ===" -ForegroundColor Yellow
$logEntries | Sort-Object TimeTaken -Descending |
Select-Object -First 10 |
Select-Object Time, Method, URI, StatusCode, TimeTaken |
Format-Table -AutoSize
# IP bazında istek sayısı (DDoS tespiti için kullanışlı)
Write-Host "`n=== IP Bazında İstek Sayısı (Top 10) ===" -ForegroundColor Cyan
$logEntries | Group-Object ClientIP |
Sort-Object Count -Descending |
Select-Object -First 10 |
Select-Object Name, Count |
Format-Table -AutoSize
Yedekleme ve Geri Yükleme
IIS yapılandırmasını yedeklemek, felaket senaryolarında hayat kurtarır. Bunu otomatize etmemek için hiçbir neden yok:
# IIS yapılandırmasını yedekle
$backupName = "Backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
Backup-WebConfiguration -Name $backupName
# Yedekleri listele
Get-WebConfigurationBackup
# Belirli bir yedeği geri yükle
Restore-WebConfiguration -Name $backupName
# Eski yedekleri temizle (30 günden eski olanları sil)
$cutoffDate = (Get-Date).AddDays(-30)
Get-WebConfigurationBackup |
Where-Object { $_.CreationDate -lt $cutoffDate } |
ForEach-Object { Remove-WebConfigurationBackup -Name $_.Name }
Backup-WebConfiguration komutu, %WINDIR%System32inetsrvbackup dizinine tam yapılandırmayı kaydeder. applicationHost.config, root web.config ve diğer kritik dosyaları içerir. Bunu günlük çalışacak şekilde Task Scheduler’a ekleyin, nokta.
Sağlık Kontrolü Script’i
Günlük monitoring için tüm sitelerin ve havuzların durumunu kontrol eden bir script:
# IIS Sağlık Kontrol Scripti
function Get-IISHealthReport {
Import-Module WebAdministration
$issues = @()
# Durdurulmuş siteleri kontrol et
$stoppedSites = Get-Website | Where-Object { $_.State -ne "Started" }
foreach ($site in $stoppedSites) {
$issues += [PSCustomObject]@{
Type = "SITE"
Name = $site.Name
Status = $site.State
Severity = "CRITICAL"
}
}
# Durdurulmuş havuzları kontrol et
$stoppedPools = Get-ChildItem IIS:AppPools |
Where-Object { $_.State -ne "Started" }
foreach ($pool in $stoppedPools) {
$issues += [PSCustomObject]@{
Type = "APPPOOL"
Name = $pool.Name
Status = $pool.State
Severity = "CRITICAL"
}
}
# Disk kullanımını kontrol et (log dizini için)
$logDisk = Get-PSDrive C
$freeGB = [math]::Round($logDisk.Free / 1GB, 2)
if ($freeGB -lt 5) {
$issues += [PSCustomObject]@{
Type = "DISK"
Name = "C: Drive"
Status = "$freeGB GB serbest"
Severity = if ($freeGB -lt 2) { "CRITICAL" } else { "WARNING" }
}
}
if ($issues.Count -eq 0) {
Write-Host "[$env:COMPUTERNAME] Tüm IIS servisleri normal çalışıyor." -ForegroundColor Green
} else {
Write-Host "[$env:COMPUTERNAME] $($issues.Count) sorun tespit edildi:" -ForegroundColor Red
$issues | Format-Table -AutoSize
}
return $issues
}
Get-IISHealthReport
Sonuç
WebAdministration modülü, IIS yönetimini gerçek anlamda ölçeklenebilir hale getiriyor. Bu yazıda ele aldığımız konular, günlük işlerin büyük çoğunluğunu kapsıyor: site ve havuz oluşturma, SSL yönetimi, log analizi, yedekleme ve sağlık kontrolü.
Buradaki scriptleri doğrudan kopyalayıp kullanabilirsiniz, ama asıl amaç bu değil. Her ortam farklıdır, her organizasyonun ihtiyaçları farklıdır. Bu örnekleri kendi senaryolarınıza uyarlayın, modüle edin ve bir script kütüphanesi oluşturun.
Özellikle şunu vurgulamak isterim: Tekrarlayan işleri otomatize etmemek artık kabul edilemez bir lüks. GUI’den tek tek yapılandırma yapıyorsanız, o süreyi bir kez script yazarak geçirin. Sonraki onlarca seferinde o süreyi başka şeylere harcayın.
Son bir not: Tüm bu scriptleri bir versiyon kontrol sisteminde (Git) saklayın. Bir ayda bir geri bakıp “bunu neden böyle yazdım” diye sormaktan kurtulursunuz, meslektaşlarınız da aynı işi tekrar yapmak zorunda kalmaz.
