PowerShell ile Dosya ve Klasör Yönetimi: Kapsamlı Rehber

Dosya ve klasör yönetimi, bir sistem yöneticisinin günlük rutininin belki de en büyük parçasını oluşturuyor. Eski usul Windows Explorer’da tıklayıp durmak, onlarca sunucuyu yönetirken artık bir seçenek değil. PowerShell bu noktada hayat kurtarıcı oluyor; hem tekrar eden işleri otomatize edebiliyorsunuz, hem de yüzlerce dosya üzerinde saniyeler içinde işlem yapabiliyorsunuz. Bu yazıda dosya ve klasör yönetiminde PowerShell’i gerçekten verimli kullanmanızı sağlayacak komutları, senaryoları ve scriptleri ele alacağız.

Temel Dosya ve Klasör Komutları

PowerShell’de dosya sistemi işlemleri için kullandığımız cmdlet’ler oldukça tutarlı bir isimlendirme yapısına sahip. Get-Item, New-Item, Copy-Item, Move-Item, Remove-Item gibi fiil-isim yapısı sayesinde ne yaptığını bilmediğiniz bir komut bile mantıklı geliyor ilk bakışta.

Klasör içeriğini listelemek için Get-ChildItem kullanıyoruz. Eski CMD alışkanlığıyla dir veya ls de çalışıyor çünkü bunlar alias olarak tanımlı, ama script yazarken her zaman tam cmdlet adını kullanın:

# Bir klasörün içeriğini listele
Get-ChildItem -Path "C:Logs"

# Alt klasörlerle birlikte tüm içeriği listele
Get-ChildItem -Path "C:Logs" -Recurse

# Sadece belirli uzantıdaki dosyaları getir
Get-ChildItem -Path "C:Logs" -Filter "*.log" -Recurse

# Gizli dosyaları da dahil et
Get-ChildItem -Path "C:UsersAdmin" -Force -Hidden

-Filter parametresi -Include‘a göre çok daha hızlı çalışır çünkü filtrelemeyi dosya sistemi sürücüsüne devreder. Büyük dizinlerde bu fark gözle görülür hale gelir.

Yeni dosya veya klasör oluşturmak için New-Item kullanıyoruz:

# Yeni klasör oluştur
New-Item -Path "C:Backup2024" -ItemType Directory

# Yeni boş dosya oluştur
New-Item -Path "C:Logsuygulama.log" -ItemType File

# İç içe klasör yapısını tek seferde oluştur
New-Item -Path "C:ProjelerWebAppLogsArchive" -ItemType Directory -Force

-Force parametresi burada çok işe yarıyor; ara klasörler yoksa bile oluşturuyor, varsa hata vermeden devam ediyor.

Dosya Kopyalama ve Taşıma İşlemleri

Copy-Item ve Move-Item günlük hayatta en çok kullandığınız cmdlet’ler arasına giriyor. Basit görünse de birkaç önemli nüans var:

# Tek dosya kopyala
Copy-Item -Path "C:Configapp.config" -Destination "C:Backupapp.config"

# Klasörü içeriğiyle kopyala (Recurse şart)
Copy-Item -Path "C:WebSite" -Destination "D:BackupWebSite" -Recurse

# Birden fazla dosyayı kopyala (wildcard ile)
Copy-Item -Path "C:Logs*.log" -Destination "D:Archive"

# Hedef yoksa oluşturarak kopyala
Copy-Item -Path "C:Data" -Destination "E:YedekData" -Recurse -Force

Gerçek dünya senaryosuna bakalım: Diyelim ki her gece uygulama konfigürasyon dosyalarını yedeklemeniz gerekiyor ve yedek dosya adına tarih eklemek istiyorsunuz:

# Tarih damgalı yedek alma
$tarih = Get-Date -Format "yyyyMMdd_HHmm"
$kaynak = "C:IISConfigapplicationHost.config"
$hedef = "D:YedekapplicationHost_$tarih.config"

Copy-Item -Path $kaynak -Destination $hedef
Write-Host "Yedek alindi: $hedef" -ForegroundColor Green

Bu kadar basit bir script bile Task Scheduler ile birleşince çok güçlü bir yedekleme rutinine dönüşüyor.

Dosya İçeriği Okuma ve Yazma

Log analizi, konfig dosyası düzenleme, rapor oluşturma gibi işler için dosya içeriğiyle çalışmak kaçınılmaz. PowerShell burada da oldukça yetenekli:

# Dosya içeriğini oku
$icerik = Get-Content -Path "C:Logsuygulama.log"

# Son 50 satırı oku (büyük log dosyaları için)
Get-Content -Path "C:Logsuygulama.log" -Tail 50

