Windows ortamlarında servis yönetimi, her sysadmin’in günlük rutininin ayrılmaz bir parçası. GUI üzerinden servis konsolunu açıp tek tek tıklamak bir süre sonra hem zaman kaybı hem de hata riski yaratıyor. PowerShell ile bu işlemleri otomatize etmek, toplu yönetim yapmak ve hatta servis sağlığını proaktif olarak izlemek mümkün. Bu yazıda Windows servislerini PowerShell ile yönetmenin tüm inceliklerini, gerçek dünya senaryolarıyla birlikte ele alacağız.
Temel Servis Yönetim Cmdlet’leri
PowerShell’de servis yönetimi için birkaç temel cmdlet var. Bunları iyi bilmek, günlük işlerinizi ciddi ölçüde hızlandırır.
Get-Service ile Servis Bilgisi Almak
Her şey önce durumu görmekle başlar. Get-Service cmdlet’i sisteminizde çalışan, durmuş veya askıya alınmış tüm servisleri listeler.
# Tüm servisleri listele
Get-Service
# Belirli bir servisi sorgula
Get-Service -Name "wuauserv"
# Wildcard ile arama
Get-Service -Name "win*"
# Duruma göre filtrele - sadece çalışan servisler
Get-Service | Where-Object {$_.Status -eq "Running"}
# Sadece durmuş servisler
Get-Service | Where-Object {$_.Status -eq "Stopped"}
Get-Service çıktısında üç temel kolon görürsünüz: Status, Name ve DisplayName. Status değerleri şunlar olabilir:
- Running: Servis aktif çalışıyor
- Stopped: Servis durdurulmuş
- Paused: Servis askıya alınmış
- StartPending: Servis başlatılıyor
- StopPending: Servis durduruluyor
Servis Başlatma, Durdurma ve Yeniden Başlatma
# Servisi başlat
Start-Service -Name "wuauserv"
# Servisi durdur
Stop-Service -Name "wuauserv"
# Servisi yeniden başlat
Restart-Service -Name "Spooler"
# Bağımlı servisleri de zorla durdur
Stop-Service -Name "wuauserv" -Force
# Servis durumunu askıya al (servis destekliyorsa)
Suspend-Service -Name "Spooler"
# Askıya alınan servisi devam ettir
Resume-Service -Name "Spooler"
Burada dikkat etmeniz gereken bir nokta var: Stop-Service bazen bağımlı servisler olduğunda hata verir. -Force parametresini kullanmak bağımlı servisleri de durdurur, ama üretim ortamında bunu dikkatli kullanın. Hangi servislerin etkileneceğini önceden kontrol etmek iyi bir alışkanlık.
Servis Yapılandırmasını Değiştirmek
Set-Service ile Servis Ayarlarını Düzenlemek
Set-Service cmdlet’i servis başlangıç tipini, açıklamasını ve görünen adını değiştirmenize olanak tanır.
# Servis başlangıç tipini değiştir
Set-Service -Name "wuauserv" -StartupType Disabled
Set-Service -Name "wuauserv" -StartupType Manual
Set-Service -Name "wuauserv" -StartupType Automatic
# Otomatik (Gecikmeli Başlangıç) için
Set-Service -Name "wuauserv" -StartupType AutomaticDelayedStart
# Servis açıklamasını güncelle
Set-Service -Name "MyService" -Description "Bu servis uygulama X için çalışır"
# Servis görünen adını değiştir
Set-Service -Name "MyService" -DisplayName "Uygulama X Servisi"
StartupType parametresi için geçerli değerler:
- Automatic: Sistem açılışında otomatik başlar
- AutomaticDelayedStart: Sistem açılışından sonra gecikmeli başlar
- Manual: Elle başlatılır
- Disabled: Devre dışı, başlatılamaz
- Boot: Sistem yükleyicisi tarafından başlatılır (sürücüler için)
- System: Kernel başlatması sırasında çalışır
Servis Kimlik Bilgilerini Değiştirmek
Servis hesabını değiştirmeniz gerektiğinde, özellikle domain ortamlarında bu oldukça yaygın bir ihtiyaç:
# Servis çalıştırma hesabını değiştir
$credential = Get-Credential
Set-Service -Name "MyService" -Credential $credential
# Script içinde kullanmak için (şifreyi güvenli şekilde sakla)
$password = ConvertTo-SecureString "P@ssw0rd123" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential("DOMAINserviceaccount", $password)
Set-Service -Name "MyService" -Credential $credential
Prodüksiyonda şifreleri düz metin olarak script’e yazmayın. Bunun yerine Windows Credential Manager veya bir secrets yönetim çözümü kullanın. Bu konuya aşağıda biraz daha değineceğiz.
Uzak Sunucularda Servis Yönetimi
Gerçek sysadmin hayatında onlarca, belki yüzlerce sunucuyu yönetiyorsunuz. Her birine RDP açıp servis konsolunu açmak zaman kaybı. PowerShell’in uzak yönetim kapasitesi burada devreye giriyor.
# Uzak sunucuda tek bir servisin durumunu kontrol et
Get-Service -ComputerName "SERVER01" -Name "wuauserv"
# Birden fazla sunucuda aynı anda kontrol
$servers = @("SERVER01", "SERVER02", "SERVER03", "SERVER04")
Get-Service -ComputerName $servers -Name "Spooler" |
Select-Object MachineName, Name, Status |
Format-Table -AutoSize
# Uzak sunucuda servis yeniden başlat
Invoke-Command -ComputerName "SERVER01" -ScriptBlock {
Restart-Service -Name "Spooler" -Force
}
# Birden fazla sunucuda paralel yeniden başlatma
$servers = @("SERVER01", "SERVER02", "SERVER03")
Invoke-Command -ComputerName $servers -ScriptBlock {
Restart-Service -Name "wuauserv"
Write-Output "$env:COMPUTERNAME - wuauserv yeniden başlatıldı"
}
-ComputerName parametresini kullanmak için hedef sunucularda WinRM’in aktif olması gerekir. WinRM yapılandırması için domain ortamında Group Policy kullanmak en temiz yol.
Gerçek Dünya Senaryo 1: Toplu Servis Sağlık Kontrolü
Sabah işe geldiniz, uygulamanın bir parçası düzgün çalışmıyor gibi görünüyor. Birden fazla sunucuda ilgili servislerin durumunu hızlıca kontrol etmeniz gerekiyor. İşte bunun için kullanabileceğiniz kapsamlı bir script:
# Çoklu sunucularda servis sağlık raporu oluştur
$servers = @("APP01", "APP02", "APP03", "DB01")
$criticalServices = @("wuauserv", "Spooler", "W32tm", "Dnscache", "LanmanServer")
$results = @()
foreach ($server in $servers) {
foreach ($service in $criticalServices) {
try {
$svc = Get-Service -ComputerName $server -Name $service -ErrorAction Stop
$results += [PSCustomObject]@{
Sunucu = $server
Servis = $service
Durum = $svc.Status
Başlangıç = $svc.StartType
Sağlık = if ($svc.Status -eq "Running") { "OK" } else { "DIKKAT" }
}
}
catch {
$results += [PSCustomObject]@{
Sunucu = $server
Servis = $service
Durum = "ERIŞILEMEZ"
Başlangıç = "Bilinmiyor"
Sağlık = "KRITIK"
}
}
}
}
# Sonuçları ekrana yaz
$results | Format-Table -AutoSize
# Sorunlu servisleri filtrele
$problemler = $results | Where-Object { $_.Sağlık -ne "OK" }
if ($problemler) {
Write-Host "`nDikkat Gerektiren Servisler:" -ForegroundColor Red
$problemler | Format-Table -AutoSize
}
# HTML rapor olarak kaydet
$results | ConvertTo-Html -Title "Servis Sağlık Raporu" |
Out-File "C:ReportsServisRaporu_$(Get-Date -Format 'yyyyMMdd').html"
Bu script’i her sabah otomatik çalıştırmak için Windows Task Scheduler’a ekleyebilirsiniz. Kritik servisler durmuşsa bunu HTML raporda hemen görürsünüz.
Gerçek Dünya Senaryo 2: Otomatik Servis İzleme ve Yeniden Başlatma
Bazı servisler zaman zaman çöküyor ve yeniden başlatmayı bekliyor. Windows’un kendi kurtarma mekanizması var ama PowerShell ile daha özelleştirilebilir bir izleme sistemi kurabilirsiniz:
# Kritik servis izleme ve otomatik kurtarma scripti
param(
[string]$ServiceName = "MyApplicationService",
[string]$LogPath = "C:LogsServisIzleme.log",
[int]$CheckInterval = 60, # Saniye cinsinden kontrol aralığı
[int]$MaxRetry = 3
)
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logEntry = "[$timestamp] [$Level] $Message"
Add-Content -Path $LogPath -Value $logEntry
switch ($Level) {
"ERROR" { Write-Host $logEntry -ForegroundColor Red }
"WARNING" { Write-Host $logEntry -ForegroundColor Yellow }
default { Write-Host $logEntry }
}
}
function Test-ServiceHealth {
param([string]$Name)
$svc = Get-Service -Name $Name -ErrorAction SilentlyContinue
return $svc
}
$retryCount = 0
Write-Log "Servis izleme başlatıldı: $ServiceName"
while ($true) {
$service = Test-ServiceHealth -Name $ServiceName
if ($null -eq $service) {
Write-Log "Servis bulunamadı: $ServiceName" -Level "ERROR"
break
}
if ($service.Status -ne "Running") {
Write-Log "Servis çalışmıyor! Durum: $($service.Status)" -Level "WARNING"
if ($retryCount -lt $MaxRetry) {
$retryCount++
Write-Log "Yeniden başlatma deneniyor... ($retryCount/$MaxRetry)" -Level "WARNING"
try {
Start-Service -Name $ServiceName -ErrorAction Stop
Start-Sleep -Seconds 10
$checkService = Get-Service -Name $ServiceName
if ($checkService.Status -eq "Running") {
Write-Log "Servis başarıyla yeniden başlatıldı."
$retryCount = 0
}
else {
Write-Log "Servis başlatılamadı!" -Level "ERROR"
}
}
catch {
Write-Log "Hata: $($_.Exception.Message)" -Level "ERROR"
}
}
else {
Write-Log "Maksimum yeniden deneme sayısına ulaşıldı! Manuel müdahale gerekli." -Level "ERROR"
# Burada e-posta veya Slack bildirimi gönderilebilir
break
}
}
else {
Write-Log "Servis normal çalışıyor."
$retryCount = 0
}
Start-Sleep -Seconds $CheckInterval
}
Bu script’i çalıştırmak için: .ServisIzleme.ps1 -ServiceName "Spooler" -CheckInterval 30
Yeni Servis Oluşturma ve Silme
New-Service ile Servis Kaydetmek
Kendi yazdığınız uygulamayı veya bir batch script’i Windows servisi olarak kaydetmek için:
# Temel servis oluşturma
New-Service -Name "MyAppService" `
-BinaryPathName "C:AppsMyAppmyapp.exe" `
-DisplayName "Uygulama X Servisi" `
-Description "Bu servis uygulama X'in arka plan işlemlerini yönetir" `
-StartupType Automatic
# PowerShell script'ini servis olarak çalıştırma (NSSM ile daha iyi ama native yol)
# Önce NSSM indirin ya da sc.exe kullanın
$binaryPath = "C:WindowsSystem32WindowsPowerShellv1.0powershell.exe -ExecutionPolicy Bypass -File C:ScriptsMyService.ps1"
New-Service -Name "PSService" `
-BinaryPathName $binaryPath `
-DisplayName "PowerShell Servis" `
-StartupType Automatic
# Servisi belirli bir hesapla çalıştır
$password = ConvertTo-SecureString "ServicePass123!" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential("DOMAINsvcaccount", $password)
New-Service -Name "MySecureService" `
-BinaryPathName "C:Appsservice.exe" `
-DisplayName "Güvenli Uygulama Servisi" `
-Credential $cred `
-StartupType Automatic
# Servis oluşturduktan sonra başlat
Start-Service -Name "MyAppService"
Servis Silmek
Windows Server 2019 ve PowerShell 6+ ile birlikte Remove-Service cmdlet’i geldi. Daha eski sistemlerde sc.exe kullanmak gerekiyor:
# PowerShell 6+ ve Windows Server 2019+
Remove-Service -Name "MyAppService"
# Eski sistemler için (hala geçerli ve yaygın kullanım)
# Önce servisi durdur
Stop-Service -Name "MyAppService" -Force
# Sonra sil
sc.exe delete "MyAppService"
# Veya WMI üzerinden
$service = Get-WmiObject -Class Win32_Service -Filter "Name='MyAppService'"
$service.Delete()
WMI ile Gelişmiş Servis Bilgisi
Get-Service bazı durumlarda yeterli bilgi vermez. Servisin PID’ini, çalıştırdığı hesabı veya tam yolunu görmek için WMI/CIM kullanmak gerekir:
# CIM ile detaylı servis bilgisi (modern yaklaşım)
Get-CimInstance -ClassName Win32_Service |
Where-Object {$_.State -eq "Running"} |
Select-Object Name, DisplayName, State, StartMode,
ProcessId, StartName, PathName |
Format-Table -AutoSize
# Belirli bir servisin detaylarını al
Get-CimInstance -ClassName Win32_Service -Filter "Name='Spooler'" |
Select-Object *
# Yüksek bellek kullanan servislerin PID'lerini bul
$services = Get-CimInstance -ClassName Win32_Service |
Where-Object {$_.State -eq "Running" -and $_.ProcessId -gt 0}
foreach ($svc in $services) {
$process = Get-Process -Id $svc.ProcessId -ErrorAction SilentlyContinue
if ($process -and $process.WorkingSet64 -gt 500MB) {
Write-Host "$($svc.Name) - PID: $($svc.ProcessId) - Bellek: $([math]::Round($process.WorkingSet64/1MB, 2)) MB" -ForegroundColor Yellow
}
}
# Uzak sunucuda CIM sorgusu
$session = New-CimSession -ComputerName "SERVER01"
Get-CimInstance -CimSession $session -ClassName Win32_Service |
Where-Object {$_.StartMode -eq "Auto" -and $_.State -eq "Stopped"} |
Select-Object Name, DisplayName, State
Remove-CimSession -CimSession $session
Servis Bağımlılıklarını Yönetmek
Servisler arasındaki bağımlılıkları anlamak, özellikle bakım pencerelerinde servis kapatma sırasını doğru belirlemek için kritik:
# Bir servisin bağımlı olduğu servisleri göster
$service = Get-Service -Name "wuauserv"
$service.RequiredServices
# Bir servise bağımlı servisleri göster
$service.DependentServices
# Detaylı bağımlılık ağacı
function Get-ServiceDependencyTree {
param([string]$ServiceName, [int]$Level = 0)
$indent = " " * $Level
$svc = Get-Service -Name $ServiceName
Write-Host "$indent$($svc.DisplayName) [$($svc.Status)]"
foreach ($dep in $svc.RequiredServices) {
Get-ServiceDependencyTree -ServiceName $dep.Name -Level ($Level + 1)
}
}
Get-ServiceDependencyTree -ServiceName "wuauserv"
İpuçları ve En İyi Pratikler
Uzun yılların getirdiği deneyimle birkaç önemli noktayı paylaşmak isterim:
Hata yönetimini ihmal etmeyin. Servis işlemleri her zaman beklenmedik durumlarla karşılaşabilir. Try-catch bloklarını kullanmak, script’lerinizin sessizce başarısız olmasını önler.
Üretim değişikliklerinde -WhatIf kullanın. Birçok PowerShell cmdlet’i -WhatIf parametresini destekler. Stop-Service -Name "kritikservis" -WhatIf komutu servisi durdurmadan önce ne yapacağını gösterir.
Log tutmayı alışkanlık edinin. Yukarıdaki izleme scriptinde gösterdiğim gibi, tüm kritik işlemleri log dosyasına yazın. Sorun çıktığında bu loglar kurtarıcı olur.
Kimlik bilgilerini güvenli saklayın. Script’lere düz metin şifre yazmak yerine Get-Credential veya Windows Credential Manager kullanın. Domain servis hesapları için gMSA (Group Managed Service Accounts) değerlendirin.
Değişikliklerden önce anlık görüntü alın. Toplu servis yapılandırması değişikliği yapmadan önce mevcut durumu kaydedin:
# Mevcut servis yapılandırmasını yedekle
Get-Service |
Select-Object Name, DisplayName, Status, StartType |
Export-Csv -Path "C:BackupServisYedek_$(Get-Date -Format 'yyyyMMdd_HHmm').csv" -NoTypeInformation -Encoding UTF8
Bu CSV dosyasını bir sorun çıktığında referans olarak kullanabilirsiniz.
Sonuç
PowerShell ile Windows servis yönetimi, GUI’ye kıyasla çok daha güçlü ve esnek bir yapı sunuyor. Tek bir komutla onlarca sunucudaki servislerin durumunu görmek, toplu yapılandırma değişiklikleri yapmak ve otomatik izleme script’leri kurarak proaktif bir yaklaşım benimsemek mümkün. Başlangıçta birkaç temel cmdlet’i ezberlemek yeterli; geri kalanı pratik yaparak geliyor.
Bu yazıda ele aldığımız konuları özetleyecek olursak: temel servis sorgulama ve yönetim işlemleri, yapılandırma değişiklikleri, uzak sunucu yönetimi, otomatik izleme scriptleri, yeni servis oluşturma/silme, WMI ile gelişmiş sorgular ve bağımlılık yönetimi. Bunların hepsini günlük pratiğinize entegre ettiğinizde, servis yönetimi için harcadığınız zamanın önemli ölçüde azaldığını göreceksiniz.
Bir sonraki adım olarak bu script’leri kendi ortamınıza uyarlayın, gerekli sunucu adlarını ve servis isimlerini düzenleyin. Özellikle sağlık kontrolü ve otomatik kurtarma scriptleri, pek çok ortamda gecenin üçünde pager’ı susturmak için biçilmiş kaftan.