Windows ortamında sistem yönetimi yapıyorsanız, er ya da geç WMI ve CIM sorgularıyla yüzleşmek zorunda kalacaksınız. Özellikle büyük ölçekli Windows Server ortamlarında donanım envanteri çıkarmak, servis durumlarını izlemek ya da uzak makinelere bağlanarak anlık bilgi toplamak için bu iki teknoloji adeta olmazsa olmaz. PowerShell bu işleri inanılmaz derecede kolaylaştırıyor, ancak WMI mi kullanmalı CIM mi kullanmalı sorusu hâlâ kafaları karıştırmaya devam ediyor. Bu yazıda her ikisini de detaylıca ele alacağız.
WMI ve CIM Nedir?
WMI (Windows Management Instrumentation), Microsoft’un Windows sistemlerini yönetmek için geliştirdiği bir altyapıdır. 1990’ların sonlarına dayanan bu teknoloji, işletim sistemi bileşenlerine, donanıma, ağ ayarlarına ve uygulama verilerine standart bir arayüz üzerinden erişmenizi sağlar. DCOM (Distributed Component Object Model) protokolü üzerinde çalışır ve bu durum özellikle güvenlik duvarı ayarları açısından bazen baş ağrısı yaratabilir.
CIM (Common Information Model) ise daha modern ve platform bağımsız bir standarttır. Microsoft, PowerShell 3.0 ile birlikte CIM cmdlet’lerini tanıttı ve bunlar WMI’ın yerini almaya başladı. CIM, WSMan (WS-Management) protokolünü kullanır ve bu sayede hem daha güvenli hem de daha az sorun çıkaran bir yapı sunar. Windows Remote Management (WinRM) üzerinden çalışır.
Kısaca özetlemek gerekirse:
- Get-WmiObject: Eski, DCOM kullanan, PowerShell 3.0 öncesi yöntem
- Get-CimInstance: Yeni, WSMan kullanan, önerilen modern yöntem
PowerShell 6.0 ve sonrasında Get-WmiObject tamamen kaldırıldı. Bu yüzden yeni scriptlerinizi mutlaka CIM cmdlet’leriyle yazın.
Temel CIM Sorguları
Get-CimInstance ile Başlangıç
En temel kullanım şekliyle bir sisteme ait işlemci bilgisini çekelim:
Get-CimInstance -ClassName Win32_Processor
Bu komut size işlemci adı, çekirdek sayısı, hız ve diğer detayları döndürür. Ama gerçek güç, bu çıktıyı filtrelediğinizde ortaya çıkar. Sadece işlemci adını ve çekirdek sayısını görmek istiyorsanız:
Get-CimInstance -ClassName Win32_Processor | Select-Object Name, NumberOfCores, NumberOfLogicalProcessors, MaxClockSpeed
Sık Kullanılan WMI/CIM Sınıfları
Günlük işlerinizde en çok kullanacağınız sınıflar şunlardır:
- Win32_OperatingSystem: İşletim sistemi bilgileri
- Win32_Processor: İşlemci detayları
- Win32_PhysicalMemory: Fiziksel RAM bilgisi
- Win32_LogicalDisk: Mantıksal disk bilgileri
- Win32_NetworkAdapterConfiguration: Ağ kartı yapılandırması
- Win32_Service: Windows servisleri
- Win32_Process: Çalışan işlemler
- Win32_BIOS: BIOS bilgileri
- Win32_ComputerSystem: Genel sistem bilgileri
Pratik Senaryolar ve Kod Örnekleri
Senaryo 1: Disk Kullanım Raporu
Bir müşteri ortamında 50’den fazla sunucunun disk kullanımını takip etmek zorunda kaldım. Manuel kontrol imkânsız, bu yüzden şu scripti geliştirdim:
$sunucular = @("SUNUCU01", "SUNUCU02", "SUNUCU03")
foreach ($sunucu in $sunucular) {
$diskler = Get-CimInstance -ClassName Win32_LogicalDisk `
-ComputerName $sunucu `
-Filter "DriveType=3"
foreach ($disk in $diskler) {
$toplamGB = [math]::Round($disk.Size / 1GB, 2)
$bosGB = [math]::Round($disk.FreeSpace / 1GB, 2)
$kullanilanYuzde = [math]::Round((($disk.Size - $disk.FreeSpace) / $disk.Size) * 100, 1)
[PSCustomObject]@{
Sunucu = $sunucu
DiskHarfi = $disk.DeviceID
ToplamGB = $toplamGB
BosGB = $bosGB
KullanilanYuzde = "$kullanilanYuzde%"
Durum = if ($kullanilanYuzde -gt 85) { "KRITIK" } elseif ($kullanilanYuzde -gt 70) { "UYARI" } else { "NORMAL" }
}
}
} | Sort-Object KullanilanYuzde -Descending | Format-Table -AutoSize
Bu script kritik diskleri hemen üste sıralıyor ve görsel olarak durumu net şekilde gösteriyor. Eğer e-posta bildirimi de eklemek istiyorsanız Durum -eq "KRITIK" olan satırları filtreleyip Send-MailMessage ile gönderebilirsiniz.
Senaryo 2: Bellek Kullanımı ve Toplam RAM
$bellekBilgisi = Get-CimInstance -ClassName Win32_OperatingSystem
$toplamRAM = [math]::Round($bellekBilgisi.TotalVisibleMemorySize / 1MB, 2)
$bosRAM = [math]::Round($bellekBilgisi.FreePhysicalMemory / 1MB, 2)
$kullanilanRAM = $toplamRAM - $bosRAM
$kullanilanYuzde = [math]::Round(($kullanilanRAM / $toplamRAM) * 100, 1)
Write-Host "Toplam RAM: $toplamRAM GB"
Write-Host "Kullanilan RAM: $kullanilanRAM GB"
Write-Host "Bos RAM: $bosRAM GB"
Write-Host "Kullanim Yuzdesi: %$kullanilanYuzde"
# Fiziksel RAM modüllerini de listeleyelim
Get-CimInstance -ClassName Win32_PhysicalMemory |
Select-Object BankLabel, Manufacturer,
@{N="KapasiteGB"; E={[math]::Round($_.Capacity / 1GB, 0)}},
Speed, MemoryType
Senaryo 3: WQL Sorguları ile Filtreleme
CIM ve WMI, SQL’e benzeyen WQL (WMI Query Language) destekler. Bu sayede çok daha hedefli sorgular yazabilirsiniz:
# Sadece çalışan servisleri listele
$calisanServisler = Get-CimInstance -Query "SELECT * FROM Win32_Service WHERE State = 'Running' AND StartMode = 'Auto'"
# Durmuş ama otomatik başlaması gereken servisleri bul (kritik bir kontrol!)
$sorunluServisler = Get-CimInstance -Query "SELECT * FROM Win32_Service WHERE State = 'Stopped' AND StartMode = 'Auto' AND Name != 'gupdate'"
if ($sorunluServisler) {
Write-Warning "Asagidaki servisler durmus durumda:"
$sorunluServisler | Select-Object Name, DisplayName, State, StartMode | Format-Table -AutoSize
} else {
Write-Host "Tum otomatik servisler calisiyor." -ForegroundColor Green
}
Bu sorgu production ortamında benim için sayısız kez hayat kurtardı. Özellikle Windows Update veya bir restart sonrasında bazı servislerin ayağa kalkmadığını tespit etmek için mükemmel.
Uzak Bilgisayarlara Bağlanmak: CimSession
CIM’in en güçlü özelliklerinden biri CimSession desteğidir. Birden fazla sunucuya aynı anda bağlanıp toplu sorgu yapabilirsiniz:
# Birden fazla sunucuya CimSession aç
$sunucular = @("SUNUCU01", "SUNUCU02", "SUNUCU03", "SUNUCU04")
$oturumlar = New-CimSession -ComputerName $sunucular -Credential (Get-Credential)
# Tüm sunucularda aynı anda işletim sistemi bilgisi al
$osSonuclari = Get-CimInstance -CimSession $oturumlar -ClassName Win32_OperatingSystem |
Select-Object PSComputerName, Caption, Version,
@{N="UptimeGun"; E={[math]::Round((Get-Date - $_.LastBootUpTime).TotalDays, 1)}},
@{N="SonRestart"; E={$_.LastBootUpTime}}
$osSonuclari | Sort-Object UptimeGun -Descending | Format-Table -AutoSize
# Oturumları kapat (önemli!)
Remove-CimSession -CimSession $oturumlar
Önemli not: CimSession’ları kullandıktan sonra mutlaka kapatın. Açık oturumlar sunucu kaynaklarını tüketir ve uzun süreli scriptlerde bağlantı limitine takılabilirsiniz.
WMI Namespace’leri Keşfetmek
WMI sadece Win32 sınıflarından ibaret değil. Farklı namespace’ler altında yüzlerce sınıf mevcut:
# Mevcut namespace'leri listele
Get-CimInstance -Namespace root -ClassName __Namespace |
Select-Object Name | Sort-Object Name
# Belirli bir namespace altındaki sınıfları bul
Get-CimClass -Namespace root/cimv2 |
Where-Object {$_.CimClassName -like "Win32_Net*"} |
Select-Object CimClassName
# Bir sınıfın tüm özelliklerini keşfet
Get-CimClass -ClassName Win32_NetworkAdapterConfiguration |
Select-Object -ExpandProperty CimClassProperties |
Select-Object Name, CimType |
Sort-Object Name
Bu keşif komutları özellikle yeni bir sınıfla çalışmaya başlarken çok işe yarıyor. Hangi özelliklerin mevcut olduğunu bilmeden doğru sorgu yazmak zorlaşıyor.
Donanım Envanteri Script’i
Gerçek bir production senaryosu: Yeni bir müşteri aldınız ve onların Windows Server envanterini çıkarmanız gerekiyor. Şu script birkaç dakikada eksiksiz bir envanter oluşturur:
function Get-SunucuEnvanter {
param(
[Parameter(Mandatory)]
[string[]]$SunucuListesi,
[string]$CiktiDosyasi = "envanter_$(Get-Date -Format 'yyyyMMdd').csv"
)
$sonuclar = @()
foreach ($sunucu in $SunucuListesi) {
Write-Host "Isleniyor: $sunucu" -ForegroundColor Cyan
try {
$oturum = New-CimSession -ComputerName $sunucu -ErrorAction Stop
$os = Get-CimInstance -CimSession $oturum -ClassName Win32_OperatingSystem
$cpu = Get-CimInstance -CimSession $oturum -ClassName Win32_Processor | Select-Object -First 1
$sistem = Get-CimInstance -CimSession $oturum -ClassName Win32_ComputerSystem
$bios = Get-CimInstance -CimSession $oturum -ClassName Win32_BIOS
$toplamDisk = Get-CimInstance -CimSession $oturum -ClassName Win32_LogicalDisk -Filter "DriveType=3" |
Measure-Object Size -Sum | Select-Object -ExpandProperty Sum
$sonuclar += [PSCustomObject]@{
SunucuAdi = $sunucu
OSVersiyon = $os.Caption
OSBuild = $os.BuildNumber
CPUModel = $cpu.Name
CPUCekirdek = $cpu.NumberOfCores
RAMtoplamGB = [math]::Round($sistem.TotalPhysicalMemory / 1GB, 0)
ToplamDiskGB = [math]::Round($toplamDisk / 1GB, 0)
Manufacturer = $sistem.Manufacturer
Model = $sistem.Model
SerialNo = $bios.SerialNumber
SonRestart = $os.LastBootUpTime
UptimeGun = [math]::Round((Get-Date - $os.LastBootUpTime).TotalDays, 0)
}
Remove-CimSession -CimSession $oturum
}
catch {
Write-Warning "$sunucu baglanilamadi: $($_.Exception.Message)"
$sonuclar += [PSCustomObject]@{
SunucuAdi = $sunucu
OSVersiyon = "ERISIM HATASI"
}
}
}
$sonuclar | Export-Csv -Path $CiktiDosyasi -NoTypeInformation -Encoding UTF8
Write-Host "`nEnvanter kaydedildi: $CiktiDosyasi" -ForegroundColor Green
return $sonuclar
}
# Kullanim ornegi
$sunucular = Get-Content "sunucu_listesi.txt"
Get-SunucuEnvanter -SunucuListesi $sunucular
CIM Yöntemi Çağırma (Invoke-CimMethod)
CIM sadece bilgi okumak için değil, işlem yapmak için de kullanılabilir. Servis başlatma, durdurma veya süreç öldürme gibi işlemleri de CIM üzerinden yapabilirsiniz:
# Bir servisi CIM üzerinden yeniden başlat
$servis = Get-CimInstance -ClassName Win32_Service -Filter "Name='Spooler'"
Invoke-CimMethod -InputObject $servis -MethodName StopService
Start-Sleep -Seconds 3
Invoke-CimMethod -InputObject $servis -MethodName StartService
# Uzak sunucuda işlem sonlandır
$uzakIslem = Get-CimInstance -ClassName Win32_Process `
-ComputerName "SUNUCU01" `
-Filter "Name='notepad.exe'"
if ($uzakIslem) {
Invoke-CimMethod -InputObject $uzakIslem -MethodName Terminate
Write-Host "Islem sonlandirildi."
}
WMI Event Subscription ile Monitoring
WMI’ın az bilinen ama çok güçlü bir özelliği de event subscription’dır. Belirli olaylar gerçekleştiğinde otomatik tepki verebilirsiniz:
# Yeni bir süreç başladığında bildirim al
$sorgu = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'"
Register-CimIndicationEvent `
-Query $sorgu `
-SourceIdentifier "YeniSurecIzleyici" `
-Action {
$surecAdi = $Event.SourceEventArgs.NewEvent.TargetInstance.Name
$pid = $Event.SourceEventArgs.NewEvent.TargetInstance.ProcessId
Write-Host "$(Get-Date -Format 'HH:mm:ss') - Yeni surec: $surecAdi (PID: $pid)" -ForegroundColor Yellow
}
Write-Host "Izleme basladi. Durdurmak icin Ctrl+C basin..."
Write-Host "Aboneyi kaldirmak icin: Unregister-Event -SourceIdentifier 'YeniSurecIzleyici'"
# Test et
# Start-Process notepad
# Izlemeyi durdur
# Unregister-Event -SourceIdentifier "YeniSurecIzleyici"
Bu tekniği zararlı yazılım tespiti veya beklenmedik süreç başlatmalarını loglamak için kullanabilirsiniz.
Performans ve Optimizasyon İpuçları
Büyük ortamlarda CIM sorgularını hızlandırmak için birkaç kritik nokta var:
Sadece Gerekli Özellikleri Çekin
# Yavaş - tüm özellikleri çeker
Get-CimInstance -ClassName Win32_Process
# Hızlı - sadece gerekli özellikleri çeker
Get-CimInstance -ClassName Win32_Process -Property Name, ProcessId, WorkingSetSize
-Property parametresi ağ trafiğini ve işlem süresini dramatik şekilde azaltır. 50 sunucuya sorguda bu fark dakikalar mertebesine ulaşabilir.
Filter Parametresini Kullanın
# Kötü pratik - tüm veriyi çekip PowerShell'de filtrele
Get-CimInstance -ClassName Win32_Service | Where-Object {$_.State -eq "Stopped"}
# İyi pratik - WMI tarafında filtrele, daha az veri transferi
Get-CimInstance -ClassName Win32_Service -Filter "State='Stopped'"
Filtrelemeyi her zaman WMI/CIM tarafında yapın. Where-Object kullanmak veriyi önce tam olarak çekip sonra filtrelemek anlamına gelir.
Paralel Sorgu için Workflow veya Jobs
# Birden fazla sunucuya paralel sorgu (PowerShell 7+)
$sunucular = @("SUNUCU01", "SUNUCU02", "SUNUCU03", "SUNUCU04", "SUNUCU05")
$sonuclar = $sunucular | ForEach-Object -Parallel {
$sunucu = $_
try {
$disk = Get-CimInstance -ComputerName $sunucu -ClassName Win32_LogicalDisk -Filter "DeviceID='C:'" -ErrorAction Stop
[PSCustomObject]@{
Sunucu = $sunucu
BosGB = [math]::Round($disk.FreeSpace / 1GB, 1)
ToplamGB = [math]::Round($disk.Size / 1GB, 1)
Durum = "OK"
}
} catch {
[PSCustomObject]@{
Sunucu = $sunucu
Durum = "HATA: $($_.Exception.Message)"
}
}
} -ThrottleLimit 10
$sonuclar | Format-Table -AutoSize
Yaygın Hatalar ve Çözümleri
DCOM/RPC bağlantı hataları: Eski Get-WmiObject kullanıyorsanız ve uzak bağlantıda sorun yaşıyorsanız, büyük ihtimalle güvenlik duvarında 135 numaralı port veya dinamik RPC portları kapalıdır. CIM’e geçerseniz sadece 5985 (HTTP) veya 5986 (HTTPS) portuna ihtiyaç duyarsınız.
WinRM servisi başlatılmamış: CIM uzak bağlantı için WinRM gerektirir. Hızlı çözüm için hedef sunucuda Enable-PSRemoting -Force komutunu çalıştırın.
Yetersiz yetki hataları: CIM sorgularını çalıştırmak için hedef makinede local admin ya da Remote Management Users grubunda üyelik gereklidir. Domain ortamında GPO ile bu izinleri merkezi yönetebilirsiniz.
Timeout sorunları: Yavaş ağ bağlantılarında veya meşgul sunucularda zaman aşımı yaşayabilirsiniz:
$oturumSec = New-CimSessionOption -OperationTimeoutSec 30
$oturum = New-CimSession -ComputerName "UZAK-SUNUCU" -SessionOption $oturumSec
Sonuç
WMI ve CIM, Windows sistem yöneticisinin araç kutusundaki en güçlü aletlerden ikisi. Eski projelerde Get-WmiObject görseniz de yeni yazdığınız her şeyi mutlaka Get-CimInstance ve CimSession ile yazın; hem daha hızlı hem daha güvenli hem de PowerShell 7+ uyumlu olur.
Bu yazıda ele aldığımız konuları özetlemek gerekirse: temel CIM sorgularından başlayıp WQL filtreleme, uzak bağlantı yönetimi, donanım envanteri, event subscription ve performans optimizasyonuna kadar oldukça geniş bir yelpazede ilerledik. Gerçek production ortamlarında en çok işinize yarayacak senaryoları gösterdim, ancak bu buzdağının sadece görünen kısmı.
CIM sınıflarını keşfetmeye devam edin. Get-CimClass -Namespace root/cimv2 | Where-Object {$_.CimClassName -like "Win32_*"} komutuyla 800’den fazla sınıf görürsünüz ve bunların büyük çoğunluğu gerçek dünya problemlerine çözüm üretmek için orada bekliyor. İyi scriptlemeler!