PowerShell ile Disk ve Depolama Yönetimi

Disk yönetimi konusunda sysadmin’lerin en çok zaman harcadığı işlerin başında depolama alanı takibi, disk bölümlendirme ve performans izleme geliyor. Windows Server ortamlarında GUI üzerinden bu işleri yapmak mümkün, ancak onlarca sunucuyu yönetiyorsanız bu yaklaşım sizi yorar. PowerShell ile disk yönetimini öğrendiğinizde, hem zaman kazanırsınız hem de tutarlı, tekrarlanabilir işlemler yapabilirsiniz. Bu yazıda gerçek dünya senaryoları üzerinden PowerShell ile disk ve depolama yönetimini ele alacağız.

Disk Bilgilerini Sorgulamak

Her şeyden önce sistemdeki disklerin durumunu görmek gerekiyor. Get-Disk cmdlet’i bu iş için temel araçtır.

# Tüm diskleri listele
Get-Disk

# Belirli bir disk hakkında detaylı bilgi
Get-Disk -Number 0 | Select-Object *

# Sadece offline diskleri bul
Get-Disk | Where-Object {$_.OperationalStatus -eq "Offline"}

# Disk boyutunu GB cinsinden göster
Get-Disk | Select-Object Number, FriendlyName, 
    @{Name="Size(GB)";Expression={[math]::Round($_.Size/1GB,2)}},
    OperationalStatus, PartitionStyle

Bu komutun çıktısında dikkat etmeniz gereken alanlar şunlar:

  • PartitionStyle: MBR ya da GPT olduğunu gösterir, 2 TB üzeri diskler için GPT zorunludur
  • OperationalStatus: Online, Offline, Unknown gibi değerler alır
  • IsReadOnly: True ise disk yazma korumalıdır
  • IsBoot: Sistemin boot diskini gösterir

Pratik bir senaryo düşünelim. Yeni bir fiziksel sunucu kurulumu yaptınız ve depolama ekibinden 5 adet disk eklendi. Bunların hepsinin düzgün tanınıp tanınmadığını kontrol etmeniz gerekiyor.

# Yeni eklenen ve henüz initialize edilmemiş diskleri bul
$rawDisks = Get-Disk | Where-Object {$_.PartitionStyle -eq "RAW"}
$rawDisks | Select-Object Number, FriendlyName, 
    @{Name="Size(GB)";Expression={[math]::Round($_.Size/1GB,2)}}

# Kaç adet ham disk var?
Write-Host "Toplam initialize edilmemiş disk sayısı: $($rawDisks.Count)" -ForegroundColor Yellow

Disk Partition ve Volume İşlemleri

Diskleri buldunuz, şimdi bunları kullanılabilir hale getirmeniz gerekiyor. Bu adımda Initialize, Partition ve Format işlemlerini sırasıyla yapacaksınız.

# Tek bir disk için tam kurulum süreci
# Disk 1'i GPT olarak initialize et
Initialize-Disk -Number 1 -PartitionStyle GPT -PassThru

# Tüm alanı kaplayan bir partition oluştur
New-Partition -DiskNumber 1 -UseMaximumSize -AssignDriveLetter

