İçeriğe geç
Yeni yazı çıkınca e-posta · 4.812 abone 115 rehber · 78 ipucu · 8 komut RSS GitHub LinkedIn İletişim
Ara Bültene katıl
Bültene katıl 4.812 abone · yeni yazı çıkınca e-posta
PowerShell

Elimde çalışan betik zamanlanmış görevde neden çalışmıyor?

Aynı kod, aynı makine, farklı sonuç. Sebep neredeyse her zaman aynı beş şeyden biri.

Mustafa Çelik 20 Mart 2026 · 9 dk okuma

Bu, sistem yöneticiliğinin en tekrar eden hayal kırıklığıdır. Betiği açar, çalıştırır, çıktıyı görürsünüz. Aynı betiği Görev Zamanlayıcı’ya koyarsınız ve hiçbir şey olmaz. Hata da yoktur — çünkü hatayı kimse görmez.

Sebep neredeyse her zaman şu beşten biridir.

1. Farklı hesap, farklı yetki

Siz betiği kendi hesabınızla çalıştırdınız. Görev, SYSTEM ya da bir hizmet hesabıyla çalışıyor. O hesabın ağ paylaşımına, kayıt defteri anahtarına veya AD nesnesine erişimi olmayabilir.

SYSTEM hesabı özellikle yanıltıcıdır: yerel makinede neredeyse her şeye yetkilidir ama ağda makine hesabı olarak görünür. Uzak bir paylaşıma erişmesi gerekiyorsa, o paylaşımda makine hesabına izin verilmiş olmalıdır.

Test etmenin yolu, betiği o hesapla elle çalıştırmaktır:

# SYSTEM olarak bir konsol açmak için (PsExec ile)
psexec -i -s powershell.exe

2. Çalışma dizini farklı

Betiğinizde .\rapor.csv gibi göreli bir yol varsa, elle çalıştırdığınızda betiğin bulunduğu klasöre yazar. Zamanlanmış görevde çalışma dizini genelde C:\Windows\System32 olur ve dosya oraya düşer — ya da yetki olmadığı için hiç düşmez.

İki çözüm var. Görev tanımında “Başlangıç yeri” alanını doldurun ya da betiği kendi kendine yetsin:

$kok = Split-Path -Parent $PSCommandPath
$cikti = Join-Path $kok 'rapor.csv'

İkincisini tercih edin; görev tanımına bağımlı olmaz.

3. Profil yüklenmiyor

Etkileşimli oturumda PowerShell profiliniz çalışır: modül yolları eklenir, takma adlar tanımlanır, kimlik bilgileri yüklenir. Zamanlanmış görevde profil çalışmaz.

Bu yüzden betiğin ihtiyaç duyduğu her modülü açıkça içe aktarın:

Import-Module ActiveDirectory -ErrorAction Stop

Ve görev eyleminde -NoProfile kullanın; böylece yerelde de aynı koşulda test edersiniz:

Program: pwsh.exe
Argüman: -NoProfile -ExecutionPolicy Bypass -File "D:\Betikler\rapor.ps1"

4. Yürütme ilkesi

Betik imzasızsa ve makinenin yürütme ilkesi Restricted veya AllSigned ise görev sessizce başarısız olur. Görev argümanına -ExecutionPolicy Bypass eklemek pratik çözümdür.

Not: bu, ilkeyi makine genelinde değiştirmez; yalnızca o çalıştırma için geçerlidir. Makine genelinde Unrestricted yapmak yerine bunu tercih edin.

5. Etkileşim bekleyen komutlar

Betikte Read-Host, Get-Credential veya onay soran bir cmdlet varsa görev sonsuza kadar bekler. Görev durumu “çalışıyor” görünür ama hiçbir şey olmaz.

Onay isteyen komutlara -Confirm:$false ekleyin. Kimlik bilgisi gerekiyorsa şifreli bir dosyadan okuyun ya da yönetilen bir kimlik kullanın; betiğe gömmeyin.

Görüntüleyemediğiniz hatayı yakalayın

Asıl sorun, zamanlanmış görevde hata mesajını görememenizdir. Çözüm, betiğin kendi günlüğünü tutmasıdır:

