Windows işletim sistemi, çalışması sırasında sistem, donanım, uygulama ve güvenlik bileşenlerine ait olayları sürekli olarak kaydeder. Bu kayıtlar, "Event Viewer" (Olay Görüntüleyicisi) aracılığıyla veya komut satırı/PowerShell üzerinden incelenebilir durumdadır.

Ekran görüntüsü 2025-06-01 015758.webp


Neden Windows günlükleri veya neden özel görünümler olduğunu hiç merak ettiniz mi? Aslında ben de etmemiştim. Sadece bununla alakalı bir kodlama yaparken detaylıca araştırmam gerektiği için fark etmiş oldum. Yönetim olayları neden Windows günlüklerine dahil değil? Neden diğerleri gibi basitçe export edilmiyor ki?

Aslında cevabı basit, Yönetim olayları bir sistem günlüğü olmadığı için.

Windows Olay Günlüklerini, sistemdeki her önemli işlemi, hata veya uyarıyı kaydetmek üzere tasarlanmış merkezi bir log sistemi olarak düşünün. Bu sistemde; Sistem (System), Uygulama (Application), Kur (Setup), Güvenlik (Security) gibi temel log kategorileri bulunur. Her olay, bir event ID, zaman damgası, olay seviyesi, kaynak (provider), açıklama ve gerekirse binary veri içerir.

Yönetim Olayları (Administrative Events), bir sistem günlüğü değil. Diğerleri bir günlük ama yönetim olayları değil çünkü bu loglar arasından seviye olarak kritik (Critical), hata (Error) ve uyarı (Warning) olanların öncelikli olarak filtrelenip sistem yöneticisine sunulduğu özel bir kategori olduğu için. Aslında yönetim olayları ayrı bir kategori değil, diğer kategori log'larının filtrelenmiş hali.

Bu filtreleme, genellikle "Custom Views" altında bulunan "Administrative Events" görünümü ile yapılıyor. Bu görüntüleme sayesinde, sistemdeki en önemli olaylara hızlıca erişim sağlanabilir. Bunu sistem üzerinden Yönetim olayları > Özellikler > Filtre düzenle... başlığı altından inceleyebilirsiniz.

Ekran görüntüsü 2025-06-01 020303.webp


Peki bu filtreleme nedir diye düşünürken, Olay düzeyi kısmı dikkatimi çekti. Sonradan bu konuda şunu fark ettim ki Windows bu olayları level sistemine göre kaydedip filtreliyor.

Aslında her Windows olayı, ciddilik derecesini belirtmek için bir "Level" (Seviye) bilgisiyle etiketleniyor. Bu seviye, olayın sistem stabilitesi açısından önemini belirtmekte kullanılıyor...

LevelSeviye AdıAnlamıKullanım Amacı
1CriticalÖnemliAniden yeniden başlatma, çökme gibi sistem için yıkıcı etkisi olan olaylar
2ErrorHataServis durması, disk hatası gibi müdahale gerektiren olaylar
3WarningUyarıGeçici sorunlar, potansiyel riskler
4InformationBilgiNormal işleyiş olayları, servis başlatıldı vb.
5VerboseAyrıntılıDebug, ayrıntılı analiz için kullanılır

Bu aslında neden yönetim olaylarının her zaman Level 1, 2 ve 3 (Critical, Error, Warning) olaylarından oluştuğunu kanıtlıyor. Bu olaylar sistem kararlılığı ve sorun tespiti için temel analiz malzemesidir.

Her bir olay, belirli bir bileşen ya da servis tarafından üretilir. Bu servis "Provider" (Kaynak/Sağlayıcı) olarak adlandırılır. Olay kaynağı, olayı hangi sistem bölümü veya uygulamasının oluşturduğunu belirler.