# Partition'ı NTFS olarak formatla
$partition = Get-Partition -DiskNumber 1 | Where-Object {$_.Type -eq "Basic"}
Format-Volume -DriveLetter $partition.DriveLetter -FileSystem NTFS `
    -NewFileSystemLabel "DataDisk01" -Confirm:$false

Birden fazla diski aynı anda işlemeniz gerektiğinde döngü kullanmak hayat kurtarır. Diyelim ki 5 adet veri diskini hızlıca kurmanız gerekiyor.

# Tüm RAW diskleri otomatik olarak kur
$diskCounter = 1
Get-Disk | Where-Object {$_.PartitionStyle -eq "RAW"} | ForEach-Object {
    $diskNumber = $_.Number
    
    Write-Host "Disk $diskNumber işleniyor..." -ForegroundColor Cyan
    
    # Initialize
    Initialize-Disk -Number $diskNumber -PartitionStyle GPT -PassThru | Out-Null
    
    # Partition oluştur
    $newPartition = New-Partition -DiskNumber $diskNumber -UseMaximumSize -AssignDriveLetter
    
    # Formatla
    Format-Volume -DriveLetter $newPartition.DriveLetter `
        -FileSystem NTFS `
        -NewFileSystemLabel "DataDisk0$diskCounter" `
        -Confirm:$false | Out-Null
    
    Write-Host "Disk $diskNumber tamamlandi. Surucu harfi: $($newPartition.DriveLetter)" `
        -ForegroundColor Green
    
    $diskCounter++
}

Disk Alanı İzleme ve Raporlama

Sysadmin hayatında en çok gelen ticket türlerinden biri “disk doldu” bildirimleridir. Bu duruma reaktif değil proaktif yaklaşmak gerekiyor.

# Tüm sürücülerin doluluk oranını göster
Get-PSDrive -PSProvider FileSystem | 
    Where-Object {$_.Used -gt 0} |
    Select-Object Name,
        @{Name="Total(GB)";Expression={[math]::Round(($_.Used + $_.Free)/1GB,2)}},
        @{Name="Used(GB)";Expression={[math]::Round($_.Used/1GB,2)}},
        @{Name="Free(GB)";Expression={[math]::Round($_.Free/1GB,2)}},
        @{Name="Used%";Expression={[math]::Round(($_.Used/($_.Used+$_.Free))*100,1)}} |
    Sort-Object "Used%" -Descending

Burada güzel bir uyarı mekanizması kurabilirsiniz. Kritik eşiği aşan diskleri tespit edip mail atması için basit bir script yazalım.

# Disk doluluk uyarı scripti
$threshold = 85  # Yüzde olarak uyarı eşiği
$criticalThreshold = 95  # Kritik eşik
$serverName = $env:COMPUTERNAME
$alerts = @()

Get-PSDrive -PSProvider FileSystem | 
    Where-Object {$_.Used -gt 0} | 
    ForEach-Object {
        $totalSize = $_.Used + $_.Free
        if ($totalSize -gt 0) {
            $usedPercent = [math]::Round(($_.Used / $totalSize) * 100, 1)
            $freeGB = [math]::Round($_.Free / 1GB, 2)
            
            if ($usedPercent -ge $criticalThreshold) {
                $alerts += [PSCustomObject]@{
                    Server    = $serverName
                    Drive     = $_.Name
                    UsedPct   = $usedPercent
                    FreeGB    = $freeGB
                    Severity  = "KRITIK"
                }
                Write-Host "KRITIK: $serverName - $($_.Name): dizin %$usedPercent dolu!" `
                    -ForegroundColor Red
            }
            elseif ($usedPercent -ge $threshold) {
                $alerts += [PSCustomObject]@{
                    Server    = $serverName
                    Drive     = $_.Name
                    UsedPct   = $usedPercent
                    FreeGB    = $freeGB
                    Severity  = "UYARI"
                }
                Write-Host "UYARI: $serverName - $($_.Name): dizin %$usedPercent dolu!" `
                    -ForegroundColor Yellow
            }
        }
    }

# Uyarı varsa e-posta gönder
if ($alerts.Count -gt 0) {
    $body = $alerts | ConvertTo-Html -Fragment | Out-String
    Send-MailMessage -To "[email protected]" `
        -From "[email protected]" `
        -Subject "[$serverName] Disk Doluluk Uyarisi" `
        -Body $body -BodyAsHtml `
        -SmtpServer "smtp.sirket.com"
    Write-Host "Uyari maili gonderildi." -ForegroundColor Cyan
}

Bu scripti Task Scheduler ile her gece çalıştırırsanız, sabah işe geldiğinizde sorunlu diskler mail kutunuzda sizi bekliyor olur.

WMI ile Daha Derin Disk Analizi

Get-Disk ve Get-PSDrive cmdlet’leri çoğu iş için yeterli, ancak daha detaylı bilgiye ihtiyaç duyduğunuzda WMI sorgularına başvurmanız gerekiyor. Özellikle uzak sunuculardan bilgi toplarken WMI çok kullanışlı.

# Yerel ve uzak sunucularda disk bilgisi topla
$servers = @("Server01", "Server02", "Server03")

$results = foreach ($server in $servers) {
    try {
        $disks = Get-WmiObject -Class Win32_LogicalDisk `
            -ComputerName $server `
            -Filter "DriveType=3" `
            -ErrorAction Stop
        
        foreach ($disk in $disks) {
            [PSCustomObject]@{
                Sunucu      = $server
                Surucu      = $disk.DeviceID
                "Toplam GB" = [math]::Round($disk.Size / 1GB, 2)
                "Bos GB"    = [math]::Round($disk.FreeSpace / 1GB, 2)
                "Dolu %"    = [math]::Round((($disk.Size - $disk.FreeSpace) / $disk.Size) * 100, 1)
                Durum       = if (($disk.FreeSpace / $disk.Size * 100) -lt 15) { "KRITIK" } 
                              elseif (($disk.FreeSpace / $disk.Size * 100) -lt 25) { "UYARI" }
                              else { "NORMAL" }
            }
        }
    }
    catch {
        Write-Warning "$server sunucusuna erisilemedi: $_"
    }
}