# Dosyayı canlı takip et (Linux'taki tail -f gibi)
Get-Content -Path "C:Logsuygulama.log" -Wait

# Belirli bir ifadeyi içeren satırları bul
Get-Content -Path "C:Logsuygulama.log" | Where-Object { $_ -match "ERROR" }

# Dosyaya yaz (üzerine yazar)
Set-Content -Path "C:Temprapor.txt" -Value "Rapor icerigi buraya"

# Dosyaya ekle (mevcut içeriği korur)
Add-Content -Path "C:Logsislem.log" -Value "$(Get-Date): Islem tamamlandi"

Büyük log dosyalarıyla uğraşırken Get-Content‘in dosyanın tamamını belleğe aldığını unutmayın. 2GB’lık bir log dosyasını Get-Content ile okumaya çalışırsanız sunucunuzun memory’si şikayet edebilir. Bu durumda Switch parametresini veya StreamReader kullanmak daha akıllıca:

# Büyük dosyaları satır satır işle (bellek dostu)
$reader = [System.IO.StreamReader]::new("C:Logsbuyuk_log.txt")
while ($null -ne ($satir = $reader.ReadLine())) {
    if ($satir -match "CRITICAL") {
        Write-Output $satir
    }
}
$reader.Close()

Dosya Silme ve Temizlik İşlemleri

Disk temizliği, eski log dosyalarını kaldırma, geçici dosyaları silme gibi işler sysadmin hayatının rutin parçası. Remove-Item burada devreye giriyor:

# Tek dosya sil
Remove-Item -Path "C:Tempgecici.txt"

# Klasörü içeriğiyle birlikte sil
Remove-Item -Path "C:OldLogs" -Recurse -Force

# Onay sormadan sil
Remove-Item -Path "C:Temp*" -Force

# Silmeden önce ne silineceğini gör (WhatIf)
Remove-Item -Path "C:Logs*.log" -WhatIf

-WhatIf parametresi gerçekten hayat kurtarıcı. Özellikle -Recurse ve -Force kombinasyonu kullanırken silmeden önce mutlaka WhatIf ile ne olacağına bakın.

Şimdi gerçekçi bir senaryo: 30 günden eski log dosyalarını temizleyen bir script:

# Eski log temizleme scripti
$logKlasor = "C:UygulamaLogs"
$gunSiniri = 30
$silinecekler = Get-ChildItem -Path $logKlasor -Filter "*.log" -Recurse |
    Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$gunSiniri) }

if ($silinecekler.Count -eq 0) {
    Write-Host "Silinecek dosya bulunamadi." -ForegroundColor Yellow
} else {
    Write-Host "$($silinecekler.Count) dosya silinecek:" -ForegroundColor Cyan
    $silinecekler | ForEach-Object {
        Write-Host "  Siliniyor: $($_.FullName)" -ForegroundColor Red
        Remove-Item -Path $_.FullName -Force
    }
    Write-Host "Temizlik tamamlandi." -ForegroundColor Green
}

Bu scripti Task Scheduler’a ekleyip her hafta çalıştırdığınızda disk doluluk problemleri büyük ölçüde azalıyor.

Dosya Özellikleri ve Metadata ile Çalışmak

Dosyaları boyutlarına, tarihlerine, özelliklerine göre filtrelemek günlük işlerde sık karşılaşılan bir ihtiyaç. Get-Item ve Get-ChildItem döndürdüğü nesnelerin özellikleri bu konuda çok yardımcı oluyor:

# Dosya özelliklerini gör
$dosya = Get-Item "C:Logssistem.log"
$dosya.Length          # Boyut (byte)
$dosya.LastWriteTime   # Son değiştirilme tarihi
$dosya.CreationTime    # Oluşturulma tarihi
$dosya.Attributes      # Dosya özellikleri

# 100MB üzerindeki dosyaları bul
Get-ChildItem -Path "C:" -Recurse -ErrorAction SilentlyContinue |
    Where-Object { $_.Length -gt 100MB } |
    Sort-Object Length -Descending |
    Select-Object FullName, @{N="Boyut_MB";E={[math]::Round($_.Length/1MB,2)}}

# En son değiştirilen 10 dosyayı bul
Get-ChildItem -Path "C:WebApp" -Recurse -File |
    Sort-Object LastWriteTime -Descending |
    Select-Object -First 10 FullName, LastWriteTime

Disk doluluk analizi yaparken en çok yer kaplayan klasörleri bulmak isteyebilirsiniz:

# Klasör boyutlarını hesapla ve listele
Get-ChildItem -Path "C:" -Directory |
    ForEach-Object {
        $boyut = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue |
            Measure-Object -Property Length -Sum).Sum
        [PSCustomObject]@{
            Klasor = $_.Name
            Boyut_GB = [math]::Round($boyut/1GB, 2)
        }
    } | Sort-Object Boyut_GB -Descending