ProviderÖzellikKullanım Amacı
Kernel-PowerSistemBeklenmedik kapanmalar, ACPI sorunları
VolmgrDiskVolume Manager olayları (disk arızaları)
Kernel-PnPDonanımDonanım tak- çıkar olayları
WHEA-LoggerDonanımDonanımsal hata raporları
Application ErrorUygulamaUygulama çökmeleri

Filtreleme yaparken bu provider adı kullanılarak olaylar daraltılabilir.


Buraya kadar olan kısım bu olayların kısaca ne olduğu ve filtrelendirilmesinin nasıl işlendiği ile ilgiliydi. Bundan sonrası ile bunun nasıl yapılacağı ile ilgili.

=CMD=

İlk ve en temel komutumuz wevtutil. Kendisi olay günlüğü (event log) işlemleri yapmak için kullanılan bir komut satırı aracı. Bu araç sayesinde sistem, güvenlik, uygulama gibi günlükleri yönetebilir, içeriğini görüntüleyebilir, yedekleyebilir veya silebiliyorsun.


Örnek olarak
Rich (BB code):
wevtutil epl System "%USERPROFILE%\Desktop\system_log.evtx"

Wevutil komut aracı ile sistem olaylarını masaüstüne kaydedebilirsiniz.

Rich (BB code):
wevtutil epl Application C:\Masaüstü\application.evtx

Örneği ile uygulama olaylarını masaüstüne alabilirsiniz.

epl sorgusu Windows'un wevutil makalesinde de belirttiği gibi [{epl | export-log}} ilgili olayları export etme sorgusudur.

Bu noktada Wevtutil ile Administrative Events gibi özel görünümleri expor edemiyoruz direkt olarak çünkü C:\ProgramData\Microsoft\Event Viewer\Views altında sadece .xml olarak tutuluyorlar ve evtx şeklinde export etmek olanaksız oluyor. Bunu 2 şekilde filtreleyebiliyoruz.

Level Filtreleme:
Rich (BB code):
wevtutil qe System /q:"*[System[(Level=1 or Level=2 or Level=3)]]" /f:text  > "%USERPROFILE%\Desktop\Olaylar.text"
Burada kod açıkça, System olaylarındaki 1,2,3 (Yönetim olayları sorgusu) seviyeleri olayları tespit edip Masaüstündeki Olaylar isimli text belgesine yazıyor.

Dipnot: Bunu kullanmanızı belli bir olay sayısı kullanmıyorsanız (Son 10 olayı al tarzı.) önermem. Muhtemelen o text dosyasını açtığınız an donacaktır. Bunun da UTF8 formatından kaynaklandığını düşünüyorum... XML formatını kullanmaya çalışın daha karışık olsa da.

Consider Filtreleme:

Rich (BB code):
wevtutil qe System /q:"*[System[(EventID=41 or EventID=6008)]" /f:text > %USERPROFILE%\Desktop\FiltrelenmisOlay.txt

Bu kod da açıkça, System olaylarındaki 41 veya 6008 ID'li olayları tespit edip Masaüstündeki FiltrelenmisOlay isimli text belgesine yazıyor.

Dipnot: Belli bir ID aramasında txt kullanmak hem daha temiz bir sonuç verir hem de donmayan bir not belgesi sunar.
  • qe İlgili olayları sorgulayan yardımcı komut.
  • /q:"..." İlgili olay yolunu sorgulayan yardımcı komut.
  • /f:text çıktı formatı.
Bunlara ek olarak eğer Level filtrelemesi yaparken temiz bir txt belgesi almak istiyorsanız /c: yardımcı komutuyla son ".." olay sayısı kadarının level filtrelemesini yapabilirsiniz. Örneğin:

Rich (BB code):
wevtutil qe System /q:"*[System[(Level=1 or Level=2 or Level=3)]]" /f:text /c:50
1,2,3 seviyeli son 50 olayı "...." isimli text belgesine yazar. Bu da UTF konusunda sıkıntı çıkarmadan temiz bir sonuç verir.

