PowerShell ile JSON ve XML Veri İşleme

Veri işleme konusuna gelince, sysadmin’lerin en çok zaman harcadığı alanlardan biri hiç şüphesiz JSON ve XML formatlarıdır. API entegrasyonları, konfigürasyon dosyaları, log çıktıları… Her yerde bu iki format karşımıza çıkıyor. PowerShell bu konuda gerçekten güçlü araçlar sunuyor ve bir kez öğrendiğinizde hayatınız ciddi ölçüde kolaylaşıyor. Gelin bu iki formatı PowerShell ile nasıl verimli şekilde işleyebileceğimize detaylıca bakalım.

JSON ile Çalışmak

JSON (JavaScript Object Notation), özellikle REST API’larla çalışırken ve modern konfigürasyon dosyalarında sıklıkla karşılaşılan bir format. PowerShell 3.0’dan itibaren gelen ConvertTo-Json ve ConvertFrom-Json cmdlet’leri bu işi oldukça kolaylaştırıyor.

ConvertFrom-Json ile JSON Okuma

Elimizde bir JSON verisi olduğunda bunu PowerShell objesine çevirmek için ConvertFrom-Json kullanıyoruz. Basit bir örnekle başlayalım:

# Basit JSON string'ini PowerShell objesine çevirme
$jsonString = '{"hostname": "WEB-SRV-01", "ip": "192.168.1.10", "port": 8080, "active": true}'
$serverInfo = $jsonString | ConvertFrom-Json

# Özelliklere erişim
Write-Host "Sunucu: $($serverInfo.hostname)"
Write-Host "IP Adresi: $($serverInfo.ip)"
Write-Host "Port: $($serverInfo.port)"
Write-Host "Aktif mi: $($serverInfo.active)"

Dikkat ettiyseniz JSON’daki true değeri PowerShell’de otomatik olarak $true boolean değerine dönüşüyor. Bu tür tip dönüşümlerini PowerShell bizim için otomatik yapıyor, bu büyük bir kolaylık.

Gerçek Dünya Senaryosu: Sunucu Envanter Dosyası Okuma

Diyelim ki elinizde sunucu envanterinizi tutan bir JSON dosyası var ve bu dosyadan belirli kriterlere göre sunucuları filtrelemek istiyorsunuz:

# sunucu_envanter.json dosyasını oku ve işle
$envanter = Get-Content -Path "C:Scriptssunucu_envanter.json" -Raw | ConvertFrom-Json

# Sadece aktif Windows sunucularını getir
$aktifSunucular = $envanter.sunucular | Where-Object { 
    $_.aktif -eq $true -and $_.os -like "*Windows*" 
}

# Aktif sunucuları listele
foreach ($sunucu in $aktifSunucular) {
    Write-Host "Sunucu: $($sunucu.hostname) | IP: $($sunucu.ip) | OS: $($sunucu.os)"
    
    # Disk kullanımı yüksek olanları işaretle
    if ($sunucu.diskKullanim -gt 85) {
        Write-Warning "UYARI: $($sunucu.hostname) disk kullanimi kritik seviyede! (%$($sunucu.diskKullanim))"
    }
}

ConvertTo-Json ile JSON Oluşturma

Veriyi JSON formatına çevirmek de oldukça basit. ConvertTo-Json cmdlet’inin -Depth parametresi özellikle iç içe objelerde kritik öneme sahip:

# Sistem bilgilerini toplayıp JSON'a çevirme
$sistemBilgisi = [PSCustomObject]@{
    Hostname    = $env:COMPUTERNAME
    Tarih       = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    OS          = (Get-WmiObject Win32_OperatingSystem).Caption
    RAM_GB      = [math]::Round((Get-WmiObject Win32_ComputerSystem).TotalPhysicalMemory / 1GB, 2)
    CPU_Cekirdek = (Get-WmiObject Win32_Processor).NumberOfCores
    DiskBilgisi = Get-WmiObject Win32_LogicalDisk | Where-Object {$_.DriveType -eq 3} | ForEach-Object {
        [PSCustomObject]@{
            Surucu    = $_.DeviceID
            Toplam_GB = [math]::Round($_.Size / 1GB, 2)
            Bos_GB    = [math]::Round($_.FreeSpace / 1GB, 2)
            Doluluk   = [math]::Round((($_.Size - $_.FreeSpace) / $_.Size) * 100, 1)
        }
    }
}