# Sonuçları ekrana yazdır
$results | Sort-Object Sunucu, Surucu

# CSV olarak kaydet
$results | Export-Csv -Path "C:ReportsDiskReport_$(Get-Date -Format 'yyyyMMdd').csv" `
    -NoTypeInformation -Encoding UTF8

Volume Shadow Copy (VSS) Yönetimi

Yedekleme altyapısının önemli bir parçası olan VSS’i PowerShell ile yönetmek oldukça pratik. Özellikle VSS snapshot’larının ne kadar yer kapladığını ve ne zaman oluşturulduğunu takip etmek önemli.

# Mevcut shadow copy'leri listele
Get-WmiObject Win32_ShadowCopy | 
    Select-Object ID, 
        VolumeName,
        @{Name="OlusturmaTarihi";Expression={
            [Management.ManagementDateTimeConverter]::ToDateTime($_.InstallDate)
        }},
        @{Name="Boyut(GB)";Expression={[math]::Round($_.Count/1GB,2)}}

# Belirli bir sürücü için shadow copy oluştur
$volume = (Get-Volume -DriveLetter C).Path
$shadowClass = [WMICLASS]"rootcimv2:win32_shadowcopy"
$result = $shadowClass.Create($volume, "ClientAccessible")

if ($result.ReturnValue -eq 0) {
    Write-Host "Shadow copy basariyla olusturuldu. ID: $($result.ShadowID)" -ForegroundColor Green
} else {
    Write-Host "Shadow copy olusturulamadi. Hata kodu: $($result.ReturnValue)" -ForegroundColor Red
}

Storage Pool ve Depolama Havuzu Yönetimi

Windows Server 2012 ve sonrasında gelen Storage Spaces özelliği, birden fazla fiziksel diski tek bir mantıksal havuzda birleştirmenizi sağlıyor. PowerShell bu özelliği yönetmek için ideal araç.

# Mevcut storage pool'ları listele
Get-StoragePool | Select-Object FriendlyName, OperationalStatus, 
    @{Name="Toplam(GB)";Expression={[math]::Round($_.Size/1GB,2)}},
    @{Name="Ayrilan(GB)";Expression={[math]::Round($_.AllocatedSize/1GB,2)}}

# Storage pool için uygun fiziksel diskleri bul
Get-PhysicalDisk -CanPool $true | 
    Select-Object FriendlyName, Size, MediaType, OperationalStatus

# Yeni storage pool oluştur (örnek)
$physicalDisks = Get-PhysicalDisk -CanPool $true | Select-Object -First 3
New-StoragePool -FriendlyName "DataPool01" `
    -StorageSubSystemFriendlyName (Get-StorageSubSystem).FriendlyName `
    -PhysicalDisks $physicalDisks

# Pool üzerinde RAID-like yapılandırma (Mirror)
New-VirtualDisk -StoragePoolFriendlyName "DataPool01" `
    -FriendlyName "DataVDisk01" `
    -ResiliencySettingName Mirror `
    -Size 500GB `
    -ProvisioningType Thin

# Virtual disk'i kullanılabilir hale getir
Get-VirtualDisk -FriendlyName "DataVDisk01" | 
    Get-Disk | 
    Initialize-Disk -PartitionStyle GPT -PassThru |
    New-Partition -UseMaximumSize -AssignDriveLetter |
    Format-Volume -FileSystem NTFS -NewFileSystemLabel "DataVol01" -Confirm:$false

Disk Performans Metrikleri

Disk doluluk takibinin yanı sıra performans izleme de kritik öneme sahip. Özellikle SQL Server veya yoğun I/O yapan uygulamaların çalıştığı sunucularda disk latency ve throughput değerlerini takip etmek gerekiyor.

# Disk performans verilerini topla
$diskCounters = Get-Counter -Counter @(
    "PhysicalDisk(*)Avg. Disk sec/Read",
    "PhysicalDisk(*)Avg. Disk sec/Write",
    "PhysicalDisk(*)Disk Reads/sec",
    "PhysicalDisk(*)Disk Writes/sec",
    "PhysicalDisk(*)% Disk Time"
) -SampleInterval 2 -MaxSamples 5

$diskCounters.CounterSamples | 
    Where-Object {$_.InstanceName -ne "_total"} |
    Select-Object InstanceName, 
        @{Name="Counter";Expression={($_.Path -split "\")[-1]}},
        @{Name="Value";Expression={[math]::Round($_.CookedValue, 4)}} |
    Sort-Object InstanceName, Counter

Bir üretim ortamında gördüğüm klasik bir senaryoyu paylaşayım. SQL Server’ın yavaş çalıştığından şikayet geliyordu. Aşağıdaki script ile 5 dakika boyunca disk metriklerini kaydettik ve sorunun log diskindeki yüksek write latency’den kaynaklandığını bulduk.

# 5 dakika boyunca disk latency takibi ve rapor
$samples = @()
$monitorDuration = 300  # saniye
$interval = 10  # saniye
$iterations = $monitorDuration / $interval

Write-Host "Disk performans izleme basliyor ($monitorDuration saniye)..." -ForegroundColor Cyan

for ($i = 1; $i -le $iterations; $i++) {
    $timestamp = Get-Date
    $counters = Get-Counter -Counter @(
        "PhysicalDisk(*)Avg. Disk sec/Read",
        "PhysicalDisk(*)Avg. Disk sec/Write"
    ) -ErrorAction SilentlyContinue
    
    $counters.CounterSamples | 
        Where-Object {$_.InstanceName -ne "_total"} |
        ForEach-Object {
            $samples += [PSCustomObject]@{
                Zaman       = $timestamp
                Disk        = $_.InstanceName
                Metrik      = ($_.Path -split "\")[-1]
                Deger_ms    = [math]::Round($_.CookedValue * 1000, 2)
            }
        }
    
    Write-Progress -Activity "Performans verisi toplaniyor" `
        -PercentComplete (($i / $iterations) * 100) `
        -Status "$i / $iterations iterasyon tamamlandi"
    
    if ($i -lt $iterations) { Start-Sleep -Seconds $interval }
}

# Yüksek latency olan disk/periyotları bul
Write-Host "`nYuksek Latency Olaylari (>20ms):" -ForegroundColor Yellow
$samples | Where-Object {$_.Deger_ms -gt 20} | 
    Sort-Object Deger_ms -Descending |
    Select-Object -First 20