Aynı şekilde bunları daha düzenli ve esnek olarak PowerShell ile de oluşturabilme şansımız var. Bu noktada karşımıza Get-WinEvent komut aracı çıkıyor. Öncelikle bunun da temelinde wevtutil ile aynı şeyi yaptığını söyleyebilirim. Farkları birden farklı birkaç olayı export etmeye çalışırken ortaya çıkıyor.


Örneğin PowerShell ile basit bir oluşturma kodu yazabiliriz:
Rich (BB code):
Get-WinEvent -LogName System -MaxEvents 100 | Out-File "C:\Logs\SistemOlaylari.txt"

Böylelikle son 100 olayı çekebiliriz. CMD komutundan farkı ise, PowerShell ile tarihe göre sıralama yapma şansımız da var:
Rich (BB code):
Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    Level = 1,2
    StartTime = (Get-Date).AddDays(-1)
} | Sort-Object TimeCreated -Descending

Böylelikle son 1 günde oluşan 1-2 seviyeli olayları çekebiliriz. Buna bir Out-File komutu da eklemeniz gerekecektir.

Bence asıl farkları birden fazla bir sürü olayı XML olarak çekerken ortaya çıkıyor. Örneğin:

Rich (BB code):
$eventIDs = 41, 161, 129 // Olayları çek
$logName = "System"

foreach ($id in $eventIDs) {
    $events = Get-WinEvent -LogName(Örnek olarak sistem olayları) $logName | Where-Object { $_.Id -eq $id }
    $outputFile = "$env:USERPROFILE\Desktop\event_$id.xml"

    // XML olarak kaydetmek için her olayı ToXml() ile dönüştür ve dosyaya yaz
    $events | ForEach-Object { $_.ToXml() } | Out-File -FilePath $outputFile -Encoding UTF8
}

Burada yaptığımız şey $eventIDs dizisinde tanımlı olan her bir Event ID için System günlüklerinden o ID'ye ait olayları çekiyor. Daha sonra her olayı XML formatına dönüştürmek için ToXml() metodunu kullanıyor ve dönüştürülen XML verilerini kullanıcı masaüstünde, ilgili Event ID'yi içeren ayrı bir dosyaya (örneğin event_41.xml, event_161.xml, event_129.xml) kaydediyor. Böylece her Event ID için ayrı bir XML dosyası oluşturulmuş oluyor.

Aynı şeyi CMD üzerinden yapmaya çalışırsak ise:
Rich (BB code):
wevtutil qe System /q:"*[System[EventID=41]]" /f:xml > "%USERPROFILE%\Desktop\event_41.xml"
wevtutil qe System /q:"*[System[EventID=161]]" /f:xml > "%USERPROFILE%\Desktop\event_161.xml"
wevtutil qe System /q:"*[System[EventID=129]]" /f:xml > "%USERPROFILE%\Desktop\event_129.xml"

Her bir ID için tek tek consider filtrelemesi yapmamız gerekecekti.

Bu noktada bu işin en iyi kısmı da özellikle XML kaydında C tabanındaki kütüphane ve kodlarını bulduktan sonra oldu.

C++ ile Windows Event Log’dan belli Event ID’lere göre filtreleyip XML formatında dışa aktarmak da Windows API’leri kullanarak yapılabiliyor. Özellikle Windows Event Log API (EvtOpenLog, EvtQuery, EvtNext, EvtRender) bu iş için varlar.

Bundan önce DumpFinder programımda kullandığım temel XML çekme mantığını anlatacağım.