# JSON'a çevir ve dosyaya kaydet
# -Depth parametresi iç içe objelerin kaç seviye derine gidileceğini belirler
$sistemBilgisi | ConvertTo-Json -Depth 4 | Out-File -FilePath "C:Raporlarsistem_bilgisi.json" -Encoding UTF8

Write-Host "Sistem bilgileri JSON formatinda kaydedildi."

-Depth parametresine dikkat edin. Varsayılan değeri 2’dir ve iç içe objeleriniz varsa bu değeri artırmazsanız veriler kesilebilir. Ben genellikle 4 ya da 5 kullanmayı tercih ediyorum.

API’dan JSON Veri Çekme

Gerçek hayatta en sık kullanılan senaryo REST API’lardan veri çekmek. Örneğin bir monitoring API’ından sunucu durumlarını çekelim:

# REST API'dan JSON veri çekme ve işleme
function Get-SunucuDurumu {
    param(
        [string]$ApiUrl = "https://monitoring.sirket.local/api/servers",
        [string]$ApiKey = "your-api-key-here"
    )
    
    try {
        $headers = @{
            "Authorization" = "Bearer $ApiKey"
            "Content-Type"  = "application/json"
        }
        
        $response = Invoke-RestMethod -Uri $ApiUrl -Headers $headers -Method GET
        
        # Kritik durumda olan sunucuları filtrele
        $kritikSunucular = $response.data | Where-Object { $_.status -eq "critical" }
        
        if ($kritikSunucular.Count -gt 0) {
            Write-Warning "Kritik durumda $($kritikSunucular.Count) sunucu tespit edildi!"
            
            foreach ($sunucu in $kritikSunucular) {
                Write-Host "KRITIK: $($sunucu.name) - Sorun: $($sunucu.issue)" -ForegroundColor Red
                
                # Olay kaydı oluştur
                $olay = [PSCustomObject]@{
                    Zaman   = Get-Date -Format "yyyy-MM-ddTHH:mm:ss"
                    Sunucu  = $sunucu.name
                    Durum   = $sunucu.status
                    Detay   = $sunucu.issue
                }
                
                $olay | ConvertTo-Json | Add-Content -Path "C:Logskritik_olaylar.json"
            }
        }
        
        return $response
    }
    catch {
        Write-Error "API baglantisi kurulamadi: $($_.Exception.Message)"
    }
}

XML ile Çalışmak

XML, özellikle eski enterprise uygulamalar, Windows konfigürasyon dosyaları ve SCCM/WSUS gibi Microsoft araçlarında hala çok yaygın. PowerShell’in XML desteği de oldukça kapsamlı.

XML Dosyası Okuma

PowerShell’de XML ile çalışmanın en temiz yolu [xml] type accelerator kullanmak:

# XML dosyasını okuma ve işleme
[xml]$config = Get-Content -Path "C:Configsuygulama_ayarlari.xml" -Encoding UTF8

# XML düğümlerine nokta notasyonuyla erişim
$dbServer    = $config.Configuration.Database.Server
$dbPort      = $config.Configuration.Database.Port
$dbName      = $config.Configuration.Database.Name
$logLevel    = $config.Configuration.Logging.Level

Write-Host "Veritabani Sunucusu: $dbServer"
Write-Host "Port: $dbPort"
Write-Host "Veritabani Adi: $dbName"
Write-Host "Log Seviyesi: $logLevel"

# Birden fazla eleman içeren düğümleri döngüyle işleme
foreach ($kullanici in $config.Configuration.Users.User) {
    Write-Host "Kullanici: $($kullanici.username) | Rol: $($kullanici.role) | Aktif: $($kullanici.active)"
}

XML Oluşturma ve Düzenleme

XML oluşturmak biraz daha fazla kod gerektiriyor ama System.Xml.XmlDocument sınıfını kullanarak oldukça temiz XML dosyaları üretebilirsiniz:

# Sıfırdan XML dosyası oluşturma
function Yeni-KonfigurasyonXML {
    param(
        [string]$CiktiDosyasi = "C:Configsyeni_config.xml"
    )
    
    # XML dökümanı oluştur
    $xmlDoc = New-Object System.Xml.XmlDocument
    
    # XML deklarasyonu ekle
    $xmlDecl = $xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", $null)
    $xmlDoc.AppendChild($xmlDecl) | Out-Null
    
    # Kök element
    $rootNode = $xmlDoc.CreateElement("Configuration")
    $xmlDoc.AppendChild($rootNode) | Out-Null
    
    # Sunucu bilgileri bölümü
    $serverNode = $xmlDoc.CreateElement("ServerSettings")
    $serverNode.SetAttribute("version", "2.0")
    $serverNode.SetAttribute("lastUpdated", (Get-Date -Format "yyyy-MM-dd"))
    
    # Alt elementler ekle
    $hostnameNode = $xmlDoc.CreateElement("Hostname")
    $hostnameNode.InnerText = $env:COMPUTERNAME
    $serverNode.AppendChild($hostnameNode) | Out-Null
    
    $maxConnNode = $xmlDoc.CreateElement("MaxConnections")
    $maxConnNode.InnerText = "500"
    $serverNode.AppendChild($maxConnNode) | Out-Null
    
    $timeoutNode = $xmlDoc.CreateElement("TimeoutSeconds")
    $timeoutNode.InnerText = "30"
    $serverNode.AppendChild($timeoutNode) | Out-Null
    
    $rootNode.AppendChild($serverNode) | Out-Null
    
    # Dosyaya kaydet
    $xmlDoc.Save($CiktiDosyasi)
    Write-Host "XML konfigurasyonu olusturuldu: $CiktiDosyasi" -ForegroundColor Green
}

Yeni-KonfigurasyonXML

Gerçek Dünya Senaryosu: Windows Event Log XML Analizi

Windows Event Log’larının XML formatındaki verisini analiz etmek, özellikle güvenlik denetimleri için çok işe yarıyor:

# Son 24 saatteki başarısız oturum açma girişimlerini XML üzerinden analiz etme
function Analiz-BasarisizGirisler {
    param(
        [int]$SaatGeriye = 24,
        [int]$EsikDeger = 5
    )
    
    $baslangicZamani = (Get-Date).AddHours(-$SaatGeriye)
    
    # Security event log'dan Event ID 4625 (başarısız giriş) olaylarını çek
    $olaylar = Get-WinEvent -FilterHashtable @{
        LogName   = 'Security'
        Id        = 4625
        StartTime = $baslangicZamani
    } -ErrorAction SilentlyContinue
    
    if (-not $olaylar) {
        Write-Host "Belirtilen zaman araliginda basarisiz giris denemesi bulunamadi."
        return
    }
    
    # Her olayın XML verisini parse et
    $girisDenemeler = foreach ($olay in $olaylar) {
        [xml]$xmlVeri = $olay.ToXml()
        
        # EventData içinden ilgili alanları çek
        $eventData = $xmlVeri.Event.EventData.Data
        
        [PSCustomObject]@{
            Zaman        = $olay.TimeCreated
            KullaniciAdi = ($eventData | Where-Object { $_.Name -eq "TargetUserName" }).'#text'
            KaynakIP     = ($eventData | Where-Object { $_.Name -eq "IpAddress" }).'#text'
            Workstation  = ($eventData | Where-Object { $_.Name -eq "WorkstationName" }).'#text'
            HataKodu     = ($eventData | Where-Object { $_.Name -eq "SubStatus" }).'#text'
        }
    }
    
    # IP bazında gruplama ve eşik değeri aşanları bul
    $supheli = $girisDenemeler | Group-Object -Property KaynakIP | 
               Where-Object { $_.Count -ge $EsikDeger } |
               Sort-Object Count -Descending
    
    if ($supheli.Count -gt 0) {
        Write-Warning "GUVENLIK UYARISI: $($supheli.Count) suphelie IP tespit edildi!"
        foreach ($ip in $supheli) {
            Write-Host "IP: $($ip.Name) | Deneme Sayisi: $($ip.Count)" -ForegroundColor Yellow
        }
    }
    
    # Sonuçları JSON formatında kaydet
    $girisDenemeler | ConvertTo-Json -Depth 3 | 
        Out-File "C:Guvenlikbasarisiz_girisler_$(Get-Date -Format 'yyyyMMdd').json" -Encoding UTF8
    
    return $girisDenemeler
}

Analiz-BasarisizGirisler -SaatGeriye 48 -EsikDeger 10

JSON ve XML Arasında Dönüşüm

Zaman zaman bir formattan diğerine dönüştürme ihtiyacı da çıkıyor. Bu oldukça kolay:

# XML'den JSON'a dönüşüm
function Cevir-XMLdenJSON {
    param(
        [string]$XmlDosyasi,
        [string]$JsonCikti
    )
    
    [xml]$xmlVeri = Get-Content -Path $XmlDosyasi -Encoding UTF8
    
    # XML'i önce hashtable'a, sonra JSON'a çevir
    $jsonVeri = $xmlVeri | ConvertTo-Json -Depth 10
    $jsonVeri | Out-File -FilePath $JsonCikti -Encoding UTF8
    
    Write-Host "Donusum tamamlandi: $XmlDosyasi --> $JsonCikti" -ForegroundColor Green
    Write-Host "JSON boyutu: $([math]::Round((Get-Item $JsonCikti).Length / 1KB, 2)) KB"
}

