Active Directory ortamlarında çalışan her sysadmin, günün birinde onlarca PowerShell komutunun çıktısını bir yere kaydetme ihtiyacı duyar. Ekrana dökülen bilgileri kopyala-yapıştır yapmak, üzerine not almak ya da ertesi gün “acaba ne yapmıştım” diye bakmak için bir dosya olmadığında işler hızla karmaşıklaşır. İşte tam bu noktada çıktı yönlendirme operatörü > devreye giriyor ve sysadmin hayatını ciddi ölçüde kolaylaştırıyor.
Bu yazıda Windows Server ve Active Directory yönetimi bağlamında > operatörünü, onun kardeşi >> ile birlikte, PowerShell ve CMD ortamlarında nasıl kullanacağını anlatacağım. Sadece teorik değil, gerçek dünyada karşılaşacağın senaryoları da ele alacağız.
Çıktı Yönlendirme Nedir ve Neden Önemlidir?
Normalde bir komut çalıştırdığında çıktı stdout (standart çıktı) kanalı üzerinden konsol ekranına gelir. Çıktı yönlendirme ile bu akışı ekran yerine bir dosyaya, başka bir komuta veya tamamen farklı bir hedefe göndeririz.
Windows ortamında iki temel yönlendirme operatörü vardır:
>: Çıktıyı belirtilen dosyaya yazar. Dosya varsa üzerine yazar, yoksa oluşturur.>>: Çıktıyı belirtilen dosyaya ekler. Dosya varsa sonuna ekler, yoksa oluşturur.
Active Directory yönetiminde bu operatörlerin önemi şuradan geliyor: Kullanıcı denetimleri, grup üyelikleri, GPO raporları, parola politikası kontrolleri… Bunların hepsinin çıktısını kayıt altına almak hem güvenlik hem de operasyonel süreçler açısından zorunluluk haline geliyor.
CMD ile Temel Kullanım
Eski usul ama hala geçerliliğini koruyan CMD ortamında > kullanımı oldukça basittir.
dir C:WindowsSystem32 > sistem32_listesi.txt
Bu komut dir çıktısını ekrana basmak yerine sistem32_listesi.txt dosyasına yazar. Dosyayı açtığında dizin listesini aynen görürsün.
Birden fazla kez çalıştırırsan ne olur? Her seferinde dosyanın üzerine yazar. Önceki içerik gider. Bunu akılda tutmak önemli, özellikle log biriktirme senaryolarında.
ipconfig /all > ag_bilgileri.txt
Bu kadar basit. Peki hata mesajlarını da kaydetmek istersen? Burada stderr (standart hata) devreye girer. CMD’de hata çıktısı 2 numaralı kanaldır.
net user > kullanici_listesi.txt 2>&1
2>&1 ifadesi “2 numaralı kanalı (stderr) 1 numaralı kanala (stdout) yönlendir” demek. Böylece hem normal çıktı hem de hata mesajları aynı dosyaya düşer.
PowerShell’de Yönlendirme: Daha Güçlü, Daha Esnek
PowerShell, CMD’nin çok ötesine geçen bir yönlendirme sistemi sunar. Active Directory yönetiminde neredeyse her zaman PowerShell kullanacaksın, o yüzden bu kısmı iyi kavramak gerekiyor.
Get-ADUser -Filter * -Properties DisplayName,EmailAddress | Select-Object Name,DisplayName,EmailAddress > tum_kullanicilar.txt
Bu komut domain’deki tüm kullanıcıları alıp belirtilen özellikleri seçiyor ve tum_kullanicilar.txt dosyasına yazıyor. Burada dikkat: PowerShell’in > operatörü çıktıyı Unicode formatında kaydeder. Türkçe karakterler varsa bu önemli.
Encoding sorunuyla karşılaşırsan:
Get-ADUser -Filter * -Properties DisplayName | Select-Object Name,DisplayName | Out-File -FilePath "kullanicilar.txt" -Encoding UTF8
Out-File cmdlet’i encoding kontrolü için daha uygun. > operatörü aslında arka planda Out-File‘ı çağırır ama parametrelerini doğrudan kontrol edemezsin.
Active Directory Senaryolarında Pratik Kullanım
Kullanıcı Denetim Raporları
Şöyle bir senaryo düşün: Güvenlik ekibi senden son 90 gün içinde hiç giriş yapmamış kullanıcıların listesini istiyor. Bu listeyi mail atacaksın ve belgeleme amacıyla saklayacaksın.
$tarih = (Get-Date).AddDays(-90)
Get-ADUser -Filter {LastLogonDate -lt $tarih -and Enabled -eq $true} `
-Properties LastLogonDate,Department,Manager `
| Select-Object Name,SamAccountName,LastLogonDate,Department `
| Sort-Object LastLogonDate `
> "C:Raporlarpasif_kullanicilar_$(Get-Date -Format 'yyyyMMdd').txt"
Burada $(Get-Date -Format 'yyyyMMdd') ile dosya adına tarih ekliyoruz. Her çalıştırmada farklı bir dosya oluşuyor, eski raporlar kaybolmuyor. Bu çok önemli bir pratik nokta.
Grup Üyeliklerini Kayıt Altına Alma
Kritik grupların üyeliklerini düzenli aralıklarla kaydetmek, olası bir yetkisiz erişim durumunda karşılaştırma yapabilmeni sağlar.
$kritik_gruplar = @("Domain Admins", "Enterprise Admins", "Schema Admins", "Backup Operators")
foreach ($grup in $kritik_gruplar) {
$dosya_adi = $grup.Replace(" ", "_") + "_uyeler.txt"
Write-Output "=== $grup - $(Get-Date) ===" > "C:Guvenlik$dosya_adi"
Get-ADGroupMember -Identity $grup -Recursive |
Select-Object Name,SamAccountName,ObjectClass >> "C:Guvenlik$dosya_adi"
}
Bu script’te ilk satır > ile dosyayı sıfırlıyor ve başlık yazıyor, sonraki satır >> ile üyelik bilgilerini ekliyor. Bu kombinasyon çok sık kullanılan bir pattern.
GPO Raporları Oluşturma
Group Policy nesnelerinin mevcut durumunu kayıt altına almak, özellikle değişiklik öncesi ve sonrası karşılaştırma için hayat kurtarır.
Get-GPO -All | Select-Object DisplayName,Id,GpoStatus,CreationTime,ModificationTime `
| Sort-Object DisplayName `
> "C:RaporlarGPO_envanteri_$(Get-Date -Format 'yyyyMMdd').txt"
Daha detaylı rapor için:
$gpo_listesi = Get-GPO -All
foreach ($gpo in $gpo_listesi) {
$rapor_yolu = "C:RaporlarGPO_$($gpo.DisplayName.Replace(' ','_')).html"
Get-GPOReport -Guid $gpo.Id -ReportType HTML > $rapor_yolu
}
Bu sefer HTML raporu oluşturuyoruz. Her GPO için ayrı bir dosya oluşuyor ve > her seferinde o dosyayı yeniden yazıyor. GPO değişiklik öncesi bu script’i çalıştırıp sonrasında da çalıştırırsan, iki HTML dosyasını yan yana açıp karşılaştırabilirsin.
Hata Çıktısını Yönetmek
PowerShell’de hata yönetimi biraz farklı çalışır. Akışlar şu şekilde numaralandırılmıştır:
- 1: Başarı çıktısı (Success/stdout)
- 2: Hata çıktısı (Error)
- 3: Uyarı çıktısı (Warning)
- 4: Ayrıntılı çıktı (Verbose)
- 5: Debug çıktısı (Debug)
- 6: Bilgi çıktısı (Information)
Tüm çıktıları tek dosyaya toplamak:
Get-ADUser -Filter * -Properties * *> "C:Loglartam_cikti.txt"
*> tüm akışları yönlendirir. Sadece hataları yakalamak için:
Get-ADComputer -Filter * 2> "C:Loglarhatalar.txt"
Büyük bir AD temizlik işlemi yaparken, başarıyla işlenen nesneleri bir dosyaya hataları ayrı bir dosyaya yazmak isteyebilirsin:
$bilgisayarlar = Import-Csv "C:devre_disi_bilgisayarlar.csv"
foreach ($bilgisayar in $bilgisayarlar) {
try {
Disable-ADAccount -Identity $bilgisayar.SamAccountName
"$($bilgisayar.SamAccountName) - Devre disi birakildi - $(Get-Date)" >> "C:Loglarbasarili.txt"
}
catch {
"$($bilgisayar.SamAccountName) - HATA: $($_.Exception.Message) - $(Get-Date)" >> "C:Loglarhatali.txt"
}
}
Bu pattern’i çok kullanıyorum. Başarılı işlemler basarili.txt‘ye, hatalar hatali.txt‘ye gidiyor. Sabah işe geldiğinde ikisini de kontrol edersin, ne olduğunu anlarsın.
Zamanlanmış Görevlerle Otomatik Raporlama
> ve >> operatörlerinin gerçek gücü, zamanlanmış görevlerle birleşince ortaya çıkar. Şu senaryoyu düşün: Her gün sabah saat 7’de bir AD sağlık raporu oluşturuluyor, log dosyasına ekleniyor ve ekip bunu görüyor.
Önce PowerShell script’ini hazırlayalım:
# AD_Saglik_Raporu.ps1
$tarih = Get-Date -Format "dd.MM.yyyy HH:mm:ss"
$rapor_dosyasi = "C:RaporlarAD_Gunluk_Rapor.txt"
"========================================" >> $rapor_dosyasi
"RAPOR TARIHI: $tarih" >> $rapor_dosyasi
"========================================" >> $rapor_dosyasi
# Toplam kullanici sayisi
$toplam_kullanici = (Get-ADUser -Filter *).Count
"Toplam Kullanici: $toplam_kullanici" >> $rapor_dosyasi
# Aktif kullanici sayisi
$aktif_kullanici = (Get-ADUser -Filter {Enabled -eq $true}).Count
"Aktif Kullanici: $aktif_kullanici" >> $rapor_dosyasi
# Son 24 saatte kilitlenen hesaplar
$kilitli = Get-ADUser -Filter {LockedOut -eq $true} -Properties LockedOut,LastBadPasswordAttempt
"Kilitli Hesap Sayisi: $($kilitli.Count)" >> $rapor_dosyasi
if ($kilitli.Count -gt 0) {
"Kilitli Hesaplar:" >> $rapor_dosyasi
$kilitli | ForEach-Object {
" - $($_.SamAccountName) (Son yanlis giris: $($_.LastBadPasswordAttempt))" >> $rapor_dosyasi
}
}
"" >> $rapor_dosyasi
Bu script her çalıştığında >> ile mevcut rapora ekleme yapıyor. Günler geçtikçe bir geçmiş oluşuyor ve geriye dönük bakabiliyorsun.
Out-File, Set-Content ve Tee-Object Karşılaştırması
> operatörü kullanışlı ama her zaman yeterli değil. Alternatiflerini de bilmek gerekiyor.
Out-File: Encoding, genişlik ve ekleme modu kontrolü için:
Get-ADUser -Filter * | Out-File -FilePath "kullanicilar.txt" -Encoding UTF8 -Width 200 -Append
- -Encoding: UTF8, ASCII, Unicode gibi seçenekler
- -Width: Satır genişliği, uzun çıktılarda kırpılmayı önler
- -Append: Dosyaya ekle, üzerine yazma
Set-Content ve Add-Content: String içerik yazmak için daha temiz:
$kullanici_sayisi = (Get-ADUser -Filter *).Count
Set-Content -Path "ozet.txt" -Value "Toplam kullanici: $kullanici_sayisi" -Encoding UTF8
Add-Content -Path "ozet.txt" -Value "Rapor tarihi: $(Get-Date)"
Tee-Object: Hem ekrana bas hem dosyaya yaz. İnteraktif çalışırken log tutmak için mükemmel:
Get-ADUser -Filter {Enabled -eq $false} |
Select-Object Name,SamAccountName |
Tee-Object -FilePath "pasif_kullanicilar.txt"
Tee-Object ile çıktıyı hem konsolda görürsün hem de dosyaya kaydolur. Uzun süren işlemleri izlerken ve aynı zamanda kayıt tutarken idealdir.
Yaygın Hatalar ve Çözümleri
Türkçe karakter sorunu: > operatörü varsayılan olarak UTF-16 LE kullanır. Türkçe karakterlerde sorun yaşarsan:
Get-ADUser -Filter * | Select-Object Name | Out-File "liste.txt" -Encoding UTF8
Dosya kilitli hatası: Bir script çalışırken aynı dosyaya yazmaya çalışan başka bir işlem varsa erişim hatası alırsın. Dosya adına process ID ekleyerek bunu çözebilirsin:
$dosya = "C:Loglarrapor_$($PID)_$(Get-Date -Format 'yyyyMMddHHmm').txt"
Get-ADDomain > $dosya
Boş dosya oluştu: Komut çıktı vermedi ama yine de > çalıştı, boş dosya oluştu. Bunu önlemek için önce sonucu bir değişkene alıp kontrol edebilirsin:
$sonuc = Get-ADUser -Filter {Department -eq "IT"} | Select-Object Name,SamAccountName
if ($sonuc) {
$sonuc > "IT_kullanicilari.txt"
} else {
Write-Warning "IT departmaninda kullanici bulunamadi."
}
Gerçek Dünya: Aylık AD Denetim Raporu
Hepsini birleştiren bir senaryo ile bitirelim. Her ayın ilk günü otomatik çalışan, kapsamlı bir AD denetim raporu script’i:
# Aylik_AD_Denetim.ps1
$ay = Get-Date -Format "yyyy-MM"
$rapor_klasoru = "C:RaporlarAD_Denetim"
$ana_rapor = "$rapor_klasoruAD_Denetim_$ay.txt"
# Klasoru olustur
if (-not (Test-Path $rapor_klasoru)) {
New-Item -ItemType Directory -Path $rapor_klasoru | Out-Null
}
# Rapor basligini yaz (> ile sifirla)
"AD DENETIM RAPORU - $ay" > $ana_rapor
"Olusturulma: $(Get-Date)" >> $ana_rapor
"Domain: $((Get-ADDomain).DNSRoot)" >> $ana_rapor
"=" * 60 >> $ana_rapor
# Kullanici istatistikleri
"`n--- KULLANICI ISTATISTIKLERI ---" >> $ana_rapor
"Toplam Kullanici: $((Get-ADUser -Filter *).Count)" >> $ana_rapor
"Aktif Kullanici: $((Get-ADUser -Filter {Enabled -eq $true}).Count)" >> $ana_rapor
"Pasif Kullanici: $((Get-ADUser -Filter {Enabled -eq $false}).Count)" >> $ana_rapor
# Parola suresi dolmak uzere olan hesaplar
"`n--- PAROLA SURESI DOLMAK UZERE ---" >> $ana_rapor
$uyari_tarihi = (Get-Date).AddDays(14)
Get-ADUser -Filter {Enabled -eq $true -and PasswordNeverExpires -eq $false} `
-Properties PasswordLastSet,PasswordExpired |
Where-Object { $_.PasswordLastSet -lt (Get-Date).AddDays(-76) } |
Select-Object Name,SamAccountName,PasswordLastSet |
ForEach-Object { " $($_.Name) ($($_.SamAccountName))" >> $ana_rapor }
# Domain Admins listesi
"`n--- DOMAIN ADMINS UYELERI ---" >> $ana_rapor
Get-ADGroupMember "Domain Admins" |
Select-Object Name,SamAccountName |
ForEach-Object { " $($_.Name) ($($_.SamAccountName))" >> $ana_rapor }
"=" * 60 >> $ana_rapor
"Rapor tamamlandi: $(Get-Date)" >> $ana_rapor
Write-Host "Rapor olusturuldu: $ana_rapor" -ForegroundColor Green
İlk kullanımda > ile dosyayı oluşturuyor ve başlığı yazıyor, sonrasında tüm bölümler >> ile ekleniyor. Sonuç, okunabilir ve paylaşılabilir bir metin dosyası.
Sonuç
Çıktı yönlendirme, göründüğünden çok daha derin bir konu. Tek bir > karakteri; raporlama, loglama, denetim ve otomasyon süreçlerinin temel taşı haline gelebiliyor. Active Directory yönetiminde bu operatörü doğru ve tutarlı kullanmak, hem günlük işlerin kolaylaşmasını sağlıyor hem de bir şeyler ters gittiğinde geriye dönük bakabilme imkanı veriyor.
Özetlemek gerekirse:
>ile üzerine yaz, taze başla>>ile ekle, geçmişi koru2>ile hataları ayrı yakala*>ile her şeyi tek dosyaya toplaTee-Objectile hem gör hem kaydet- Dosya adlarına tarih ekle, geçmişi kaybetme
- Encoding’e dikkat et, Türkçe karakter sorununu baştan önle
Bu araçları script’lerine entegre etmeye başladığında, bir hafta içinde “bunu neden daha önce yapmıyordum” diye sorduğunu göreceksin. Denetle, kayıt tut, arşivle. Sysadmin’in en iyi dostu iyi tutulmuş loglardır.