Tüm yazılar
Altyapı 6 dk okuma

PowerShell Intelligence Reporter: Sistem Kaynak Analizi

PowerShell ile CPU, RAM, GPU ve disk durumunu tek komutta raporlayın: CIM envanteri, Get-Counter örneklemesi, JSON çıktı ve Python ile eşik analizi.

#powershell #windows #monitoring #scripting #performance

Bir makinenin sağlığını merak ettiğimde Görev Yöneticisi'ni açıp dört ayrı sekme arasında gezinmekten uzun süre önce vazgeçtim. PowerShell sistem izleme konusuna eğilmemin sebebi tam olarak buydu: CPU, RAM, GPU ve disk durumunu tek komutla, tek ekranda ve tekrar üretilebilir biçimde görmek istiyordum. Windows bu bilgilerin tamamını zaten içinde taşıyor; eksik olan, onları derleyip düzenli bir rapor hâlinde önüme koyan küçük bir katmandı.

Bu yazıda kendi makinelerimde ve yönettiğim Windows sunucularında kullandığım yaklaşımı adım adım paylaşıyorum: önce CIM üzerinden donanım envanteri, sonra Get-Counter ile anlık performans örneklemesi, ardından raporu JSON'a döküp zamanlanmış göreve bağlamak ve son olarak biriken raporları Python ile eşik ve eğilim analizinden geçirmek.

Amaç gösterişli bir izleme platformu kurmak değil. Zabbix veya Prometheus gibi araçların yeri ayrı; burada anlattığım şey, tek dosyalık bir betikle "bu makinenin kapasitesi şu an ne durumda, bakım gerekiyor mu" sorusuna saniyeler içinde cevap almak.

Neden tek komutluk bir kaynak raporu?

Görev Yöneticisi ve Kaynak İzleyicisi işlerini görüyor ama üç temel zaafları var: anlık görüntü verirler, geçmiş tutmazlar ve çıktıları karşılaştırılabilir değildir. Bir makineye "geçen aya göre yavaşladı mı" diye sorduğunuzda ekran görüntüsü koleksiyonuyla cevap arayamazsınız. Dağınık bakışın bana yaşattığı somut sorunlar şunlardı:

  • CPU, RAM, disk ve GPU bilgisi dört farklı pencereye dağılmış durumda; bütünsel bir fotoğraf yok.
  • Gözle bakılan değer kayıt altına alınmıyor; iki hafta sonra "o gün neydi" sorusunun cevabı yok.
  • Uzak bir makinede aynı incelemeyi yapmak için RDP açıp aynı tıklamaları tekrarlamak gerekiyor.
  • Çıktı makine-okunur olmadığı için hiçbir otomasyona bağlanamıyor.

Tek komutluk bir rapor bu dört sorunu birden çözüyor: aynı betik her makinede aynı biçimde çalışıyor, çıktısı dosyaya düşüyor, dosyalar birikince de eğilim analizi kendiliğinden mümkün hâle geliyor. Betiği sürüm kontrolüne koyduğunuzda raporun kendisi de belgelenmiş oluyor.

Danışmanlık işinde bunun bir yan faydası daha var: yeni bir ortamla ilk kez karşılaştığımda "bu makinede ne var, ne durumda" sorusunun cevabını tahminle değil, aynı betiğin çıktısıyla veriyorum. Konuşma "bana öyle geliyor ki disk doluyor" yerine "işte rapor, D sürücüsünde şu kadar yer kalmış" düzeyinde başlıyor; bu fark, bakım kararlarının kalitesini doğrudan etkiliyor.

Donanım envanteri: CPU, RAM, GPU ve diski CIM'den toplamak

İlk adım, makinenin "ne olduğunu" tespit etmek. Bunun için WMI'ın modern arayüzü olan CIM'i kullanıyorum; Get-CimInstance hem PowerShell 5.1'de hem PowerShell 7'de aynı şekilde çalışıyor ve eski Get-WmiObject'e göre hem hızlı hem de uzak makinelere daha temiz bağlanıyor:

$cpu  = Get-CimInstance Win32_Processor
$os   = Get-CimInstance Win32_OperatingSystem
$gpu  = Get-CimInstance Win32_VideoController
$disk = Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3"

[PSCustomObject]@{
    Islemci          = $cpu.Name
    Cekirdek         = $cpu.NumberOfCores
    MantiksalIslemci = $cpu.NumberOfLogicalProcessors
    ToplamRamGB      = [math]::Round($os.TotalVisibleMemorySize / 1MB, 1)
    BosRamGB         = [math]::Round($os.FreePhysicalMemory / 1MB, 1)
    Gpu              = ($gpu | ForEach-Object Name) -join ', '
    Diskler          = ($disk | ForEach-Object {
        '{0} {1}/{2} GB bos' -f $_.DeviceID,
            [math]::Round($_.FreeSpace / 1GB, 0),
            [math]::Round($_.Size / 1GB, 0)
    }) -join ' | '
}

