Parsing Event Log Files
Filtering and searching an event log using the Event Log Viewer (eventvwr) is often unpractical and it is quicker to
save the selected content of the Event Log to a Event Log File of the format .evtx.
This is done using the following classes in System.Diagnostics.Eventing.Reader:
- EventLogReader
- EventLogQuery
- EventLogRecord
The following code is a console line application written in C# generating excel files with filtered contents of the event log file.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Eventing.Reader;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using OfficeOpenXml;
using OfficeOpenXml.Style;
namespace EventLogParserUtility
{
class Program
{
private static void Main(string[] args)
{
bool outputToExcel = false;
string eventLogFileName = null;
string excelFileName = null;
Console.WriteLine("Starting analysis of target Event Log file: ");
Timer timer = new Timer(TimerTick, null, 0, 100);
if (args.Any(a => a.StartsWith(@"-f:")))
{
eventLogFileName = args.First(a => a.StartsWith(@"-f:")).Split(':')[1];
}
if (string.IsNullOrEmpty(eventLogFileName))
{
ShowUsageInfo();
return;
}
var events = from l in LogRecordCollection(eventLogFileName)
where l.Properties.Any()
&& l.Properties[0].Value != null
select l;
if (args.Any(a => a.StartsWith(@"-t:")))
{
string timeArgument = args.First(a => a.StartsWith(@"-t:")).Split(':')[1];
DateTime fromTime;
if (DateTime.TryParse(timeArgument, out fromTime))
{
events = events.Where(e => e.TimeCreated >= fromTime);
} //if
} //if
if (args.Any(a => a.StartsWith(@"-m:")))
{
string messageArgument = args.First(a => a.StartsWith(@"-m:")).Split(':')[1].Replace("'", "");
events =
events.Where(
e => Regex.IsMatch(e.Properties[0].Value.ToString(), messageArgument, RegexOptions.IgnoreCase));
}
if (args.Any(a => a.StartsWith(@"-excel:")))
{
excelFileName = DateTime.Now.ToString("ddmmyyyyhhmmss") + args.First(a => a.StartsWith(@"-excel:")).Split(':')[1].Replace("'", "");
outputToExcel = true;
}
if (!outputToExcel)
{
foreach (var e in DistinctBy(events, e => e.RecordId).OrderByDescending(e => e.TimeCreated))
{
Console.WriteLine(Environment.NewLine + e.TimeCreated + Environment.NewLine +
GetFilteredValue(e.Properties[0].Value, args));
Console.WriteLine("Hit enter to go to NEXT.");
Console.ReadKey();
}
}
else
{
using (var excelPackage = new ExcelPackage(new FileInfo(Path.Combine(Directory.GetCurrentDirectory(), excelFileName))))
{
excelPackage.Workbook.Worksheets.Add("Eventlog matches:" + DateTime.Now.ToShortDateString());
var workSheet = excelPackage.Workbook.Worksheets[1];
int rowIndex = 2;
workSheet.Cells[1, 1].Value = "Level";
workSheet.Cells[1, 2].Value = "Date and Time";
workSheet.Cells[1, 3].Value = "Source";
workSheet.Cells[1, 4].Value = "Details";
workSheet.Cells[1, 5].Value = "Computer Name";
workSheet.Cells[1, 6].Value = "Filtered Details";
workSheet.Cells[1, 1, 1, 6].Style.Font.Bold = true;
workSheet.Cells[1, 1, 1, 6].Style.Font.Size = 14;
foreach (var e in DistinctBy(events, e => e.RecordId).OrderByDescending(e => e.TimeCreated))
{
workSheet.Cells[rowIndex, 1].Value = e.Level;
workSheet.Cells[rowIndex, 2].Value = e.TimeCreated;
workSheet.Cells[rowIndex, 2].Style.Numberformat.Format = "dd.mm.yyyy hh:mm";
workSheet.Cells[rowIndex, 3].Value = e.ProviderName;
workSheet.Cells[rowIndex, 4].Value = e.Properties[0].Value;
workSheet.Cells[rowIndex, 5].Value = e.MachineName;
workSheet.Cells[rowIndex, 6].Value = GetFilteredValue(e.Properties[0].Value, args);
workSheet.Cells[rowIndex, 1, rowIndex, 5].Style.Fill.PatternType = ExcelFillStyle.Solid;
workSheet.Cells[rowIndex, 1, rowIndex, 5].Style.Fill.BackgroundColor.SetColor(rowIndex % 2 == 0
? Color.AliceBlue
: Color.White);
rowIndex++;
}
workSheet.Cells[workSheet.Dimension.Address].AutoFitColumns();
excelPackage.Save();
}
Process.Start(Path.Combine(Directory.GetCurrentDirectory(), excelFileName));
}
timer.Dispose();
Console.WriteLine("All done. Press the any key to continue ..");
Console.ReadKey();
}
private static string GetFilteredValue(object value, string[] args)
{
if (args.Any(a => a.StartsWith("-o:")))
{
var pattern = string.Join(":", args.First(a => a.StartsWith("-o:")).Split(':').Skip(1)).Replace("<", "<")
.Replace(">", ">").Replace("'", "").Trim();
Regex filterMatch =
new Regex(pattern, RegexOptions.IgnoreCase);
Match mc = filterMatch.Match(value.ToString());
StringBuilder sb = new StringBuilder();
foreach (Group group in mc.Groups)
{
sb.Append(group.Value + " ");
}
return sb.ToString();
}
return value.ToString();
}
private static void TimerTick(object state)
{
Console.Write(".");
}
private static void ShowUsageInfo()
{
Console.WriteLine("Example Usage: EventLogParserUtility -f:MyEventLogFile.evtx "
+ Environment.NewLine + "Additional parameters: -t:1.1.2015 [TimeCreated larger than] "
+ Environment.NewLine + "-m:MySearchKey [Properties[0].Value or Message contains] "
+ Environment.NewLine + "-excel:SomeFileName.xlsx [Outputting to Excel file]"
+ Environment.NewLine + "-o:MyFilter [Filter output by regex]");
}
static IEnumerable<EventLogRecord> LogRecordCollection(string filename, string xpathquery = "*")
{
var eventLogQuery = new EventLogQuery(filename, PathType.FilePath, xpathquery);
using (var eventLogReader = new EventLogReader(eventLogQuery))
{
EventLogRecord eventLogRecord;
while ((eventLogRecord = (EventLogRecord)eventLogReader.ReadEvent()) != null)
{
yield return eventLogRecord;
}
}
}
static IEnumerable<T> DistinctBy<T, TKey>(IEnumerable<T> inputList, Func<T, TKey> keySelector, IEqualityComparer<TKey> comparer = null)
{
var distinctItems = inputList.GroupBy(keySelector, comparer).Select(g => g.First()).ToList();
return distinctItems;
}
}
}
The command line application is able to output content of the event log file that matches a given search term key and also output a filtered column specified by a Regex.
cd EventLogParserUtility\bin\Debug
EventLogParserUtility -f:EventLogs\hendelseslogg.evtx -m:'OfficialId' -excel:MyOutputExcelFile.xlsx -o:'<OfficialId>(?<x>.*)</OfficialId>'
Supported switches in EventLogParserUtility:
-f: File name of event log file (obligatory column)
-m: Search messages in event log specified by search term. It is possible to type in a regex here (optional parameter)
-excel: filename to output to excel (optional parameter)
-o: Regular expression to use to filter the message additionally for targeted output (will be displayed in filtered column)
-t: Filtering to output content where TimeCreated of Event Log Item above specified date (optional parameter, specify as datetime value
To use this utilty, put the arguments of the switches inside quotes if the arguments got spaces.