Sunucu yönetiminde en can sıkıcı işlerden biri eski log dosyalarını temizlemek, belirli tarihe göre dosyaları arşivlemek ya da yüzlerce klasör içindeki dosyalara toplu işlem uygulamaktır. PowerShell bu işler için güçlü bir araç olsa da bazen sadeliği ve hızıyla CMD’nin yerini hiçbir şey tutamaz. İşte tam bu noktada forfiles komutu devreye giriyor. Windows’ta gömülü gelen bu araç, özellikle tarih bazlı dosya filtrelemesi konusunda son derece yetenekli ve script yazarken hayat kurtarıcı bir komuttur.
Forfiles Nedir ve Neden Kullanılır?
forfiles, Windows’ta belirli kriterlere uyan dosyaları bulup üzerlerinde toplu komut çalıştırmanı sağlayan bir komut satırı aracıdır. for döngüsüne benzer ama dosya filtreleme konusunda çok daha gelişmiş özelliklere sahiptir. Özellikle şu senaryolarda vazgeçilmezdir:
- Belirli günden eski log dosyalarını silmek
- Dosya uzantısına göre toplu taşıma veya kopyalama
- Belirli bir tarih aralığındaki dosyaları arşivlemek
- Otomatik temizlik scriptleri yazmak
- Görev Zamanlayıcı ile periyodik bakım işlemleri yapmak
forfiles Windows XP’den bu yana var olan ama pek çok sysadmin’in göz ardı ettiği bir araçtır. Halbuki özellikle Windows Server ortamlarında scheduled task’larla birleştirildiğinde muazzam bir otomasyon gücü sunar.
Temel Sözdizimi
forfiles /P <yol> /S /M <maske> /D <tarih> /C <komut>
Parametreleri tek tek inceleyelim:
- /P: Hangi klasörde arama yapılacağını belirtir. Belirtilmezse mevcut dizin kullanılır.
- /S: Alt klasörleri de dahil eder (recursive arama).
- /M: Dosya adı maskesi. Örneğin
.log,.tmp,rapor_*.txtgibi wildcard kullanabilirsin. - /D: Tarih filtresi.
+7son 7 günden yeni,-77 günden eski dosyaları filtreler. AyrıcaDD/MM/YYYYformatında sabit tarih de verebilirsin. - /C: Her eşleşen dosya için çalıştırılacak komut. Tırnak içinde yazılmalıdır.
/C parametresinde kullanabileceğin özel değişkenler şunlardır:
- @file: Dosya adı (tırnak işaretleriyle)
- @fname: Uzantısız dosya adı
- @ext: Dosya uzantısı (nokta dahil)
- @path: Tam dosya yolu
- @relpath: Göreli yol
- @isdir: Klasörse TRUE, değilse FALSE
- @fsize: Dosya boyutu (byte cinsinden)
- @fdate: Dosyanın son değiştirilme tarihi
- @ftime: Dosyanın son değiştirilme saati
İlk Temel Örnekler
Başlamadan önce basit bir kullanım görelim. Belirli bir klasördeki tüm .log dosyalarını listelemek için:
forfiles /P "C:Logs" /M *.log /C "cmd /c echo @path"
Bu komut C:Logs klasöründeki tüm .log dosyalarının tam yolunu ekrana basar. Test aşamasında gerçekten silmeden önce hangi dosyaların etkileneceğini görmek için bu yöntemi kullanmak çok işe yarar.
Alt klasörlere de inmek istersen /S eklemen yeterli:
forfiles /P "C:Logs" /S /M *.log /C "cmd /c echo @path"
Senaryo 1: Eski Log Dosyalarını Otomatik Silme
En yaygın kullanım senaryosu budur. IIS, uygulama logları, antivirus logları… Bunlar birikmeye bırakıldığında C: sürücüsünü doldururlar. Aşağıdaki komut 30 günden eski tüm .log dosyalarını siler:
forfiles /P "C:inetpublogsLogFiles" /S /M *.log /D -30 /C "cmd /c del /Q @path"
Dikkat: Bu komutu çalıştırmadan önce mutlaka /C "cmd /c echo @path" ile önce hangi dosyaların silineceğini görün. Üretim ortamında geri dönüşü olmayan işlemlerde bu adımı atlamak ciddi sorunlara yol açabilir.
Silme işlemine hata mesajlarını bastırmak ve çıktıyı bir log dosyasına yazmak istersen:
forfiles /P "C:inetpublogsLogFiles" /S /M *.log /D -30 /C "cmd /c del /Q @path 2>&1" >> "C:Scriptstemizlik_log.txt"
Senaryo 2: Eski Dosyaları Arşiv Klasörüne Taşıma
Dosyaları silmek yerine arşivlemek isteyebilirsin. Örneğin 60 günden eski raporları bir arşiv klasörüne taşımak:
forfiles /P "C:Raporlar" /M *.pdf /D -60 /C "cmd /c move @path C:Arsiv"
Eğer arşiv klasörü içinde tarih bazlı bir yapı oluşturmak istersen biraz daha karmaşık bir yaklaşım gerekir. Bu durumda önce klasörü oluşturup sonra taşıma işlemi yapılır. Bunu bir .bat dosyasında şöyle organize edebilirsin:
@echo off
set ARSIV=C:Arsiv%date:~10,4%-%date:~7,2%-%date:~4,2%
if not exist "%ARSIV%" mkdir "%ARSIV%"
forfiles /P "C:Raporlar" /M *.pdf /D -60 /C "cmd /c move @path "%ARSIV%""
echo Arsivleme tamamlandi: %date% %time% >> "C:Scriptsarsiv_log.txt"
Bu script her çalıştığında o günün tarihiyle bir klasör oluşturur ve 60 günden eski PDF dosyalarını oraya taşır. Görev Zamanlayıcı ile her ay 1’inde çalışacak şekilde ayarlandığında tamamen otomatik bir arşivleme sistemi elde edersin.
Senaryo 3: Toplu Dosya Yeniden Adlandırma
Forfiles ile doğrudan rename yapamazsın ama ren komutunu çağırarak bunu başarabilirsin. Örneğin tüm .bak dosyalarına tarih eklemek:
forfiles /P "C:Backups" /M *.bak /C "cmd /c ren @file @fname_%date:~10,4%%date:~7,2%%date:~4,2%@ext"
Daha pratik bir senaryo: Tüm geçici dosyaların başına OLD_ eklemek:
forfiles /P "C:TempFiles" /M *.tmp /C "cmd /c ren @file OLD_@fname@ext"
Dikkat etmen gereken nokta şu: @file tırnak işaretleriyle gelir. Eğer dosya adında boşluk varsa bu tırnak işaretleri işe yarar ama bazı komutlarda sorun çıkarabilir. Bu durumda tırnakları açıkça yönetmen gerekebilir.
Senaryo 4: Dosya Boyutuna Göre Raporlama
Forfiles tarih filtresi kadar bilinen olmasa da dosya bilgilerini raporlamak için de kullanılabilir. Örneğin 30 günden eski ve dosya yollarını bir rapora yazmak:
forfiles /P "C:AppLogs" /S /M *.log /D -30 /C "cmd /c echo @fdate @ftime @fsize @path" >> "C:Raporlareski_dosyalar.txt"
Bu raporu her hafta otomatik oluşturup ilgili kişilere mail atmak için Task Scheduler ile SendEmail veya PowerShell’in Send-MailMessage cmdlet’iyle birleştirebilirsin.
Belirli bir tarihten sonra oluşturulan dosyaları bulmak da mümkün. Örneğin 15 Ocak 2024’ten sonra değiştirilen dosyalar:
forfiles /P "C:Data" /S /D +15/01/2024 /C "cmd /c echo @path @fdate"
Senaryo 5: Klasörlere Özel İşlem Yapmak
@isdir değişkeni sayesinde sadece klasörlere ya da sadece dosyalara işlem uygulayabilirsin. Örneğin boş klasörleri tespit etmek için:
forfiles /P "C:Projects" /M * /C "cmd /c if @isdir==TRUE echo @path"
Ya da 90 günden eski tüm backup klasörlerini silmek için:
forfiles /P "D:Backups" /D -90 /C "cmd /c if @isdir==TRUE rmdir /S /Q @path"
Uyarı: rmdir /S /Q içinde ne olursa olsun sorumsuzca siler. Bunu production’da kullanmadan önce mutlaka test edin ve kritik veriler için ayrı bir kontrol mekanizması ekleyin.
Senaryo 6: Çoklu Uzantı ile Çalışmak
Forfiles’in bir kısıtlaması şudur: /M parametresi tek bir maske kabul eder. Hem .log hem .tmp hem .bak dosyalarını temizlemek istersen farklı yöntemler kullanman gerekir.
Yöntem 1: Forfiles’i birden fazla çalıştırmak
@echo off
forfiles /P "C:Temp" /M *.log /D -7 /C "cmd /c del /Q @path"
forfiles /P "C:Temp" /M *.tmp /D -7 /C "cmd /c del /Q @path"
forfiles /P "C:Temp" /M *.bak /D -7 /C "cmd /c del /Q @path"
echo Temizlik tamamlandi: %date% %time%
Yöntem 2: Bir döngü içinde kullanmak
@echo off
for %%E in (log tmp bak temp old) do (
forfiles /P "C:Temp" /M *.%%E /D -7 /C "cmd /c del /Q @path" 2>nul
echo %%E uzantili dosyalar temizlendi
)
echo Tum temizlik tamamlandi: %date% %time% >> C:Scriptstemizlik.log
2>nul eklemesinin sebebi şu: Eğer ilgili uzantıda hiç dosya bulunamazsa forfiles bir hata kodu döndürür ve bu hata mesajı ekrana basar. 2>nul bunu bastırır.
Senaryo 7: Ağ Paylaşımlarında Kullanım
Forfiles sadece yerel disklerle değil, UNC yollarıyla da çalışır. Bir dosya sunucusundaki eski dosyaları temizlemek için:
forfiles /P "\FILESERVER01PaylasimGecici" /S /M *.tmp /D -14 /C "cmd /c del /Q @path"
Ancak burada dikkat etmen gereken birkaç nokta var. Script’i çalıştıran kullanıcının veya servis hesabının ilgili ağ paylaşımında yazma yetkisi olması gerekir. Scheduled Task kullanıyorsan, task’ı uygun yetkiye sahip bir domain hesabıyla çalıştırman şart.
Ayrıca ağ bağlantısı kesilirse script yarıda kalabilir. Kritik temizlik işlemleri için başlangıçta bağlantı kontrolü eklemek iyi bir pratiktir:
@echo off
ping -n 1 FILESERVER01 >nul 2>&1
if errorlevel 1 (
echo HATA: Sunucuya eresilemiyor >> C:Scriptshata.log
exit /b 1
)
forfiles /P "\FILESERVER01PaylasimGecici" /S /M *.tmp /D -14 /C "cmd /c del /Q @path"
Hata Yönetimi ve Logging
Production scriptlerinde hata yönetimi kritiktir. Forfiles bir hata aldığında errorlevel değeri sıfırdan farklı olur. Bunu kontrol etmek için:
@echo off
set LOGFILE=C:Scriptstemizlik_%date:~10,4%%date:~7,2%%date:~4,2%.log
echo Temizlik basladi: %date% %time% >> %LOGFILE%
forfiles /P "C:Logs" /S /M *.log /D -30 /C "cmd /c echo Siliniyor: @path && del /Q @path" >> %LOGFILE% 2>&1
if errorlevel 1 (
echo HATA: Forfiles bir hata ile karsilasti. Kod: %errorlevel% >> %LOGFILE%
) else (
echo Temizlik basariyla tamamlandi >> %LOGFILE%
)
echo Temizlik bitti: %date% %time% >> %LOGFILE%
Bu script hem ne yapıldığını kaydeder hem de hata durumunda log’a yazar. Log dosyası adında tarih olduğu için her gün ayrı bir log oluşur.
Windows Server’da Görev Zamanlayıcı ile Entegrasyon
Temizlik scriptini elle çalıştırmak pratik değil, asıl güç otomasyonda. Aşağıdaki komutla Task Scheduler’a görev ekleyebilirsin:
schtasks /create /tn "Gunluk Log Temizligi" /tr "C:Scriptslog_temizlik.bat" /sc daily /st 02:00 /ru SYSTEM /f
Bu komut her gece saat 02:00’de SYSTEM hesabıyla scripti çalıştıran bir görev oluşturur. /f parametresi aynı isimde görev varsa üzerine yazar.
Görevi haftalık yapmak istersen:
schtasks /create /tn "Haftalik Arsivleme" /tr "C:Scriptsarsivle.bat" /sc weekly /d MON /st 01:00 /ru "DOMAINServiceAccount" /rp "Sifre123!" /f
Tabii schtasks ile şifre açık yazmak güvenlik açığı oluşturabilir. Bu yüzden GUI üzerinden veya PowerShell’in Register-ScheduledTask cmdlet’iyle yapmak daha güvenlidir.
Yaygın Hatalar ve Çözümleri
“No files found with the specified search criteria” hatası: Bu hata belirtilen kriterlere uyan dosya bulunamadığında oluşur. Script’in çökmemesi için 2>nul ekle.
Boşluklu yol sorunları: Klasör adında boşluk varsa /P parametresini tırnak içine almayı unutma:
forfiles /P "C:Program FilesMyAppLogs" /M *.log /D -7 /C "cmd /c del @path"
Tarih formatı sorunu: /D parametresinde tarih formatı sistemin bölgesel ayarlarına bağlıdır. Türkçe Windows’ta GG/AA/YYYY formatı kullanılır. Sunucuyu başka bir locale ile kurduysanız format değişebilir. Bunu kontrol etmek için önce echo %date% çalıştırıp formatı gör.
@path ile @file farkı: @file sadece dosya adını (tırnaklı) verirken @path tam yolu verir. del komutu için @path kullanman gerekir, yoksa çalışma dizinine göre arar.
Forfiles vs PowerShell: Ne Zaman Hangisini Kullanmalı?
Bu soruyu çok alıyorum. Kısa cevap: ikisinin de yeri var.
Forfiles tercih et eğer:
- Basit, hızlı bir script yazman gerekiyorsa
- PowerShell yüklü olmayan eski sistemlerde çalışıyorsan
- CMD’de zaten çalışan bir scripte entegre edeceksen
- Execution policy kısıtlamaları sorun çıkarıyorsa
PowerShell tercih et eğer:
- Karmaşık filtreleme mantığı gerekiyorsa
- Dosya boyutuna göre de filtreleme yapacaksan (forfiles bunu doğrudan desteklemez)
- E-posta gönderme, veritabanına yazma gibi ek işlemler yapacaksan
- Daha ayrıntılı hata yönetimi istiyorsan
İkisini karıştırmaktan korkmayın. Bir batch script içinde hem forfiles hem PowerShell one-liner kullanmak gayet meşru bir yaklaşımdır.
Pratik İpuçları
Gerçek dünyada bu aracı kullanırken öğrendiğim birkaç önemli ipucu:
- Önce test et, sonra sil: Her yeni script için önce
echoile çıktıyı gör, ancak sonra gerçek komutu çalıştır. - Log klasörlerini koru: Temizlik scriptlerinin log dosyalarını da temizlememesine dikkat et. Log yolunu temizlik kapsamı dışında tut.
- Minimum yetki prensibi: Scheduled task’ları her zaman ihtiyaç duyduğu minimum yetkiye sahip hesapla çalıştır.
- Kritik klasörleri hariç tut: Windows sistem klasörlerine asla forfiles ile dokunma.
- Backup sonrası temizlik: Dosyaları silmeden önce bir backup veya arşivleme adımı ekle.
Sonuç
forfiles küçük ama son derece güçlü bir araçtır. Özellikle log yönetimi, geçici dosya temizliği ve periyodik arşivleme gibi görevlerde Görev Zamanlayıcı ile birleştirildiğinde tam anlamıyla “çalıştır ve unut” tipi bir otomasyon sağlar. Sözdizimi ilk bakışta biraz tuhaf gelebilir ama birkaç kez kullandıktan sonra ezberden yazacak hale gelirsin.
Bir Windows Server ortamını yönetiyorsan disk dolması sorunlarının büyük bölümü eski log ve geçici dosyalardan kaynaklanır. Düzgün kurgulanmış bir forfiles tabanlı temizlik sistemi bu sorunu kökünden çözer ve seni gece saatlerinde uyandıran “disk full” alarmlarından kurtarır. Bunu kurmak için harcayacağın bir saatin getirisi aylarca sürecek rahatlıktır. Hızlıca bir test ortamında dene, scripti olgunlaştır ve production’a al. Pişman olmayacaksın.