ACL ve İzin Yönetimi

Dosya izinleri Windows ortamında ciddi bir konu. PowerShell ile NTFS izinlerini görüntülemek ve değiştirmek mümkün, üstelik GUI’ye hiç dokunmadan:

# Bir klasörün izinlerini görüntüle
Get-Acl -Path "C:SharedProje" | Format-List

# İzin listesini daha okunabilir hale getir
(Get-Acl -Path "C:SharedProje").Access |
    Select-Object IdentityReference, FileSystemRights, AccessControlType

# Yeni bir kullanıcıya okuma izni ver
$acl = Get-Acl -Path "C:SharedProje"
$izin = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "DOMAINkullanici",
    "Read",
    "ContainerInherit,ObjectInherit",
    "None",
    "Allow"
)
$acl.SetAccessRule($izin)
Set-Acl -Path "C:SharedProje" -AclObject $acl
Write-Host "Izin basariyla eklendi." -ForegroundColor Green

Birden fazla klasöre aynı izni uygulamak gerektiğinde bu yaklaşım GUI’ye kıyasla çok büyük zaman tasarrufu sağlıyor.

Sembolik Link ve Junction Oluşturma

Modern Windows ortamlarında sembolik link ve junction kullanımı giderek yaygınlaşıyor. Özellikle uygulama verilerini farklı disklere taşırken veya paylaşımlı kaynak yapılandırırken işe yarıyor:

# Sembolik link oluştur (yönetici yetkisi gerekir)
New-Item -ItemType SymbolicLink -Path "C:AppDataLogs" -Target "D:LogsApp"

# Junction oluştur
New-Item -ItemType Junction -Path "C:OldPath" -Target "D:NewPath"

# Mevcut linkleri görmek için
Get-ChildItem -Path "C:" | Where-Object { $_.Attributes -match "ReparsePoint" }

Toplu Yeniden Adlandırma

Onlarca hatta yüzlerce dosyayı yeniden adlandırmak GUI ile çile, PowerShell ile birkaç satır:

# Tüm .txt dosyalarını .bak olarak yeniden adlandır
Get-ChildItem -Path "C:Temp" -Filter "*.txt" |
    Rename-Item -NewName { $_.Name -replace ".txt$", ".bak" }

# Dosya adlarındaki boşlukları alt çizgi ile değiştir
Get-ChildItem -Path "C:Belgeler" -Filter "* *" |
    Rename-Item -NewName { $_.Name -replace " ", "_" }

# Dosyalara sıra numarası ekle
$i = 1
Get-ChildItem -Path "C:Resimler" -Filter "*.jpg" |
    ForEach-Object {
        $yeniAd = "resim_{0:D3}.jpg" -f $i
        Rename-Item -Path $_.FullName -NewName $yeniAd
        $i++
    }

Dosya Arama ve İçerik Tarama

Büyük bir sunucu ortamında belirli bir içeriği veya dosyayı bulmak zorunda kaldığınızda Select-String çok işlevli bir araç:

# Dosyalar içinde metin ara (grep benzeri)
Select-String -Path "C:Logs*.log" -Pattern "connection refused"

# Alt klasörlerde de ara
Get-ChildItem -Path "C:WebApp" -Filter "*.config" -Recurse |
    Select-String -Pattern "connectionString"

# Büyük/küçük harf duyarsız arama
Select-String -Path "C:Scripts*.ps1" -Pattern "password" -CaseSensitive:$false

# Sonuçları dosyaya yaz
Get-ChildItem -Path "C:Logs" -Filter "*.log" -Recurse |
    Select-String -Pattern "ERROR|CRITICAL" |
    Out-File -FilePath "C:Raporhatalar.txt"

Bir web sunucusunun tüm config dosyalarında eski bir veritabanı sunucu adını aramak istediğinizde bu komut dakikalar içinde sonucu veriyor.

Pratik Bir Yedekleme Scripti

Tüm öğrendiklerimizi bir araya getiren, production’da kullanılabilecek bir yedekleme scripti yazalım:

# Kapsamli yedekleme scripti
param(
    [string]$KaynakKlasor = "C:IISwwwroot",
    [string]$YedekKlasor = "D:Yedekler",
    [int]$MaxYedekSayisi = 7
)

$tarih = Get-Date -Format "yyyyMMdd_HHmmss"
$yedekYolu = Join-Path $YedekKlasor "yedek_$tarih"
$logDosyasi = Join-Path $YedekKlasor "yedekleme.log"