$gunluk = Join-Path (Split-Path -Parent $PSCommandPath) "gunluk-$(Get-Date -f yyyyMMdd).log"
Start-Transcript -Path $gunluk -Append

try {
    # asıl iş
} catch {
    "HATA: $($_.Exception.Message) [satır $($_.InvocationInfo.ScriptLineNumber)]" |
        Out-File $gunluk -Append
    exit 1
} finally {
    Stop-Transcript
}

exit 1 önemlidir: görev sonucu böylece “başarısız” olarak kaydedilir ve izleme sisteminiz bunu görebilir. Kod hata verse bile exit 0 dönen görevler, panoda hep yeşil görünür.

Görev sonucunu okumak

Get-ScheduledTaskInfo -TaskName 'Gunluk-Rapor' |
  Select-Object LastRunTime, LastTaskResult, NextRunTime

LastTaskResult değeri 0 başarıdır. Sık görülen diğerleri: 0x1 genel hata, 0x41301 hâlâ çalışıyor, 0x2 dosya bulunamadı (genelde yol hatası).

Kimlik bilgisini betiğe gömmeyin

Zamanlanmış görevlerde en sık karşılaşılan kötü çözüm, parolayı betiğin içine yazmaktır. Betik dosyası yedeklenir, kopyalanır, kod deposuna düşer — parola da onunla birlikte gider.

Tercih sırası şudur:

1. Hesap gerektirmeyen çözüm. Görevi, hedefe zaten yetkili bir hizmet hesabıyla çalıştırın. En temizi budur.

2. Grup yönetimli hizmet hesabı (gMSA). Parolayı AD yönetir ve otomatik döndürür; siz hiç görmezsiniz.

New-ADServiceAccount -Name 'gmsa-rapor' -DNSHostName 'gmsa-rapor.sirket.local' `
  -PrincipalsAllowedToRetrieveManagedPassword 'GG-RaporSunuculari'
Install-ADServiceAccount -Identity 'gmsa-rapor'

3. Şifreli kimlik bilgisi dosyası. gMSA mümkün değilse, Export-Clixml ile kaydedilen kimlik bilgisi yalnızca aynı kullanıcı ve aynı makinede çözülebilir:

Get-Credential | Export-Clixml D:\gizli\rapor.cred   # görevi çalıştıran hesapla yapın
$kb = Import-Clixml D:\gizli\rapor.cred

Bu dosyayı başka bir makineye kopyalarsanız çözülmez — bu bir kısıtlama değil, korumadır.

Görev geçmişini açın

Görev Zamanlayıcı’da geçmiş varsayılan olarak kapalı olabilir. Açık değilse görevin ne zaman çalıştığını, ne kadar sürdüğünü göremezsiniz:

wevtutil set-log Microsoft-Windows-TaskScheduler/Operational /enabled:true

Doğrulama adımı

Görevi kurduktan sonra elle bir kez tetikleyin ve üç şeyi kontrol edin: günlük dosyası oluştu mu, beklenen çıktı doğru yerde mi, LastTaskResult sıfır mı.

Üçü de doğruysa görevi zamana bırakın. Ama ilk planlı çalışmasından sonra aynı üç kontrolü tekrarlayın — elle tetikleme sizin oturumunuzun bağlamını taşıyabilir, planlı çalışma taşımaz. Aradaki farkı ancak ikinci kontrol gösterir.

Mustafa Çelik

Kıdemli Sistem Yöneticisi, Ankara. 12 yıldır Windows Server, Active Directory ve ağ altyapısıyla uğraşıyor; öğrendiklerini bu blogda üretim ortamında denenmiş rehberlere çeviriyor.

Hakkımda

Bu rehber işinize yaradıysa, sonrakini kaçırmayın.

Yeni yazı yayınlandığında tek e-posta. Takvim yok, dilediğiniz an çıkabilirsiniz.

Bülten sağlayıcısı henüz bağlanmadı. Bağlanana kadar e-posta ile yazabilirsiniz ya da RSS akışını takip edebilirsiniz.