C++:
 std::string eventLogPath = systemRoot + "System32\\winevt\\Logs\\";
        std::string evtxLogs[] = { "Application.evtx", "System.evtx", "Security.evtx" };

        for (const auto& log : evtxLogs) {
            std::string src = eventLogPath + log;
            if (fs::exists(src)) {
                try {
                    fs::copy_file(src, logFolder + "\\" + log, fs::copy_options::overwrite_existing);
                    std::cout << log << msg("log_copy") << std::endl;
                    reportFile << log << " copied." << std::endl;
                }
                catch (const std::exception& e) {
                    std::cerr << msg("log_copy_fail") << e.what() << std::endl;
                }
            }
            else {
                std::cerr << log << msg("log_missing") << std::endl;
            }
        }

        std::string logs[] = { "Application", "System", "Security" };
        for (const auto& log : logs) {
            std::string outFile = logFolder + "\\" + log + "_Filtered.txt";
            std::string cmd = "wevtutil qe " + log + " /q:\"*[System[(Level=1 or Level=2 or Level=3)]]\" /f:xml > \"" + outFile + "\"";
            int ret = system(cmd.c_str());
            if (ret != 0) {
                std::cerr << log << msg("log_filter_fail") << std::endl;
            }
            else {
                std::cout << log << msg("log_filter_ok") << outFile << std::endl;
                reportFile << log << " filtered -> " << outFile << std::endl;
            }
        }
    }
    else {
        reportFile << (systemLang == Lang::TR ? "Olay raporlari eklenmedi, sadece dump dosyalarý kopyalandi." : "No event logs included, only dump files copied.") << std::endl;
    }

    reportFile << "\n" << msg("report_summary");
    if (secim == 1)
        reportFile << msg("report_with_logs");

    reportFile.close();
    std::cout << "\n" << msg("report_complete") << reportFilePath << std::endl;
}
catch (const fs::filesystem_error& e) {
    std::cerr << "Hata: " << e.what() << std::endl;
    if (reportFile.is_open()) reportFile.close();
    return 1;
}

Kodda ilk önce çok basit bir şekilde System32\\winevt\\Logs\\ dizinini eventLogPath adında bir yola tanımladım. Ardından Application.evtx, System.evtx ve Security.evtx olay günlüklerinin adlarını içeren bir dizi (evtxLogs) tanımladım. Sonra da bir günlük dosyası için döngüye girer ve dosya mevcutsa (fs::exists(src)), fs::copy_file fonksiyonu ile bu dosya, hedef klasöre (logFolder) kopyalanıyor. Kopyalanan klasör DumpFinder içinde DmpGunluk adlı bir klasör. Kopyalama başarılı olunca başarılı olduğuna dair bir uyarı görürsünüz. Genelde filtrelemesi başarılı oluyor lakin evtx formatı için izin gerekebiliyor özellikle.

İkinci döngüde de "Application", "System" ve "Security" günlük isimlerini wevtutil komutu ile sorgulama qe sorgusu başlatmak için kullandım. Her bir günlük için, XML formatında ve sadece belirli öncelik düzeylerindeki olayları içeren bir sorgu (/q) oluşturuyorum ve komut satırında çalıştırılacak komutun tam metni, cmd değişkeninde oluşturuyorum. Bu tabii ki system() fonksiyonu ile çalıştırılması gereken bir fonksiyon. Komutun çıktısı, günlük adına özel olarak oluşturulmuş bir dosyaya yönlendiriliyor (XGünlüğü_Filtred) (&gt; "outFile"). Başarılı olunca da başarılı olduğunu belirtiyor.

Bunlar sonunda da 3 olay XML toplamı bize yönetim olaylarını veriyor neredeyse :) Yönetim olaylarının bizim yapamadığımız kısmı sadece evtx formatında olması. Biz bunu direkt olarak bir kodla yapamıyoruz ne yazık ki. Export mantığında sadece XML veya UTF sorunu olmazsa txt şansımız var.

Daha komplike bir kod kullanarak da XML yapılarını çekebiliyoruz:

C++:
#include <windows.h>       // Temel Windows API fonksiyonları için
#include <winevt.h>        // Windows Event Log API fonksiyonları için
#include <iostream>        // Konsola çıktı için
#include <fstream>         // Dosya işlemleri için
#include <vector>          // Dinamik dizi için

#pragma comment(lib, "wevtapi.lib")  // wevtapi.lib kütüphanesi (Event Log API)

