Windows ortamında bir şeylerin ters gittiğini fark edip de “Bu ne zaman başladı, nasıl oldu?” diye saatlerce log dosyalarını karıştırdıysanız, ETW’nin (Event Tracing for Windows) hayatınızı nasıl kolaylaştırabileceğini bu yazıda göreceksiniz. ETW, Windows’un derinliklerine gömülü, son derece düşük maliyetli ve güçlü bir izleme altyapısıdır. PowerShell ile bu altyapıyı kullanmak hem günlük operasyonel işleri hem de ciddi sorun giderme senaryolarını çok daha yönetilebilir hale getirir.
ETW Nedir ve Neden Önemlidir?
ETW, Windows NT 5.1’den bu yana var olan, çekirdek ve kullanıcı modu bileşenlerinin olayları yüksek performanslı şekilde kaydetmesine imkan tanıyan bir mekanizmadır. Basit bir Event Log’dan çok daha fazlasıdır. Kernel seviyesindeki ağ trafiğinden, disk I/O işlemlerine, process oluşturma olaylarından uygulama özel izleme verilerine kadar her şeyi yakalayabilirsiniz.
Üç temel bileşenden oluşur:
- Provider: Olayları üreten bileşen (örneğin bir servis, sürücü veya uygulama)
- Controller: İzleme oturumlarını başlatıp durduran ve provider’ları yapılandıran kısım
- Consumer: Olayları okuyup işleyen taraf
PowerShell bu üç rolü de üstlenebilir. Hem Get-WinEvent gibi yüksek seviyeli cmdlet’ler hem de doğrudan ETW API çağrıları ile çalışabilirsiniz.
Temel ETW Araçları: Get-WinEvent ile Başlamak
Çoğu sysadmin için ilk temas noktası Get-WinEvent‘tir. Eski Get-EventLog‘un aksine ETW tabanlı kanalları da okuyabilir ve çok daha hızlıdır.
# Son 50 System log olayını getir
Get-WinEvent -LogName System -MaxEvents 50
# Kritik ve hata seviyesindeki olayları filtrele
Get-WinEvent -LogName System | Where-Object { $_.Level -le 2 }
# Belirli bir Event ID'yi ara
Get-WinEvent -LogName Security | Where-Object { $_.Id -eq 4625 }
Ama asıl güç FilterHashtable parametresinde yatar. Bu yöntem XML filtrelemeye göre çok daha hızlıdır çünkü ETW altyapısına doğrudan filtre geçirir:
# Son 24 saatte başarısız oturum açma girişimleri
$filter = @{
LogName = 'Security'
Id = 4625
StartTime = (Get-Date).AddHours(-24)
}
Get-WinEvent -FilterHashtable $filter | Select-Object TimeCreated, Message
ETW Provider’larını Keşfetmek
Sisteminizdeki kayıtlı tüm provider’ları listelemek için:
# Tüm kayıtlı ETW provider'larını listele
$providers = [System.Diagnostics.Eventing.Reader.EventLogSession]::GlobalSession.GetProviderNames()
$providers | Sort-Object | Where-Object { $_ -like "*Microsoft-Windows-DNS*" }
# Alternatif olarak logman aracıyla
logman query providers | Select-String "DNS"
# Belirli bir provider'ın desteklediği kanalları gör
$session = New-Object System.Diagnostics.Eventing.Reader.EventLogSession
$providerMeta = New-Object System.Diagnostics.Eventing.Reader.ProviderMetadata("Microsoft-Windows-DNS-Client")
$providerMeta.Events | Select-Object Id, Description | Sort-Object Id
Bu komutla hangi uygulamanın hangi GUID altında kayıtlı olduğunu bulabilir, izleme oturumlarınızı hedefli şekilde kurabilirsiniz.
Analytic ve Debug Kanallarını Açmak
Windows, varsayılan olarak bazı kanalları kapalı tutar. Özellikle Analytic ve Debug kanalları çok ayrıntılı veri içerir ama disk alanı tüketimini artırır. Sorun giderme sırasında bunları açmak gerekebilir:
# Kapalı kanalları listele
Get-WinEvent -ListLog * | Where-Object { $_.IsEnabled -eq $false -and $_.LogType -eq 'Analytical' } |
Select-Object LogName, LogType, RecordCount
# Belirli bir analytic kanalı etkinleştir
$log = New-Object System.Diagnostics.Eventing.Reader.EventLogConfiguration("Microsoft-Windows-TaskScheduler/Operational")
$log.IsEnabled = $true
$log.SaveChanges()
# Kanalı tekrar kapat (veri topladıktan sonra)
$log.IsEnabled = $false
$log.SaveChanges()
Bu yaklaşımı özellikle Task Scheduler sorunlarını, WMI aktivitelerini veya uygulama başlatma hatalarını debug ederken kullanıyorum. Kanal açık kaldığında disk dolabilir, bu yüzden iş bitince kapatmayı unutmayın.
Gerçek Dünya Senaryosu 1: Başarısız Oturum Açmaları Tespit Etmek
Bir sabah iş yerine geldiniz ve birinin gece boyunca sunucunuza brute-force saldırısı denediğini düşünüyorsunuz. Security logunu incelemek için:
# Son 12 saatte IP bazında başarısız oturum açmaları grupla
$failedLogins = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4625
StartTime = (Get-Date).AddHours(-12)
} -ErrorAction SilentlyContinue
$failedLogins | ForEach-Object {
$xml = [xml]$_.ToXml()
[PSCustomObject]@{
Time = $_.TimeCreated
User = $xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' } | Select-Object -ExpandProperty '#text'
SourceIP = $xml.Event.EventData.Data | Where-Object { $_.Name -eq 'IpAddress' } | Select-Object -ExpandProperty '#text'
WorkStation = $xml.Event.EventData.Data | Where-Object { $_.Name -eq 'WorkstationName' } | Select-Object -ExpandProperty '#text'
}
} | Group-Object SourceIP | Sort-Object Count -Descending | Select-Object -First 10 Name, Count
Bu scripti her gün sabah çalıştırıp sonuçları mail atacak şekilde Task Scheduler’a ekleyebilirsiniz. 10’un üzerinde deneme yapan IP’yi otomatik olarak Windows Firewall’a eklemek için de genişletebilirsiniz.
ETW Oturumları Oluşturmak: Logman Entegrasyonu
Yüksek performanslı, gerçek zamanlı izleme için logman aracını PowerShell içinden kullanmak en pratik yoldur. Kernel seviyesinde bile çalışabilirsiniz:
# Yeni bir ETW izleme oturumu başlat
# DNS sorgu izleme örneği
logman create trace "DNS-Trace" -p "Microsoft-Windows-DNS-Client" -o "C:ETWLogsdns_trace.etl" -ets
# İzlemeyi durdur ve dosyayı kapat
logman stop "DNS-Trace" -ets
# .etl dosyasını okunabilir formata dönüştür
netsh trace convert input="C:ETWLogsdns_trace.etl" output="C:ETWLogsdns_trace.txt" overwrite=yes
# PowerShell ile oturum durumunu kontrol et
$session = logman query "DNS-Trace" -ets 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host "Oturum aktif" -ForegroundColor Green
} else {
Write-Host "Oturum bulunamadi" -ForegroundColor Yellow
}
Daha kapsamlı bir izleme için birden fazla provider’ı aynı oturuma ekleyebilirsiniz:
# Network ve process aktivitelerini aynı anda izle
logman create trace "SystemActivity" `
-p "Microsoft-Windows-Kernel-Process" `
-p "Microsoft-Windows-Kernel-Network" `
-o "C:ETWLogssystem_activity.etl" `
-f bincirc `
-max 256 `
-ets
# Belirli süre sonra otomatik durdur
Start-Sleep -Seconds 300
logman stop "SystemActivity" -ets
Write-Host "Izleme tamamlandi. Dosya: C:ETWLogssystem_activity.etl"
-f bincirc parametresi circular buffer formatını etkinleştirir, -max 256 ise maksimum 256 MB dosya boyutu belirler. Uzun süreli izlemelerde disk şişmesini önlemek için bu ikisini birlikte kullanın.
Gerçek Dünya Senaryosu 2: Ani Yükselen CPU’yu Analiz Etmek
Bir uygulama sunucusunda CPU’nun belirli saatlerde %90’a fırladığını fark ettiniz ama nedeni belirsiz. ETW ile process seviyesinde neler olduğunu görebilirsiniz:
# Process oluşturma olaylarını izle (Event ID 4688 - Audit Process Creation etkin olmalı)
function Get-ProcessActivity {
param(
[int]$DurationMinutes = 30,
[string]$OutputPath = "C:LogsProcessActivity"
)
# Audit Process Creation'ı etkinleştir
auditpol /set /subcategory:"Process Creation" /success:enable /failure:enable | Out-Null
# ETW izlemesini başlat
$traceName = "ProcessTrace_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
$etlPath = "$OutputPath$traceName.etl"
New-Item -Path $OutputPath -ItemType Directory -Force | Out-Null
logman create trace $traceName `
-p "Microsoft-Windows-Kernel-Process" 0x10 `
-o $etlPath `
-ets
Write-Host "[$traceName] $DurationMinutes dakika izleniyor..." -ForegroundColor Cyan
Start-Sleep -Seconds ($DurationMinutes * 60)
logman stop $traceName -ets
Write-Host "Izleme durduruldu. ETL: $etlPath" -ForegroundColor Green
# Security logdan process olaylarini getir
$events = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4688
StartTime = (Get-Date).AddMinutes(-$DurationMinutes)
} -ErrorAction SilentlyContinue
$events | ForEach-Object {
$xml = [xml]$_.ToXml()
[PSCustomObject]@{
Time = $_.TimeCreated
ProcessName = $xml.Event.EventData.Data | Where-Object { $_.Name -eq 'NewProcessName' } | Select-Object -ExpandProperty '#text'
ParentProc = $xml.Event.EventData.Data | Where-Object { $_.Name -eq 'ParentProcessName' } | Select-Object -ExpandProperty '#text'
CommandLine = $xml.Event.EventData.Data | Where-Object { $_.Name -eq 'CommandLine' } | Select-Object -ExpandProperty '#text'
}
} | Export-Csv "$OutputPath$traceName_processes.csv" -NoTypeInformation -Encoding UTF8
Write-Host "Sonuclar: $OutputPath$traceName_processes.csv"
}
Get-ProcessActivity -DurationMinutes 30
Windows Event Forwarding ile Merkezi Toplama
Tek bir sunucuyu izlemek yeterli değil, elinizde onlarca sunucu var. Windows Event Forwarding (WEF) ve PowerShell birlikte kullanıldığında merkezi bir izleme altyapısı kurabilirsiniz:
# Collector sunucusunda WEF servisini yapılandır
winrm quickconfig -quiet
wecutil qc /quiet
# Subscription oluştur (Collector Initiated)
$subscriptionXml = @"
<Subscription xmlns="http://schemas.microsoft.com/2006/03/windows/events/subscription">
<SubscriptionId>SecurityEvents</SubscriptionId>
<SubscriptionType>CollectorInitiated</SubscriptionType>
<Description>Kritik Guvenlik Olaylari</Description>
<Enabled>true</Enabled>
<Uri>http://schemas.microsoft.com/wbem/wsman/1/windows/EventLog</Uri>
<ConfigurationMode>Normal</ConfigurationMode>
<Delivery Mode="Push">
<Batching>
<MaxLatencyTime>900000</MaxLatencyTime>
</Batching>
<PushSettings>
<Heartbeat Interval="900000"/>
</PushSettings>
</Delivery>
<Query>
<![CDATA[<QueryList>
<Query Id="0">
<Select Path="Security">*[System[(EventID=4624 or EventID=4625 or EventID=4648 or EventID=4672)]]</Select>
</Query>
</QueryList>]]>
</Query>
<EventSources>
<EventSource Enabled="true">
<Address>web01.domain.local</Address>
</EventSource>
<EventSource Enabled="true">
<Address>app01.domain.local</Address>
</EventSource>
</EventSources>
<ContentFormat>RenderedText</ContentFormat>
<Locale Language="tr-TR"/>
</Subscription>
"@
$subscriptionXml | Out-File -FilePath "C:Tempsecurity_subscription.xml" -Encoding UTF8
wecutil cs "C:Tempsecurity_subscription.xml"
Write-Host "Subscription olusturuldu" -ForegroundColor Green
# Mevcut subscriptionlari listele
wecutil es | ForEach-Object { Write-Host "Subscription: $_" }
Özel ETW Provider Yazmak
Kendi uygulamanızdan ETW olayları üretmek isteyebilirsiniz. PowerShell 5.1 ve üzeri ile bu mümkündür:
# Basit bir EventSource kullanan custom provider
Add-Type -TypeDefinition @"
using System.Diagnostics.Tracing;
[EventSource(Name = "MyCompany-MyApp-Operations")]
public class AppEventSource : EventSource
{
public static AppEventSource Log = new AppEventSource();
[Event(1, Level = EventLevel.Informational, Message = "Islem basladi: {0}")]
public void OperationStart(string operationName)
{
WriteEvent(1, operationName);
}
[Event(2, Level = EventLevel.Error, Message = "Hata olustu: {0} - {1}")]
public void OperationError(string operationName, string errorMessage)
{
WriteEvent(2, operationName, errorMessage);
}
[Event(3, Level = EventLevel.Informational, Message = "Islem tamamlandi: {0} - Sure: {1}ms")]
public void OperationComplete(string operationName, long durationMs)
{
WriteEvent(3, operationName, durationMs);
}
}
"@ -ReferencedAssemblies @("System.Core")
# Provider'ı kullan
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
[AppEventSource]::Log.OperationStart("DatabaseBackup")
try {
# Simule edilmis islem
Start-Sleep -Milliseconds 500
[AppEventSource]::Log.OperationComplete("DatabaseBackup", $stopwatch.ElapsedMilliseconds)
}
catch {
[AppEventSource]::Log.OperationError("DatabaseBackup", $_.Exception.Message)
}
Performans Optimizasyonu: Büyük Log Dosyalarını İşlemek
Prod ortamında binlerce olay içeren log dosyalarını işlerken dikkat edilmesi gereken noktalar var:
# Buyuk log dosyalarini verimli isle
function Process-LargeEventLog {
param(
[string]$LogName = "Security",
[DateTime]$StartTime = (Get-Date).AddDays(-7),
[DateTime]$EndTime = (Get-Date),
[int[]]$EventIds = @(4624, 4625, 4648),
[string]$OutputCsv = "C:LogsSecurityReport.csv"
)
$filter = @{
LogName = $LogName
Id = $EventIds
StartTime = $StartTime
EndTime = $EndTime
}
$results = [System.Collections.Generic.List[PSCustomObject]]::new()
$counter = 0
# Batch isleme ile bellek kullanimi kontrol et
$events = Get-WinEvent -FilterHashtable $filter -ErrorAction SilentlyContinue
foreach ($event in $events) {
$counter++
# Her 1000 olayda bir ekrana bildir
if ($counter % 1000 -eq 0) {
Write-Progress -Activity "Olaylar isleniyor" -Status "$counter olay islendi" -PercentComplete -1
}
$xml = [xml]$event.ToXml()
$obj = [PSCustomObject]@{
TimeCreated = $event.TimeCreated
EventId = $event.Id
Level = $event.LevelDisplayName
Computer = $event.MachineName
UserId = $event.UserId
Message = ($event.Message -split "`n")[0] # Sadece ilk satiri al
}
$results.Add($obj)
# Her 5000 kayitta bir CSV'e yaz ve listeyi temizle
if ($results.Count -ge 5000) {
$results | Export-Csv -Path $OutputCsv -NoTypeInformation -Append -Encoding UTF8
$results.Clear()
[GC]::Collect() # Garbage collector'u zorla calistir
}
}
# Kalan kayitlari yaz
if ($results.Count -gt 0) {
$results | Export-Csv -Path $OutputCsv -NoTypeInformation -Append -Encoding UTF8
}
Write-Host "Toplam $counter olay islendi. Rapor: $OutputCsv" -ForegroundColor Green
}
Process-LargeEventLog -StartTime (Get-Date).AddDays(-3) -OutputCsv "C:LogsSecurityReport_$(Get-Date -Format 'yyyyMMdd').csv"
[System.Collections.Generic.List[PSCustomObject]] kullanımı, += operatörüne göre büyük veri setlerinde çok daha hızlıdır çünkü her eklemede yeni bir dizi oluşturulmaz.
ETW ile Ağ Aktivitesi İzleme
Özellikle malware analizi veya yetkisiz bağlantıları tespit etmek için ağ olaylarını izlemek kritik önem taşır:
# Ağ bağlantı olaylarini topla (Windows Firewall logging etkin olmali)
function Get-SuspiciousConnections {
param(
[string[]]$SuspiciousPorts = @("4444", "1337", "31337", "8888"),
[int]$HoursBack = 6
)
# Firewall logunu etkinlestir (yoksa)
netsh advfirewall set allprofiles logging droppedconnections enable | Out-Null
netsh advfirewall set allprofiles logging allowedconnections enable | Out-Null
# Security logdan ağ olaylarini al
$networkEvents = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = @(5156, 5158) # Filtering Platform Connection events
StartTime = (Get-Date).AddHours(-$HoursBack)
} -ErrorAction SilentlyContinue
$suspicious = $networkEvents | ForEach-Object {
$xml = [xml]$_.ToXml()
$destPort = $xml.Event.EventData.Data | Where-Object { $_.Name -eq 'DestPort' } | Select-Object -ExpandProperty '#text'
$destAddr = $xml.Event.EventData.Data | Where-Object { $_.Name -eq 'DestAddress' } | Select-Object -ExpandProperty '#text'
$appName = $xml.Event.EventData.Data | Where-Object { $_.Name -eq 'Application' } | Select-Object -ExpandProperty '#text'
if ($destPort -in $SuspiciousPorts) {
[PSCustomObject]@{
Time = $_.TimeCreated
Application = $appName
DestAddress = $destAddr
DestPort = $destPort
EventId = $_.Id
}
}
} | Where-Object { $_ -ne $null }
if ($suspicious) {
Write-Warning "UYARI: $($suspicious.Count) supheyli baglanti tespit edildi!"
$suspicious | Format-Table -AutoSize
} else {
Write-Host "Son $HoursBack saatte supheyli baglanti bulunamadi." -ForegroundColor Green
}
return $suspicious
}
Get-SuspiciousConnections -HoursBack 24
İzleme Senaryoları için Öneriler
Günlük operasyonlarda ETW’yi etkin kullanmak için bazı pratik noktalar:
- Analytic kanalları sadece aktif sorun giderme sırasında açın, iş bitince kapatın
- FilterHashtable kullanımını her zaman tercih edin, XML query’ye göre belirgin biçimde daha hızlıdır
- ETL dosyaları için Windows Performance Analyzer (WPA) veya PerfView araçlarını kullanın, doğrudan PowerShell ile okumaktan çok daha verimlidir
- Circular buffer modunu uzun süreli izlemelerde mutlaka kullanın
- Remote log toplama için WinRM’nin açık olduğundan emin olun:
Enable-PSRemoting -Force - Event log boyutlarını düzenli gözden geçirin:
Get-WinEvent -ListLog Security | Select-Object MaximumSizeInBytes, FileSize - Önemli Event ID’leri not alın: 4624 (başarılı oturum), 4625 (başarısız oturum), 4688 (process oluşturma), 7045 (yeni servis kurulumu)
Sonuç
ETW ve PowerShell kombinasyonu, Windows ortamında gözlemlenebilirliği ciddi ölçüde artıran güçlü bir çifttir. Basit Get-WinEvent sorgularından başlayıp özel provider’lar yazmaya, merkezi log toplama altyapısı kurmaya kadar geniş bir yelpazede kullanabilirsiniz. Burada anlattıklarım çoğunlukla kendi prod ortamlarımda test ettiğim ve işe yaradığını gördüğüm yaklaşımlar.
Başlangıç için şu üç alışkanlığı edinmenizi öneririm: her sabah önceki geceye ait başarısız oturum açmaları ve yeni kurulu servisleri kontrol eden otomatik bir script, kritik sunucularda process creation audit’ini açık tutmak ve en az aylık bazda event log boyutlarını gözden geçirmek. Bu üçü bile birçok sorunu henüz büyümeden yakalamanızı sağlar.
Sonraki adım olarak PerfView ve Windows Performance Analyzer araçlarını incelemenizi tavsiye ederim. ETL dosyalarını görsel olarak analiz etmek, PowerShell çıktısını okumaktan kat kat daha hızlı içgörü sağlar. Özellikle uygulama performans sorunlarında bu araçlar olmadan ETW’nin potansiyelinin yarısını bile kullanamazsınız.