# Özet rapor
Write-Host "`nOrtalama Latency Ozeti:" -ForegroundColor Cyan
$samples | Group-Object Disk, Metrik | ForEach-Object {
    [PSCustomObject]@{
        Disk    = ($_.Name -split ", ")[0]
        Metrik  = ($_.Name -split ", ")[1]
        "Ort(ms)" = [math]::Round(($_.Group.Deger_ms | Measure-Object -Average).Average, 2)
        "Maks(ms)" = [math]::Round(($_.Group.Deger_ms | Measure-Object -Maximum).Maximum, 2)
    }
} | Sort-Object "Maks(ms)" -Descending

Büyük Dosyaları Bulma ve Temizlik

Disk doluluk sorunlarının büyük kısmı gereksiz büyük dosyalardan kaynaklanır. PowerShell ile bunları hızlıca tespit edebilirsiniz.

# Belirli bir dizindeki en büyük dosyaları bul
function Get-LargeFiles {
    param(
        [string]$Path = "C:",
        [int]$TopCount = 20,
        [int]$MinSizeMB = 100
    )
    
    Write-Host "Taranıyor: $Path (Bu işlem biraz sürebilir...)" -ForegroundColor Cyan
    
    Get-ChildItem -Path $Path -Recurse -File -ErrorAction SilentlyContinue |
        Where-Object {$_.Length -gt ($MinSizeMB * 1MB)} |
        Sort-Object Length -Descending |
        Select-Object -First $TopCount |
        Select-Object FullName,
            @{Name="Boyut(MB)";Expression={[math]::Round($_.Length/1MB,2)}},
            LastWriteTime,
            @{Name="Uzanti";Expression={$_.Extension}}
}