void ExportEventsByID(const std::wstring& logName, DWORD eventID, const std::wstring& outputFile)
{
    // Event ID filtrelemesi için XPath sorgusu oluşturuyoruz
    std::wstring query = L"*[(System/EventID=" + std::to_wstring(eventID) + L")]";

    // Belirtilen log ve sorgu ile Event Log sorgusu başlatılıyor
    EVT_HANDLE hQuery = EvtQuery(NULL, logName.c_str(), query.c_str(), EvtQueryChannelPath);

    // Eğer sorgu başarısızsa hata mesajı yazdırıp fonksiyondan çıkıyoruz
    if (!hQuery)
    {
        std::wcerr << L"EvtQuery failed with error code " << GetLastError() << std::endl;
        return;
    }

    // XML çıktı dosyasını açıyoruz özellikle binary formatı öneriyoruz
    std::ofstream outFile(outputFile, std::ios::out | std::ios::binary);

    // Dosya açılamazsa hata verip ve sorguyu kapatıyoruz
    if (!outFile.is_open())
    {
        std::wcerr << L"Cannot open output file: " << outputFile << std::endl;
        EvtClose(hQuery);
        return;
    }

    const int bufferSize = 4096;                // Başlangıç buffer boyutumuz
    std::vector<wchar_t> buffer(bufferSize);    // XML verisini tutacak buffer
    DWORD returnedCount = 0;               

    EVT_HANDLE events[10];   // Aynı anda 10 olayı tutacak dizi

    while (true)
    {
        // 10 olayı sorgudan alıyoruz, sonsuz bekleme süresi ile (INFINITE)
        if (!EvtNext(hQuery, 10, events, INFINITE, 0, &returnedCount))
        {
            // Eğer artık alınacak olay kalmamışsa döngüyü bitiriyoruz
            if (GetLastError() == ERROR_NO_MORE_ITEMS)
                break;

        
            std::wcerr << L"EvtNext failed: " << GetLastError() << std::endl;
            break;
        }

        // Alınan her olay için aynı işlemleri yapıyoruz
        for (DWORD i = 0; i < returnedCount; i++)
        {
            DWORD bufferUsed = 0;
            DWORD propertyCount = 0;

            // Olayı XML formatına dönüştürmek için buffer boyutunu sorguluyoruz
            if (!EvtRender(NULL, events[i], EvtRenderEventXml, bufferSize * sizeof(wchar_t), buffer.data(), &bufferUsed, &propertyCount))
            {
                // Yetersizse büyüt
                if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
                {
                    buffer.resize(bufferUsed / sizeof(wchar_t));

                    if (!EvtRender(NULL, events[i], EvtRenderEventXml, bufferUsed, buffer.data(), &bufferUsed, &propertyCount))
                    {
                        std::wcerr << L"EvtRender failed: " << GetLastError() << std::endl;
                        EvtClose(events[i]);
                        continue;
                    }
                }
                else
                {
                    // Başka hata durumunda mesaj yazıp olayı kapattıyoruz
                    std::wcerr << L"EvtRender failed: " << GetLastError() << std::endl;
                    EvtClose(events[i]);
                    continue;
                }
            }

            // XML verisini dosyaya yaz
            outFile << std::wstring(buffer.data()) << std::endl;

            // Olayı kapat (kaynakları serbest bırak)
            EvtClose(events[i]);
        }
    }

    // Dosyayı kapat
    outFile.close();

    // Sorguyu kapat
    EvtClose(hQuery);
}

