PowerShell'de fonksiyon yazmak ve hataları yönetmek: örneklerle rehber
PowerShell'de fonksiyon yazımı: parametreler, doğrulama, çıktı; try/catch/finally ve ErrorAction Stop ile hata yönetimi örnekleriyle.
Fonksiyon neden yazılır?
Aynı komut dizisini birkaç yerde yapıştırıyorsanız fonksiyon yazma zamanı gelmiştir. Fonksiyon, adı olan, parametre alan ve tekrar kullanılabilen bir komut bloğudur. Betiğiniz kısalır, değişiklik tek yerde yapılır ve test etmek kolaylaşır.
En sade biçim şöyledir:
function Get-DiskOzet { param( [string]$SurucuAdi ) Get-PSDrive -Name $SurucuAdi }
Çağırırken parametre adıyla verilir: Get-DiskOzet -SurucuAdi C. PowerShell adlandırma geleneği "Fiil-Isim" biçimindedir. Fiil olarak Get, Set, New, Remove, Test gibi onaylı fiillerden birini seçmek, fonksiyonunuzun diğer komutlarla uyumlu görünmesini sağlar.
Bu ilk biçim basit fonksiyondur. Parametre doğrulama, boru hattından girdi alma ve ortak parametreler gibi yetenekler için gelişmiş fonksiyona geçilir.
Parametreler ve doğrulama
Microsoft belgelerine göre parametreler param() bloğunda tanımlanır ve Parameter özniteliğiyle zorunlu, konumlu ya da boru hattından değer alan hale getirilebilir. Örnek:
function Get-SunucuBilgisi { [CmdletBinding()] param( [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNullOrEmpty()] [string[]]$SunucuAdi,
[switch]$AyrintiliGoster ) process { foreach ($ad in $SunucuAdi) { Write-Verbose "Sorgulanıyor: $ad" Test-Connection -ComputerName $ad -Quiet } } }
Bu tanımdaki parçalar şunlardır:
- CmdletBinding: Fonksiyonu gelişmiş fonksiyon yapar ve Verbose, ErrorAction gibi ortak parametreleri otomatik ekler.
- Mandatory: Parametre verilmezse PowerShell değer ister.
- ValueFromPipeline: Boru hattından gelen nesneyi parametreye bağlar. Bu durumda işi process bloğu yapar.
- ValidateNotNullOrEmpty: Boş değerleri baştan reddeder. Belgelerde ValidateSet (izinli değerler listesi), ValidateRange, ValidatePattern ve ValidateScript gibi başka doğrulayıcılar da tanımlıdır.
- switch: Değer almayan, varlığıyla doğru olan parametredir. Varsayılan değer atanmaz.
Doğrulamayı parametrede yapmak, fonksiyon gövdesini sade tutar: geçersiz girdi fonksiyon çalışmadan hata verir.
Çıktı: Write-Output, return ve nesneler
PowerShell'de fonksiyon, çalışırken ürettiği her çıktıyı çağırana döndürür; yalnızca return ifadesinin değerini değil. Bu sık karşılaşılan bir şaşırtmadır: gövdede çıktısı yakalanmayan bir komut (örneğin bir koleksiyona ekleme) çıktı akışına karışabilir.
Çıktıyı temiz tutmak için:
- Sonuç nesnesini bilinçli üretin: [pscustomobject]@{ Ad = $ad; Durum = "Hazır" } gibi.
- Çıktısı istenmeyen komutları Out-Null ile ya da değişkene atayarak susturun.
- Ekrana bilgi yazacaksanız Write-Host yerine Write-Verbose veya Write-Information kullanın; böylece çıktı akışı bozulmaz ve kullanıcı isterse görür.
Metin yerine nesne döndürmek PowerShell'in gücüdür. Nesne döndüren fonksiyonun sonucu Where-Object, Sort-Object, Export-Csv gibi komutlara doğrudan bağlanabilir. Biçimlendirme (Format-Table gibi) komutlarını fonksiyonun içinde değil, en sonda, yalnızca ekranda görmek için kullanın.
Hata türleri: sonlandırıcı ve sonlandırıcı olmayan
Hata yönetiminin ilk adımı, PowerShell'in farklı türde hatalar ürettiğini bilmektir. Microsoft belgeleri bunu şöyle ayırır: ifadeyi sonlandıran hatalar (statement-terminating) geçerli ifadeyi durdurur; betiği sonlandıran hatalar (script-terminating, örneğin throw ile üretilenler) tüm çağrı yığınını geriye sarar. Sonlandırıcı olmayan hatalar ise mesajı yazar ve çalışmaya devam eder.
try/catch yalnızca sonlandırıcı hataları yakalar. Pek çok cmdlet'in hatası sonlandırıcı olmadığı için varsayılan ayarla catch bloğuna hiç düşmez. Çözüm, ErrorAction ortak parametresini Stop yapmaktır: belgelere göre Stop değeri sonlandırıcı olmayan hatayı sonlandırıcıya yükseltir ve try/catch ile yakalanabilir hale getirir.
Get-Content -Path $dosya -ErrorAction Stop
Bu satırı try içine yazarsanız dosya yoksa catch bloğu çalışır. ErrorAction'ı yalnızca yakalamak istediğiniz komuta verin; oturum genelinde $ErrorActionPreference değiştirmek yan etkiler doğurabilir.
try, catch, finally kullanımı
Yapı şu parçalardan oluşur. try bloğu hata izlenecek kodu, catch bloğu hata olduğunda yapılacak işi, finally bloğu hata olsun olmasın çalışacak temizliği içerir. Belgelere göre bir try ifadesi en az bir catch ya da bir finally içermelidir.
try { $icerik = Get-Content -Path $dosya -ErrorAction Stop $icerik | Out-File -FilePath $hedef } catch [System.IO.FileNotFoundException] { Write-Warning "Dosya bulunamadı: $dosya" } catch { Write-Error "Beklenmeyen hata: $($_.Exception.Message)" } finally { Write-Verbose "İşlem bitti." }
Önemli noktalar:
- catch bloğunda geçerli hata $_ ya da $PSItem ile erişilen bir ErrorRecord nesnesidir. Ayrıntı için Exception, ScriptStackTrace gibi özelliklerine bakılır.
- Belirli tür yakalamak için catch yanına köşeli parantezle özel durum türü yazılır. Birden çok catch varsa türe özgü olan genel olandan önce gelmelidir.
- Türsüz catch bütün sonlandırıcı hataları yakalar.
- finally, kaynakları serbest bırakmak içindir: açılan dosya, bağlantı, geçici dosya gibi.
- Hatayı yakalayıp yutmayın. Yapılacak bir şey yoksa throw ile yeniden fırlatın ki çağıran taraf bilsin.
Fonksiyon içinde hata stratejisi
Fonksiyonun hatayı nasıl bildireceğine baştan karar verin.
Kütüphane gibi kullanılan bir fonksiyonda hata durumunda throw ya da Write-Error kullanın ve çağıranın karar vermesine izin verin. Fonksiyon her şeyi kendi içinde yakalayıp "Hata oluştu" yazdırıyorsa çağıran taraf başarısızlığı anlayamaz.
Birden çok öğeyi işleyen fonksiyonda tek bir öğenin hatası bütün işi durdurmamalıdır. Bunun için döngü içinde try/catch kullanın: hatalı öğeyi kaydedin, sonrakine geçin ve sonda başarısız olanların listesini döndürün.
Örnek akış:
foreach ($ad in $SunucuAdi) { try { Test-Connection -ComputerName $ad -Quiet -ErrorAction Stop } catch { Write-Warning "$ad atlandı: $($_.Exception.Message)" } }
Hata kayıtlarını kalıcı tutmanız gerekiyorsa catch içinde bir günlük dosyasına zaman damgasıyla yazın. Zamanlanmış görevlerde ekran okuyan kimse olmadığı için günlük tek tanık olur.
ErrorVariable ortak parametresi de hataları ayrı bir değişkende toplamak için kullanılır; hatayı yakalamadan sonradan incelemek istediğinizde işe yarar.
Sık yapılan hatalar
- ErrorAction Stop vermeden try/catch yazmak: Sonlandırıcı olmayan hata catch'e düşmez, kod "çalışıyor" gibi görünüp hatayı kaçırır.
- Geniş try blokları: Her şeyi tek try içine koymak hatanın nerede olduğunu gizler. Riskli komutu dar bir blokta yakalayın.
- Boş catch: Hatayı sessizce yutar. En azından günlüğe yazın.
- Çıktıyı kirletmek: Fonksiyonda istemeden çıktı üreten bir satır, dönüş değerini bozar.
- Write-Host ile veri döndürmek: Write-Host çıktı akışına girmez; çağıran tarafın yakalayabileceği bir veri değildir.
- Parametre doğrulamayı atlamak: Geçersiz girdi fonksiyonun ortasında anlaşılmaz bir hata olarak patlar.
- Onaylı olmayan fiillerle adlandırmak: Modüle aktarılırken uyarı verir ve komut keşfini zorlaştırır.
- Test etmemek: Başarı yolunu olduğu kadar hata yolunu da deneyin; olmayan dosya, erişilemeyen sunucu gibi senaryolarla catch bloğunu çalıştırın.
Bu beceriyi Mindset programlarında nerede çalışırsınız?
PowerShell ile Windows Otomasyonu eğitimi, sistem yöneticileri, destek mühendisleri ve altyapı ekipleri için tasarlanmıştır; tekrarlayan yönetim işlerini betikleştirmek isteyen herkes için uygundur. Modül başlıkları arasında PowerShell temelleri ve nesne modeli, değişkenler ve akış kontrolü, fonksiyon yazımı ve hata yönetimi, sistem ve dizin yönetimi otomasyonu, uzak yönetim ve güvenlik ile modül paketleme, zamanlama ve proje yer alır.
Fonksiyon yazımı ve hata yönetimi modülü, bu sayfadaki konunun doğrudan çalışıldığı bölümdür. Sonraki modüllerde bu fonksiyonlar modüle paketlenip zamanlanmış görev olarak çalıştırılabildiği için, kurumsal ekipler ortak bir fonksiyon kütüphanesi kurma yolunu da aynı programda görebilir.
İlgili Mindset programı
PowerShell ile Windows Otomasyonu
Sık sorulan sorular
PowerShell'de basit fonksiyon ile gelişmiş fonksiyon arasındaki fark nedir?
Basit fonksiyon yalnızca param bloğu ve gövdeden oluşur. Gelişmiş fonksiyon CmdletBinding ya da Parameter özniteliği kullanır; bu sayede ortak parametreleri (Verbose, ErrorAction gibi) otomatik kazanır ve parametre doğrulama, boru hattı girdisi gibi yeteneklere sahip olur. Paylaşılacak kodlarda gelişmiş fonksiyon tercih edilir.
Neden catch bloğum çalışmıyor?
En sık neden, hatanın sonlandırıcı olmamasıdır. Birçok cmdlet hata mesajı yazar ve devam eder; try/catch bunu yakalamaz. Çözüm komuta ErrorAction Stop parametresini vermektir. Böylece sonlandırıcı olmayan hata, catch'in yakalayabileceği bir sonlandırıcı hataya yükselir.
Hata mesajına nasıl erişirim?
catch bloğu içinde geçerli hata $_ ya da $PSItem değişkenindedir. Mesaj metni için $_.Exception.Message, hatanın kaynağını görmek için ScriptStackTrace özelliği kullanılabilir. Hatayı olduğu gibi yazdırmak da yeterli bir başlangıçtır; ayrıntıya ihtiyaç oldukça özellikler incelenir.
ErrorAction parametresi ile $ErrorActionPreference arasındaki fark nedir?
ErrorAction parametresi yalnızca verildiği tek komutun hata davranışını belirler. $ErrorActionPreference ise oturumdaki ya da betikteki tüm komutlar için varsayılanı değiştirir. İkisi birlikte varsa komuta verilen parametre önceliklidir. Betiğin başında tercih değişkenini Stop yapmak, her cmdlet'e ayrı ayrı parametre yazmadan hataların catch'e düşmesini sağlar.
Fonksiyondaki hatayı çağıran koda nasıl iletirim?
Sorunun fonksiyon içinde çözülemediği durumlarda throw ile hatayı yeniden fırlatmak ya da Write-Error ile hata kaydı üretmek gerekir. Çağıran taraf kendi try/catch bloğunda bunu yakalayıp karar verir. Hatayı içeride yutup başarılıymış gibi devam etmek, hataları gizler ve sonradan bulunmasını zorlaştırır.
İlgili rehberler
Kategori: Yazılım Geliştirme