function Yaz-Log {
    param([string]$Mesaj, [string]$Seviye = "INFO")
    $logSatiri = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [$Seviye] $Mesaj"
    Add-Content -Path $logDosyasi -Value $logSatiri
    $renk = switch ($Seviye) {
        "INFO"  { "White" }
        "OK"    { "Green" }
        "WARN"  { "Yellow" }
        "ERROR" { "Red" }
    }
    Write-Host $logSatiri -ForegroundColor $renk
}

# Yedek klasoru olustur
if (-not (Test-Path $YedekKlasor)) {
    New-Item -Path $YedekKlasor -ItemType Directory -Force | Out-Null
}

Yaz-Log "Yedekleme baslatildi: $KaynakKlasor"

# Kaynak kontrol
if (-not (Test-Path $KaynakKlasor)) {
    Yaz-Log "Kaynak klasor bulunamadi: $KaynakKlasor" "ERROR"
    exit 1
}

# Kopyalama
try {
    Copy-Item -Path $KaynakKlasor -Destination $yedekYolu -Recurse -Force
    $dosyaSayisi = (Get-ChildItem -Path $yedekYolu -Recurse -File).Count
    Yaz-Log "Yedek alindi: $yedekYolu ($dosyaSayisi dosya)" "OK"
} catch {
    Yaz-Log "Yedekleme hatasi: $_" "ERROR"
    exit 1
}

# Eski yedekleri temizle
$eskiYedekler = Get-ChildItem -Path $YedekKlasor -Directory |
    Where-Object { $_.Name -like "yedek_*" } |
    Sort-Object CreationTime -Descending |
    Select-Object -Skip $MaxYedekSayisi

foreach ($eski in $eskiYedekler) {
    Remove-Item -Path $eski.FullName -Recurse -Force
    Yaz-Log "Eski yedek silindi: $($eski.Name)" "WARN"
}

Yaz-Log "Yedekleme tamamlandi." "OK"

Bu script parametrik çalışıyor, loglama yapıyor, hata durumunu ele alıyor ve eski yedekleri otomatik temizliyor. Task Scheduler ile çalıştırdığınızda tamamen otomatik bir yedekleme sisteminiz oluyor.

Hata Yönetimi ve Güvenli Kullanım

Dosya sistemi işlemlerinde hata yönetimi kritik. Yanlış bir silme komutu gerçekten zarar verebilir:

# ErrorAction ile hataları yonet
Get-ChildItem -Path "C:SilinmisKlasor" -ErrorAction SilentlyContinue

# Try-Catch ile kritik islemler
try {
    Remove-Item -Path "C:KritikVeri" -Recurse -Force -ErrorAction Stop
    Write-Host "Silme basarili" -ForegroundColor Green
} catch {
    Write-Host "Hata olustu: $($_.Exception.Message)" -ForegroundColor Red
}

# Silmeden once yedek al
$hedef = "C:Configweb.config"
$yedek = "C:Backupweb_$(Get-Date -Format 'yyyyMMdd').config"
Copy-Item -Path $hedef -Destination $yedek
# Yedek basariliysa devam et
if (Test-Path $yedek) {
    # Asil islemi yap
    Set-Content -Path $hedef -Value $yeniIcerik
}

-ErrorAction Stop kullanmayı alışkanlık edinin; bu sayede hatalı işlemler sessizce geçip gitmez, catch bloğunuzda yakalanır.

Sonuç

PowerShell ile dosya ve klasör yönetimi, GUI tabanlı işlemlere kıyasla hem çok daha hızlı hem de çok daha güvenilir. Tekrar eden işleri otomatize edebilmek, yüzlerce dosyayı saniyeler içinde işlemek, hata yönetimini merkezi bir şekilde sağlamak; bunların hepsi scripting dünyasının getirdiği avantajlar.

Başlangıç için birkaç pratik öneri: Önce -WhatIf ile komutlarınızı test edin, özellikle silme ve taşıma işlemlerinde. Kritik işlemler öncesi mutlaka yedek alın. Scriptlerinize loglama ekleyin, aylarca sonra ne olduğunu anlayabilmek için bu şart. Son olarak, sık kullandığınız işlemleri fonksiyonlara döküp bir module haline getirin; hem tekrar kullanırsınız hem de ekibinizle paylaşabilirsiniz.

Dosya sistemi işlemlerini PowerShell ile otomatize etmeye başladığınızda, “bunu neden daha önce yapmadım” diye düşünmeniz kaçınılmaz. Küçük scriptlerle başlayın, zamanla daha karmaşık senaryoları çözmeye başlarsınız ve sonunda saatlerce süren manuel işleri dakikalara indirmiş olursunuz.

Yorum yapın