int wmain()
{
    // İşlem yapılacak Event ID’ler ve karşılık gelen çıktı dosya yolları
    std::vector<DWORD> eventIDs = {41, 161, 129};
    std::vector<std::wstring> outputFiles = {
        L"C:\\Users\\Public\\Desktop\\event_41.xml",
        L"C:\\Users\\Public\\Desktop\\event_161.xml",
        L"C:\\Users\\Public\\Desktop\\event_129.xml"
    };

    const std::wstring logName = L"System";  // Okunacak Event Log ismi - Burada sistemi seçtim

    // Her Event ID için ExportEventsByID fonksiyonunu çağır
    for (size_t i = 0; i < eventIDs.size(); i++)
    {
        std::wcout << L"Exporting Event ID " << eventIDs[i] << L" to " << outputFiles[i] << std::endl;
        ExportEventsByID(logName, eventIDs[i], outputFiles[i]);
    }

    return 0;
}

ExportEventsByID fonksiyonu ile parametre olarak aldığımız günlük ismi (logName), Event ID (eventID) ve çıktı dosyasının yolu (outputFile) beraber çalışıyorlar. Fonksiyon içerisinde önce Event ID’ye göre bir XPath sorgusu oluşturuyorr ve bu sorgu EvtQuery() ile yürütülerek sorgu tutacağı elde ediliyor. Eğer sorgu başarısız olursa, sorgu basitçe kapatılıyor.

Daha sonra bir for döngümüz var. EvtNext() fonksiyonu ile sıradaki maksimum 10 olay alınmaya çalışılıyor. Eğer daha fazla olay yoksa döngü bitiyor. Her bir olay için EvtRender() çağrılıyor ki burada olaylar XML biçimine çevriliyor. EvtRender() başlangıçta tahmini bir buffer büyüklüğü ile çağrılıyor ama bu buffer yetersiz kalırsa diye gerekli boyut hesaplanıyor ve buffer yeniden boyutlandırılıyor, sonra tekrar EvtRender() ile XML verisi alınıyor. Bu aşamada oluşabilecek hatalar kontrol ediliyor. Başarılı dönüşümde, elde edilen XML metni çıktı dosyasına yazılır ve kod kapanır.

Ana fonksiyon (wmain) ise bir Event ID listesi (41, 161, 129) ve bu ID’lere karşılık gelen çıktı dosyalarının yollarını tutuyor. Döngü ile her Event ID için ExportEventsByID fonksiyonu çağrılıyor ve işlem gerçekleştiriliyor.



Bunları yapmadan önce mutlaka erişim iznini de kodun içine entegre etmenizi öneriyorum. Zira EvtLog export'ları için Windows yönetici izni arıyor...

C++:
#include <AccCtrl.h>
#include <windows.h>
#include <Aclapi.h>

void ErisimIstegi(const std::string& filePath) {
    DWORD result = SetNamedSecurityInfoA(
        const_cast<char*>(filePath.c_str()),
        SE_FILE_OBJECT,
        DACL_SECURITY_INFORMATION,
        NULL,
        NULL,
        NULL,
        NULL
    );

    if (result != ERROR_SUCCESS) {
        std::cerr << "Izinle Alinamadi: " << result << std::endl;
    }
}

Kaynaklar: Orin-Thomas
 
Elinize sağlık. Zahmet edip olabildiğince ayrıntılı anlatmışsınız.

wstring kullanıyorsunuz ama neden raw string kullanmıyorsunuz? Gerçi muhtemelen Windows diretmese kullanmazsınız.
std::string eventLogPath = systemRoot + "System32\\winevt\\Logs\\"; şeklinde başlayan kısım da try-catch ve if içinde gibi ama try kısmı gelmemiş.
fs için muhtemelen namespace ataması yaptınız (namespace fs = std::filesystem;), açıkça belirtilmemiş, bilinmeyen bir namespace gibi duruyor.
Keza filesystem için operator/ var. Bence kullanımı hem yazmayı hem okumayı kolaylaştırıyor.
Son olarak burada 3 başlıklı 1 tablo olması gerekirken başlıkların içinde birer tane tablo olduğu için 4 tane tablo var. O yüzden değişik görünüyor.

1748767964173.webp
 