Birkaç ayrıntıya dikkat: Win32_OperatingSystem bellek değerlerini kilobayt cinsinden döndürür, bu yüzden 1MB'a bölmek gigabayt verir; ilk bakışta ters gelen bu dönüşüm klasik bir tuzaktır. DriveType=3 filtresi yalnızca sabit diskleri getirir; USB bellekler ve ağ sürücüleri rapora karışmaz. SSD/HDD ayrımı ve disk sağlığı gerekiyorsa Get-PhysicalDisk cmdlet'i MediaType ve HealthStatus alanlarıyla bu tabloyu tamamlar.

Anlık performans: Get-Counter ile örnekleme

Envanter makinenin kimliğini söyler; yük altında nasıl davrandığını ise performans sayaçları anlatır. Get-Counter ile birkaç saniyelik bir örnekleme alıp ortalama ve tepe değerleri çıkarıyorum, ardından her şeyi tarih damgalı bir JSON dosyasına yazıyorum:

$sayaclar = @(
    '\Processor(_Total)\% Processor Time',
    '\Memory\Available MBytes',
    '\PhysicalDisk(_Total)\Avg. Disk Queue Length'
)
$ornek = Get-Counter -Counter $sayaclar -SampleInterval 2 -MaxSamples 5

$ozet = $ornek.CounterSamples | Group-Object Path | ForEach-Object {
    [PSCustomObject]@{
        Sayac    = $_.Name
        Ortalama = [math]::Round(($_.Group.CookedValue | Measure-Object -Average).Average, 2)
        Tepe     = [math]::Round(($_.Group.CookedValue | Measure-Object -Maximum).Maximum, 2)
    }
}

$rapor = [PSCustomObject]@{
    Makine   = $env:COMPUTERNAME
    Zaman    = (Get-Date).ToString('s')
    Sayaclar = $ozet
}
$rapor | ConvertTo-Json -Depth 4 |
    Set-Content -Path "$env:USERPROFILE\rapor-$(Get-Date -Format yyyyMMdd-HHmm).json" -Encoding UTF8

Burada iki nokta önemli:

  • Yerelleştirilmiş sayaç adları: Türkçe Windows'ta sayaç yolları çevrilmiş olabilir ("% Processor Time" yerine "% İşlemci Zamanı" gibi). Betik hata verirse önce Get-Counter -ListSet * ile kendi sisteminizdeki gerçek adları doğrulayın; bu, forumlardan kopyalanan betiklerin Türkçe sistemlerde en sık patlama sebebidir.
  • Disk kuyruğu neden orada: Ortalama disk kuyruk uzunluğu, disk yüzdesinden çok daha dürüst bir darboğaz göstergesidir. Kendi makinemde gördüğüm mertebeyle konuşursam, boşta 0'a yakın seyreden bu değerin sürekli yüksek kalması "disk yetişemiyor" demektir; kesin bir evrensel eşik yoktur, kendi taban çizginizi ölçmeniz gerekir.

Beş örneklik iki saniyelik pencere kısa görünebilir; amaç zaten uzun süreli izleme değil, rapor anındaki fotoğrafı biraz titreşimden arındırmak. Tek bir anlık okuma yanıltıcı olabilir: antivirüs taramasının tam ortasına denk gelirseniz CPU yüzde yüz görünür, iki saniye sonra normale döner. Ortalama ve tepe değeri birlikte raporlamak bu yüzden önemli; ortalama genel resmi, tepe ise kısa süreli sıçramaları anlatır. Daha uzun pencere isterseniz MaxSamples değerini büyütmeniz yeterli.

Raporu otomasyona bağlamak: Zamanlanmış Görev

JSON çıktının asıl gücü, raporun artık bir insanın bakmasını beklememesi. Betiği Zamanlanmış Görev'e bağladığınızda her sabah bir dosya birikir ve elinizde makinenin günlüğü oluşur:

$eylem = New-ScheduledTaskAction -Execute 'powershell.exe' `
    -Argument '-NoProfile -ExecutionPolicy Bypass -File C:\Araclar\kaynak-raporu.ps1'
$tetik = New-ScheduledTaskTrigger -Daily -At 08:45
Register-ScheduledTask -TaskName 'KaynakRaporu' -Action $eylem -Trigger $tetik

İki pratik uyarı: görev, oturum açık olmasa da çalışsın istiyorsanız kaydederken uygun bir hizmet hesabı seçmeniz gerekir; ayrıca betiğin yazdığı klasörün o hesap tarafından yazılabilir olduğundan emin olun. Sessizce başarısız olan zamanlanmış görev, hiç kurulmamış görevden daha tehlikelidir — rapor geldiğini sanırsınız ama gelmiyordur. Ben bu yüzden betiğin sonuna "son çalışma zamanı" bilgisini ayrı bir dosyaya yazan bir satır ekler, arada bir o dosyanın tarihine bakarım.

Bu "küçük betik + zamanlayıcı + dosyaya düşen makine-okunur çıktı" kalıbını yalnızca Windows'ta değil, Raspberry Pi üzerinde veri senkronizasyonu ve güç yönetimi kurarken de birebir aynı mantıkla kullandım; platform değişse de desen değişmiyor. Aynı makinede birden fazla proje ve servis yan yana koşuyorsa, raporun hangi yükün kime ait olduğunu söyleyebilmesi için ortamları düzgün ayırmak gerekir — Docker Compose tarafında proje adlandırma ve izolasyon üzerine yazdıklarım tam da bu karışıklığı önlemek içindi.

Eşik, eğilim ve bakım planlaması: Python ile analiz

Biriken JSON dosyalarını okumak için harici bağımlılığı olmayan kısa bir Python betiği yetiyor. Eşikleri aşan günleri listeliyor ve CPU ortalamasında belirgin bir artış eğilimi varsa bakım uyarısı basıyor:

import json
from pathlib import Path

# Esikler ornektir; kendi taban cizginize gore ayarlayin.
ESIK = {"islemci_yuzde": 80.0, "bos_ram_mb": 2048.0, "disk_kuyrugu": 2.0}

def deger(rapor, parca):
    for s in rapor["Sayaclar"]:
        if parca in s["Sayac"].lower():
            return s["Ortalama"]
    return None

seri = []
for dosya in sorted(Path.home().glob("rapor-*.json")):
    # utf-8-sig: PowerShell 5.1'in UTF8 ciktisindaki BOM'u da sorunsuz okur
    r = json.loads(dosya.read_text(encoding="utf-8-sig"))
    cpu = deger(r, "processor time")
    ram = deger(r, "available mbytes")
    kuyruk = deger(r, "disk queue")
    seri.append(cpu)
    if cpu is not None and cpu > ESIK["islemci_yuzde"]:
        print(f"{r['Zaman']}: CPU ortalamasi %{cpu} - esik asildi")
    if ram is not None and ram < ESIK["bos_ram_mb"]:
        print(f"{r['Zaman']}: bos RAM {ram} MB - esigin altinda")
    if kuyruk is not None and kuyruk > ESIK["disk_kuyrugu"]:
        print(f"{r['Zaman']}: disk kuyrugu {kuyruk} - darbogaz isareti")

gecerli = [c for c in seri if c is not None]
if len(gecerli) >= 2 and gecerli[-1] - gecerli[0] > 10:
    print(f"Egilim: CPU ortalamasi {gecerli[0]} -> {gecerli[-1]}, kalici artis var; bakim planlayin.")

Buradaki eşikler kesin doğrular değil, başlangıç noktaları. Doğru yöntem, makineyi bir iki hafta izleyip normal seyrini öğrenmek ve eşikleri o taban çizgisine göre koymak. Pandas ya da grafik kütüphanesi bilerek eklemedim; standart kütüphane yeterli olduğu sürece bağımlılık eklemek, betiğin beş yıl sonra da çalışma ihtimalini azaltmaktan başka işe yaramıyor.

Bu analizin asıl karşılığı bakım planlamasında ortaya çıkıyor. Boş RAM'in haftalar içinde istikrarlı biçimde eridiğini görüyorsanız bellek yükseltmesini bütçe döngüsüne şimdiden yazarsınız; disk kuyruğu belirli saatlerde düzenli yükseliyorsa yedekleme penceresini kaydırmayı düşünürsünüz. "Disk doluyor", "RAM sürekli sınırda" gibi sinyalleri kriz gününde değil haftalar öncesinden yakalamak, bakımı acil müdahale olmaktan çıkarıp takvim işine dönüştürüyor.

Bir de es geçilmemesi gereken bir gizlilik boyutu var. Kendi makinenizi izlemek serbesttir; ama başkasının kullandığı bir bilgisayarı izliyorsanız kurallar değişir:

  • İzlenen kişiyi açıkça bilgilendirin ve rızasını alın; kurumsal ortamda bunu yazılı politikaya bağlayın.
  • Veri minimizasyonu uygulayın: sayaç değerleri yeter, açık pencere başlıkları veya kullanıcı davranışı gibi veriler bu işin kapsamı dışıdır.
  • Raporları sınırsız saklamayın; belirli bir süre sonra silinmelerini de otomasyona bağlayın.
  • Türkiye'de çalışıyorsanız kişisel veriye dokunan her izlemenin KVKK kapsamına girebileceğini unutmayın.

Özetle: dört pencereye dağılmış bir bakışın yerini, tek komutla üretilen, dosyaya düşen ve kendi kendini analiz eden bir rapor aldı. Kurulumu yarım saat, getirisi ise her bakım kararında hissediliyor. Bu tür küçük ama dayanıklı otomasyonlar, veri ve otomasyon danışmanlığı işimin de temel felsefesi. Kendi ortamınıza uyarlamak isterseniz ya da elinizdeki makineler için bir izleme düzeni kurgulamak istiyorsanız iletişim sayfasından bana yazabilirsiniz.