Windows ortamında tekrar eden görevleri otomatikleştirmek istediğinizde, batch scripting hala en hızlı ve en erişilebilir çözümlerden biri olmaya devam ediyor. PowerShell kadar güçlü olmasa da, batch scriptler her Windows sürümünde çalışır, ekstra modül gerektirmez ve basit görevler için fazlasıyla yeterlidir. Bu yazıda sıfırdan başlayarak gerçek dünya senaryolarında kullanabileceğiniz batch scriptler yazacağız.
Batch Script Temelleri
Batch dosyaları .bat veya .cmd uzantılı düz metin dosyalarıdır. Notepad ile bile yazabilirsiniz ama ben genellikle Notepad++ kullanıyorum, sözdizimi renklendirmesi hayat kurtarır. Komut dosyaları CMD.exe tarafından satır satır işlenir ve Windows’un temel otomasyon aracıdır.
İlk olarak en önemli komuttan başlayalım: @echo off. Bu satır olmadan her çalıştırdığınız komut ekranda görüntülenir, scriptiniz okunaksız bir hale gelir.
@echo off
REM Bu bir yorum satiridir
echo Merhaba, Sysadmin!
pause
@echo off: Komutların ekranda tekrar gösterilmesini engeller REM: Yorum satırı tanımlar, script çalışırken atlanır pause: “Devam etmek için bir tuşa basın” mesajı gösterir
Değişkenler ve SET Komutu
Batch scriptlerde değişkenler %degisken_adi% formatında kullanılır. SET komutuyla değişken tanımlanır:
@echo off
SET sunucu_adi=WINSERVER01
SET yedek_dizin=D:Yedekler
SET tarih=%DATE:~6,4%-%DATE:~3,2%-%DATE:~0,2%
echo Sunucu: %sunucu_adi%
echo Yedek Dizini: %yedek_dizin%
echo Bugünün Tarihi: %tarih%
Tarih formatlaması biraz karmaşık görünüyor, haklısınız. %DATE% değişkeni GG.AA.YYYY formatında döner, biz bunu parçalara ayırıyoruz. ~6,4 ifadesi 6. karakterden itibaren 4 karakter al demek.
SET /A: Matematiksel işlemler için kullanılır SET /P: Kullanıcıdan girdi almak için kullanılır
@echo off
SET /A sonuc = 10 + 5
echo Sonuc: %sonuc%
SET /P kullanici_girdi=Lütfen bir değer girin:
echo Girdiğiniz değer: %kullanici_girdi%
Koşullu İfadeler ve IF Blokları
Gerçek otomasyon scriptlerinde karar mekanizmaları şart. IF komutu batch scriptin bel kemiğidir:
@echo off
SET servis_adi=Spooler
sc query %servis_adi% | find "RUNNING" >nul
IF %ERRORLEVEL% EQU 0 (
echo %servis_adi% servisi çalışıyor.
) ELSE (
echo %servis_adi% servisi çalışmıyor, başlatılıyor...
net start %servis_adi%
IF %ERRORLEVEL% EQU 0 (
echo Servis başarıyla başlatıldı.
) ELSE (
echo HATA: Servis başlatılamadı!
)
)
Bu script önce Print Spooler servisinin çalışıp çalışmadığını kontrol ediyor, çalışmıyorsa başlatmaya çalışıyor. ERRORLEVEL sistem değişkeni son komutun çıkış kodunu tutar, 0 başarı anlamına gelir.
Dosya ve Dizin Varlık Kontrolü
@echo off
SET log_dizin=C:LogsUygulama
IF NOT EXIST "%log_dizin%" (
echo Log dizini bulunamadı, oluşturuluyor...
mkdir "%log_dizin%"
echo Dizin oluşturuldu: %log_dizin%
) ELSE (
echo Log dizini mevcut.
)
IF EXIST "%log_dizin%uygulama.log" (
echo Log dosyası bulundu.
copy "%log_dizin%uygulama.log" "%log_dizin%uygulama_%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%.log"
del "%log_dizin%uygulama.log"
echo Eski log arşivlendi.
)
IF EXIST: Dosya veya dizin var mı kontrol eder IF NOT EXIST: Dosya veya dizin yoksa işlem yapar mkdir: Dizin oluşturur, iç içe dizinler için de çalışır
FOR Döngüleri ile Toplu İşlemler
FOR döngüsü batch scriptin en güçlü yapısıdır. Birden fazla sunucuya aynı işlemi uygulamak, bir dizindeki tüm dosyaları işlemek veya bir liste üzerinde döngü kurmak için kullanılır.
Basit Liste Döngüsü
@echo off
echo Sunucu Ping Testi Başlıyor...
echo ================================
FOR %%S IN (WEBSERVER01 WEBSERVER02 DBSERVER01 FILESERVER01) DO (
echo Test ediliyor: %%S
ping -n 2 %%S >nul 2>&1
IF %ERRORLEVEL% EQU 0 (
echo [OK] %%S - Erişilebilir
) ELSE (
echo [HATA] %%S - Erişilemiyor!
)
)
echo ================================
echo Test tamamlandı.
pause
Döngü değişkenlerinde %%S kullanıyoruz. Komut satırında direkt çalıştırıyorsanız tek %S yeterli, ama script dosyasında her zaman çift %% kullanın.
Dizin İçindeki Dosyaları İşleme
@echo off
SET kaynak=C:Raporlar
SET hedef=D:ArsivRaporlar
IF NOT EXIST "%hedef%" mkdir "%hedef%"
FOR %%F IN (%kaynak%*.pdf) DO (
echo Taşınıyor: %%~nxF
move "%%F" "%hedef%%%~nxF"
)
echo Tüm PDF dosyaları arşive taşındı.
%%~nxF: Dosyanın adını ve uzantısını verir (yol bilgisi olmadan) %%~dpF: Sürücü harfi ve yol bilgisini verir %%~zF: Dosya boyutunu byte cinsinden verir
Dosyadan Satır Satır Okuma
Sunucu listesi bir dosyada tutuluyorsa, o dosyayı döngüde okuyabilirsiniz:
@echo off
SET sunucu_listesi=C:Scriptssunucular.txt
SET log_dosya=C:Logsdisk_raporu_%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%.txt
echo Disk Kullanım Raporu > "%log_dosya%"
echo Tarih: %DATE% %TIME% >> "%log_dosya%"
echo ========================= >> "%log_dosya%"
FOR /F "tokens=*" %%L IN (%sunucu_listesi%) DO (
echo İşleniyor: %%L
echo. >> "%log_dosya%"
echo Sunucu: %%L >> "%log_dosya%"
wmic /node:"%%L" logicaldisk get caption,freespace,size /format:list >> "%log_dosya%" 2>&1
)
echo Rapor tamamlandı: %log_dosya%
notepad "%log_dosya%"
FOR /F: Dosyadan veya komut çıktısından veri okur tokens=*: Her satırın tamamını al >> dosya: Çıktıyı dosyaya ekle (üzerine yazmaz) > dosya: Çıktıyı dosyaya yaz (varsa üzerine yazar)
Fonksiyonlar ve GOTO Kullanımı
Batch scriptlerde fonksiyon benzeri yapılar GOTO ve CALL komutlarıyla oluşturulur:
@echo off
SET log_dosya=C:Logsscript_%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%.log
CALL :log_yaz "Script başlatıldı"
CALL :servis_kontrol "Spooler"
CALL :servis_kontrol "wuauserv"
CALL :servis_kontrol "BITS"
CALL :log_yaz "Script tamamlandı"
EXIT /B 0
:servis_kontrol
SET servis=%~1
sc query "%servis%" | find "RUNNING" >nul 2>&1
IF %ERRORLEVEL% EQU 0 (
CALL :log_yaz "[OK] %servis% - Çalışıyor"
) ELSE (
CALL :log_yaz "[UYARI] %servis% - Çalışmıyor"
)
EXIT /B
:log_yaz
echo [%TIME%] %~1
echo [%DATE% %TIME%] %~1 >> "%log_dosya%"
EXIT /B
CALL :etiket: Bir alt rutini çağırır ve bitince kaldığı yerden devam eder EXIT /B: Alt rutinden çıkar, 0 ile kullanılırsa scripti başarıyla sonlandırır %~1: Fonksiyona geçirilen ilk parametreden tırnak işaretlerini temizler
Gerçek Dünya Senaryosu 1: Otomatik Yedekleme Scripti
Küçük ve orta ölçekli ortamlarda robocopy ile basit ama etkili bir yedekleme scripti:
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET tarih=%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%
SET saat=%TIME:~0,2%%TIME:~3,2%
SET saat=%saat: =0%
SET yedek_etiketi=%tarih%_%saat%
SET kaynak_dizinler=C:InetPubwwwroot D:UygulamalarConfig E:VeritabaniYedek
SET hedef_ana=\FILESERVER01YedeklerGünlük
SET log=%hedef_ana%Logsyedek_%yedek_etiketi%.log
SET hata_sayisi=0
IF NOT EXIST "%hedef_ana%Logs" mkdir "%hedef_ana%Logs"
echo ============================================ >> "%log%"
echo Yedekleme Başlangıç: %DATE% %TIME% >> "%log%"
echo ============================================ >> "%log%"
FOR %%D IN (%kaynak_dizinler%) DO (
SET hedef=%hedef_ana%%%~nD_%yedek_etiketi%
echo Yedekleniyor: %%D >> "%log%"
robocopy "%%D" "!hedef!" /E /ZB /R:3 /W:10 /LOG+:"%log%" /NP
IF !ERRORLEVEL! GTR 7 (
echo HATA: %%D yedeklenemedi! >> "%log%"
SET /A hata_sayisi+=1
) ELSE (
echo TAMAM: %%D başarıyla yedeklendi. >> "%log%"
)
)
echo ============================================ >> "%log%"
echo Yedekleme Bitiş: %DATE% %TIME% >> "%log%"
echo Toplam Hata: %hata_sayisi% >> "%log%"
IF %hata_sayisi% GTR 0 (
echo Yedekleme hatalarla tamamlandı. IT ekibine bildirim gönderiliyor...
blat -to [email protected] -subject "YEDEKLEME HATASI - %COMPUTERNAME%" -body "Yedekleme sırasında %hata_sayisi% hata oluştu. Log: %log%" -server mailserver
)
ENDLOCAL
SETLOCAL ENABLEDELAYEDEXPANSION: Döngü içinde değişken değerlerini !degisken! şeklinde anlık okumayı sağlar, bu olmadan döngü içindeki değişken güncellemeleri çalışmaz robocopy: Windows’un güçlü kopyalama aracı, /E tüm alt dizinleri, /ZB yeniden başlatılabilir modu, /R:3 3 kez tekrar denemeyi belirtir Robocopy ERRORLEVEL 7 ve altı: Başarılı veya bilgilendirme mesajları, 8 ve üzeri gerçek hatalardır
Gerçek Dünya Senaryosu 2: Kullanıcı Hesabı Toplu Oluşturma
İK’dan gelen Excel listesini CSV’ye çevirip şu scriptlе toplu kullanıcı oluşturabilirsiniz:
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET kullanici_listesi=C:Scriptsyeni_kullanicilar.csv
SET varsayilan_sifre=Sirket2024!
SET log=C:Logskullanici_olusturma_%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%.log
echo Toplu Kullanıcı Oluşturma Başlıyor...
echo =========================================
FOR /F "skip=1 tokens=1,2,3,4 delims=," %%A IN (%kullanici_listesi%) DO (
SET ad=%%A
SET soyad=%%B
SET departman=%%C
SET grup=%%D
SET kullanici_adi=!ad:~0,1!!soyad!
SET kullanici_adi=!kullanici_adi: =!
echo Oluşturuluyor: !kullanici_adi! - !ad! !soyad! [!departman!]
net user "!kullanici_adi!" "%varsayilan_sifre%" /add /fullname:"!ad! !soyad!" /comment:"!departman!" /passwordchg:yes >nul 2>&1
IF !ERRORLEVEL! EQU 0 (
net localgroup "!grup!" "!kullanici_adi!" /add >nul 2>&1
echo [OK] !kullanici_adi! oluşturuldu ve !grup! grubuna eklendi >> "%log%"
) ELSE (
echo [HATA] !kullanici_adi! oluşturulamadı - Zaten mevcut olabilir >> "%log%"
)
)
echo =========================================
echo İşlem tamamlandı. Log: %log%
ENDLOCAL
CSV dosyası şu formatta olmalı:
- Birinci kolon: Ad
- İkinci kolon: Soyad
- Üçüncü kolon: Departman
- Dördüncü kolon: Grup adı
skip=1: Başlık satırını atlar delims=,: Virgülü ayraç olarak kullanır tokens=1,2,3,4: İlk dört kolonu al
Hata Yönetimi ve Loglama
İyi bir batch script hataları yakalar ve kayıt altına alır. Benim her scriptte kullandığım temel loglama yapısı:
@echo off
SETLOCAL
SET script_adi=%~n0
SET log_dizin=C:Logs
SET log=%log_dizin%%script_adi%_%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%.log
SET hata_kodu=0
IF NOT EXIST "%log_dizin%" mkdir "%log_dizin%"
CALL :log "INFO" "Script başlatıldı: %script_adi%"
net stop "Spooler" >nul 2>&1
IF %ERRORLEVEL% NEQ 0 (
CALL :log "HATA" "Spooler servisi durdurulamadı. Kod: %ERRORLEVEL%"
SET hata_kodu=1
GOTO :temizle
)
CALL :log "INFO" "Spooler durduruldu"
del /Q /F "C:WindowsSystem32spoolPRINTERS*.*" >nul 2>&1
CALL :log "INFO" "Print kuyruğu temizlendi"
net start "Spooler" >nul 2>&1
IF %ERRORLEVEL% NEQ 0 (
CALL :log "KRITIK" "Spooler yeniden başlatılamadı!"
SET hata_kodu=2
GOTO :temizle
)
CALL :log "INFO" "Spooler yeniden başlatıldı"
:temizle
CALL :log "INFO" "Script tamamlandı. Çıkış kodu: %hata_kodu%"
ENDLOCAL
EXIT /B %hata_kodu%
:log
echo [%DATE% %TIME%] [%~1] %~2
echo [%DATE% %TIME%] [%~1] %~2 >> "%log%"
EXIT /B
%~n0: Scriptin adını uzantısız verir, dinamik log dosyası isimlendirmesi için kullanışlı GOTO :temizle: Hata durumunda temizlik bölümüne atlar, hem çıkmak için hem de cleanup işlemleri için
Task Scheduler ile Otomasyonu Tamamlamak
Scripti yazmak yetmez, zamanında çalıştırmanız gerekir. Task Scheduler’a komut satırından görev ekleyebilirsiniz:
schtasks /create /tn "Günlük Yedekleme" /tr "C:Scriptsyedekleme.bat" /sc daily /st 23:00 /ru SYSTEM /f
schtasks /create /tn "Haftalık Temizlik" /tr "C:Scriptstemizlik.bat" /sc weekly /d MON /st 06:00 /ru "DOMAINservis_hesabi" /rp "SifreBurada" /f
schtasks /query /tn "Günlük Yedekleme" /fo list
schtasks /run /tn "Günlük Yedekleme"
schtasks /create: Yeni görev oluşturur /tn: Görev adı /tr: Çalıştırılacak dosya yolu /sc daily: Günlük çalıştır /st: Başlangıç saati /ru SYSTEM: SYSTEM hesabıyla çalıştır /f: Görev zaten varsa üzerine yaz
Pratik İpuçları ve Sık Yapılan Hatalar
Boşluk içeren yolları her zaman tırnak içine alın. “Program Files” gibi dizinlerde tırnak kullanmazsanız script hata verir.
ENABLEDELAYEDEXPANSION’ı döngülerde unutmayın. Döngü içinde bir değişkeni güncelleyip hemen okumaya çalışıyorsanız bu şart, aksi halde eski değeri okursunuz.
Çıktıyı nul’a yönlendirin. >nul 2>&1 ifadesi hem standart çıktıyı hem de hata çıktısını gizler, scriptin temiz görünmesini sağlar.
Test modunda çalıştırın. Önemli işlemler öncesinde echo komutunun başına koyun, önce ne yapacağını görün:
REM Gerçek komut: del /Q "%hedef%*.tmp"
echo del /Q "%hedef%*.tmp"
ERRORLEVEL kontrolünü hemen yapın. Komuttan sonra başka bir komut çalıştırırsanız ERRORLEVEL değişir.
Eski logları temizlemek için de basit bir yaklaşım:
@echo off
SET log_dizin=C:Logs
SET kac_gun=30
forfiles /p "%log_dizin%" /s /m *.log /d -%kac_gun% /c "cmd /c del @path" 2>nul
echo %kac_gun% günden eski loglar temizlendi.
forfiles: Belirli kriterlere göre dosyaları işler /d -%kac_gun%: Belirtilen günden daha eski dosyaları seçer
Sonuç
Batch scripting, yıllar geçse de Windows yöneticisinin araç kutusundan çıkmıyor. PowerShell daha güçlü, daha modern ve kesinlikle öğrenilmesi gereken bir araç. Ama legacy sistemler, çok basit otomasyon ihtiyaçları veya her ortamda çalışması garanti edilen scriptler yazmanız gerektiğinde batch hala en hızlı çözüm.
Burada anlattıklarımı baz alarak başlayın, sonra kendi ihtiyaçlarınıza göre geliştirin. En iyi batch scripti, gerçek bir sorunu çözen, hataları düzgün yöneten ve log bırakan scripttir. Süslü olması gerekmiyor, çalışması gerekiyor.
Özellikle değişken expansion, FOR döngüleri ve hata yönetimi konularında pratik yapın. Bu üç konuyu iyi kavradığınızda, aklınıza gelen her türlü otomasyon görevini batch script ile halledebilirsiniz. Karmaşık iş mantığına ihtiyaç duyduğunuzda ise artık PowerShell’e geçme zamanı gelmiş demektir.