@Vavien. Görüşlerin için teşekkür ederim, tablo hatasını ben de fark etmiştim ama konuyu gece çok geç saatte onaya gönderdiğim için düzeltmeleri gün içinde yaparım diye düşünüyordum.

wstring kullanıyorsunuz ama neden RAW string kullanmıyorsunuz? Gerçi muhtemelen Windows diretmese kullanmazsınız.
Windows'un diretmesinden değil de daha dinamik olduğundan ve RAW String'in bir tık daha sabit kullanımlı olmasından dolayı wstring kullanmıştım. Yönetim olayları log filtrelemesini araştırırken aynı anda koda geçirdiğim için de olabilir bu, spesifik bir kod düşünmesi de yok içinde...

Keza filesystem için operator/ var. Bence kullanımı hem yazmayı hem okumayı kolaylaştırıyor.
Geçen gün koda consider filtrelemesini eklemeye çalışırken operator/ ile dosya yolu oluşturmayı da denemiştim. Ancak consider filtresinde oluşan bir hata programı doğrudan kapatıyordu. Eğer bu filtreyi düzgün çalıştırabilirsem, dosya yollarında operator/ kullanımını ben de mantıklı buluyorum.

Tabloyu düzelttim.
 
Windows'un diretmesinden değil de daha dinamik olduğundan ve RAW String'in bir tık daha sabit kullanımlı olmasından dolayı wstring kullanmıştım.
Beraber kullanılabiliyorlar.

Kod:
std::vector<std::wstring> outputFiles = {
    L"C:\\Users\\Public\\Desktop\\event_41.xml",
    L"C:\\Users\\Public\\Desktop\\event_161.xml",
    L"C:\\Users\\Public\\Desktop\\event_129.xml"
};
std::vector<std::wstring> outputFiles = {
    LR"(C:\Users\Public\Desktop\event_41.xml)",
    LR"(C:\Users\Public\Desktop\event_161.xml)",
    LR"(C:\Users\Public\Desktop\event_129.xml)",
};
 
String yapısını basitleştirdim. Operator de ekledim haliyle bunu yapınca da önceden dediğim gibi Windows consider filtrelemesinde sıkıntı çıkarıyor şu anlık gördüğüm.

Rich (BB code):
 if (choice == 1) {
 fs::path systemEvtx = systemRoot / R"(System32\winevt\Logs\System.evtx)";
 if (fs::exists(systemEvtx)) {
 try {
 fs::copy_file(systemEvtx, logFolder / "System.evtx", fs::copy_options::overwrite_existing);
 std::cout << "System.evtx" << msg("log_copy") << std::endl;
 reportFile << "System.evtx copied." << std::endl;
 }
 catch (const std::exception& e) {
 std::cerr << msg("log_copy_fail") << e.what() << std::endl;
 }

 std::string outFile = (logFolder / "System_Filtered.txt").string();
 std::string cmd = "wevtutil qe System /q:\"*[System[(Level=1 or Level=2 or Level=3)]]\" /f:xml > \"" + outFile + "\"";
 int ret = system(cmd.c_str());
 if (ret != 0) {
 std::cerr << "System" << msg("log_filter_fail") << std::endl;
 }
 else {
 std::cout << "System" << msg("log_filter_ok") << outFile << std::endl;
 reportFile << "System filtered -> " << outFile << std::endl;
 }
 }
 else {
 std::cerr << "System.evtx" << msg("log_missing") << std::endl;
 }
 }
 else {
 reportFile << (systemLang == Lang::TR ? "Sadece dump dosyalari kopyalandi." : "Only dump files copied.") << std::endl;
 }

 reportFile << "\n" << msg("report_summary");
 if (choice == 1) reportFile << msg("report_with_logs");

 reportFile.close();
 std::cout << "\n" << msg("report_complete") << reportFilePath.string() << std::endl;
 }
 catch (const fs::filesystem_error& e) {
 std::cerr << "Hata: " << e.what() << std::endl;
 return 1;
 }

 system("pause");
 return 0;
}