# Kullanım örneği
Get-LargeFiles -Path "D:" -TopCount 30 -MinSizeMB 500

# Windows temp dosyalarını temizle
function Clear-TempFiles {
    $tempPaths = @(
        $env:TEMP,
        "C:WindowsTemp",
        "C:WindowsSoftwareDistributionDownload"
    )
    
    foreach ($path in $tempPaths) {
        if (Test-Path $path) {
            $before = (Get-ChildItem $path -Recurse -ErrorAction SilentlyContinue | 
                Measure-Object -Property Length -Sum).Sum
            
            Get-ChildItem $path -Recurse -ErrorAction SilentlyContinue |
                Remove-Item -Force -Recurse -ErrorAction SilentlyContinue
            
            $after = (Get-ChildItem $path -Recurse -ErrorAction SilentlyContinue | 
                Measure-Object -Property Length -Sum).Sum
            
            $freed = [math]::Round(($before - $after) / 1MB, 2)
            Write-Host "$path temizlendi. Kazanilan alan: $freed MB" -ForegroundColor Green
        }
    }
}

Disk Sağlığı ve SMART Verisi

Fiziksel disk sağlığını izlemek için SMART verilerine bakmak gerekiyor. PowerShell ile bu verilere de erişebilirsiniz.

# Disk sağlık durumunu kontrol et
Get-PhysicalDisk | Select-Object FriendlyName, 
    MediaType, 
    OperationalStatus, 
    HealthStatus,
    @{Name="Boyut(GB)";Expression={[math]::Round($_.Size/1GB,2)}}

# Sorunlu diskleri bul
$unhealthyDisks = Get-PhysicalDisk | 
    Where-Object {$_.HealthStatus -ne "Healthy" -or $_.OperationalStatus -ne "OK"}

if ($unhealthyDisks) {
    Write-Host "UYARI: Sagliksiz disk tespit edildi!" -ForegroundColor Red
    $unhealthyDisks | Select-Object FriendlyName, HealthStatus, OperationalStatus
} else {
    Write-Host "Tüm diskler saglikli." -ForegroundColor Green
}

# Storage reliability counter (NVMe ve bazı SSD'ler için)
Get-StorageReliabilityCounter -PhysicalDisk (Get-PhysicalDisk) |
    Select-Object DeviceId, 
        ReadErrorsTotal, 
        WriteErrorsTotal, 
        Temperature,
        Wear |
    Sort-Object Wear -Descending

Düzenli Bakım için Scheduled Script

Tüm bu işlemleri bir araya getiren ve düzenli çalışacak şekilde ayarlayabileceğiniz kapsamlı bir script:

# Haftalık disk bakım ve raporlama scripti
# Task Scheduler ile her Pazartesi 06:00'da çalıştırın

$reportDate = Get-Date -Format "yyyy-MM-dd"
$reportPath = "C:ReportsDiskReport_$reportDate.html"
$serverName = $env:COMPUTERNAME

# HTML rapor başlığı
$htmlHeader = @"
<html><head><style>
body { font-family: Arial; margin: 20px; }
h2 { color: #336699; }
.kritik { background-color: #ff4444; color: white; padding: 3px; }
.uyari { background-color: #ffbb33; padding: 3px; }
.normal { background-color: #00C851; color: white; padding: 3px; }
</style></head><body>
<h2>$serverName - Disk Durum Raporu - $reportDate</h2>
"@

# Disk doluluk bilgisi
$diskInfo = Get-PSDrive -PSProvider FileSystem | 
    Where-Object {$_.Used -gt 0} |
    Select-Object Name,
        @{Name="Toplam(GB)";Expression={[math]::Round(($_.Used+$_.Free)/1GB,2)}},
        @{Name="Kullanilan(GB)";Expression={[math]::Round($_.Used/1GB,2)}},
        @{Name="Bos(GB)";Expression={[math]::Round($_.Free/1GB,2)}},
        @{Name="Dolu%";Expression={[math]::Round(($_.Used/($_.Used+$_.Free))*100,1)}}

$diskHtml = $diskInfo | ConvertTo-Html -Fragment -PreContent "<h3>Disk Doluluk Durumu</h3>"

# Disk sağlığı
$healthHtml = Get-PhysicalDisk | 
    Select-Object FriendlyName, HealthStatus, OperationalStatus |
    ConvertTo-Html -Fragment -PreContent "<h3>Fiziksel Disk Sagligi</h3>"

# Raporu kaydet
$htmlContent = $htmlHeader + $diskHtml + $healthHtml + "</body></html>"
$htmlContent | Out-File -FilePath $reportPath -Encoding UTF8

Write-Host "Rapor olusturuldu: $reportPath" -ForegroundColor Green

# E-posta ile gönder
$criticalDrives = $diskInfo | Where-Object {$_."Dolu%" -ge 90}
$subject = if ($criticalDrives) { 
    "[KRITIK] $serverName Disk Raporu - $reportDate" 
} else { 
    "$serverName Disk Raporu - $reportDate" 
}

Send-MailMessage -To "[email protected]" `
    -From "[email protected]" `
    -Subject $subject `
    -Body (Get-Content $reportPath -Raw) `
    -BodyAsHtml `
    -SmtpServer "smtp.sirket.com" `
    -Attachments $reportPath

Sonuç

PowerShell ile disk yönetimi, başlangıçta karmaşık görünse de öğrendikten sonra sysadmin hayatınızı ciddi ölçüde kolaylaştırıyor. Bu yazıda ele aldığımız konuları özetlemek gerekirse:

  • Disk ve partition yönetimi için Get-Disk, New-Partition, Format-Volume cmdlet’lerini kullanın
  • Disk doluluk takibini otomatize edin, reaktif değil proaktif olun
  • Uzak sunucularda toplu bilgi toplama için WMI sorgularından yararlanın
  • Storage Spaces özelliğini PowerShell üzerinden yönetmek ciddi esneklik sağlıyor
  • Disk performans metriklerini özellikle yoğun I/O uygulamaları için düzenli izleyin
  • Haftalık otomatik raporlar oluşturun ve mail ile gönderin

Buradaki scriptleri olduğu gibi kopyalayıp yapıştırmak yerine kendi ortamınıza uyarlayın. Mail sunucusu adresleri, eşik değerleri ve rapor yolları gibi parametreleri mutlaka değiştirin. Scriptleri production’a almadan önce test ortamında çalıştırmanızı da öneririm. Disk işlemleri geri alınamaz olabilir, bu yüzden özellikle partition ve format işlemlerinde dikkatli olun.

Yorum yapın