# JSON'dan XML'e dönüşüm
function Cevir-JSONdenXML {
    param(
        [string]$JsonDosyasi,
        [string]$XmlCikti
    )
    
    $jsonVeri = Get-Content -Path $JsonDosyasi -Raw | ConvertFrom-Json
    
    # PowerShell objesini XML'e çevirme
    $xmlDoc = New-Object System.Xml.XmlDocument
    $rootNode = $xmlDoc.CreateElement("Root")
    $xmlDoc.AppendChild($rootNode) | Out-Null
    
    function Ekle-XMLDugumu {
        param($ParentNode, $Veri, $AnahtarAdi)
        
        if ($Veri -is [PSCustomObject] -or $Veri -is [hashtable]) {
            $dugum = $xmlDoc.CreateElement($AnahtarAdi)
            $Veri.PSObject.Properties | ForEach-Object {
                Ekle-XMLDugumu -ParentNode $dugum -Veri $_.Value -AnahtarAdi $_.Name
            }
            $ParentNode.AppendChild($dugum) | Out-Null
        } else {
            $dugum = $xmlDoc.CreateElement($AnahtarAdi)
            $dugum.InnerText = "$Veri"
            $ParentNode.AppendChild($dugum) | Out-Null
        }
    }
    
    $jsonVeri.PSObject.Properties | ForEach-Object {
        Ekle-XMLDugumu -ParentNode $rootNode -Veri $_.Value -AnahtarAdi $_.Name
    }
    
    $xmlDoc.Save($XmlCikti)
    Write-Host "Donusum tamamlandi: $JsonDosyasi --> $XmlCikti" -ForegroundColor Green
}

Performans ve Best Practice Önerileri

Büyük dosyalarla çalışırken dikkat etmeniz gereken bazı noktalar var:

  • Büyük JSON dosyalarında Get-Content -Raw kullanın, satır satır okumak çok daha yavaş çalışır
  • -Depth parametresini ihtiyacınıza göre ayarlayın, gereğinden yüksek değer performansı olumsuz etkiler
  • XML için Select-Xml cmdlet’i XPath sorguları için çok güçlü bir alternatiftir, büyük XML dosyalarında düğüm araması yaparken tercih edin
  • Encoding sorunları için her zaman -Encoding UTF8 parametresini açıkça belirtin, özellikle Türkçe karakter içeren dosyalarda bu kritik
  • Hata yönetimi için try-catch bloklarını ihmal etmeyin, özellikle API çağrılarında ve dosya işlemlerinde
# Select-Xml ile XPath sorgusu - büyük XML dosyalarında çok daha verimli
$xpathSorgu = "//User[@active='true']"
$aktifKullanicilar = Select-Xml -Path "C:Configskullanicilar.xml" -XPath $xpathSorgu

foreach ($sonuc in $aktifKullanicilar) {
    $kullanici = $sonuc.Node
    Write-Host "Kullanici: $($kullanici.username) | Email: $($kullanici.email)"
}

Sonuç

PowerShell ile JSON ve XML işleme konusunu bir kez iyice kavradığınızda, günlük sysadmin görevlerinizin büyük kısmını otomatize edebiliyorsunuz. API entegrasyonları, konfigürasyon yönetimi, log analizi, raporlama… Bunların hepsi bu bilgiler üzerine inşa ediliyor.

Özellikle şu noktalara odaklanmanızı öneririm: ConvertFrom-Json ve ConvertTo-Json ikilisini iyice sindirin çünkü modern ortamlarda JSON her yerde karşınıza çıkacak. XML tarafında ise [xml] type accelerator ile başlayın, büyük dosyalar için Select-Xml ve XPath sorgularına geçin. Dönüşüm senaryolarında -Depth parametresini asla unutmayın.

Yazdığınız scriptleri modüler tutun, her veri işleme işlemi için ayrı fonksiyonlar yazın ve encoding’e dikkat edin. Türkçe karakter sorunları genellikle UTF-8 belirtilmediğinde ortaya çıkıyor ve bunlar en sinir bozucu bug’lar arasında yer alıyor. Bir kez düzgün alışkanlıklar edindikten sonra bu işlerin ne kadar pratik olduğunu göreceksiniz.

Yorum yapın