Exemple #1
0
        private static void ProcessFile(string file)
        {
            if (File.Exists(file) == false)
            {
                _logger.Warn($"'{file}' does not exist! Skipping");
                return;
            }

            _logger.Warn($"\r\nProcessing '{file}'...");

            Stream fileS;

            try
            {
                fileS = new FileStream(file, FileMode.Open, FileAccess.Read);
            }
            catch (Exception)
            {
                //file is in use

                if (Helper.IsAdministrator() == false)
                {
                    _logger.Fatal("\r\nAdministrator privileges not found! Exiting!!\r\n");
                    Environment.Exit(0);
                }

                _logger.Warn($"\r\n'{file}' is in use. Rerouting...");

                var files = new List <string>();
                files.Add(file);

                var rawFiles = Helper.GetFiles(files);
                fileS = rawFiles.First().FileStream;
            }

            try
            {
                var evt = new EventLog(fileS);

                var seenRecords = 0;

                foreach (var eventRecord in evt.GetEventRecords())
                {
                    if (_includeIds.Count > 0)
                    {
                        if (_includeIds.Contains(eventRecord.EventId) == false)
                        {
                            //it is NOT in the list, so skip
                            continue;
                        }
                    }
                    else if (_excludeIds.Count > 0)
                    {
                        if (_excludeIds.Contains(eventRecord.EventId))
                        {
                            //it IS in the list, so skip
                            continue;
                        }
                    }


                    eventRecord.SourceFile = file;
                    try
                    {
                        _csvWriter?.WriteRecord(eventRecord);
                        _csvWriter?.NextRecord();

                        var xml = string.Empty;
                        if (_swXml != null)
                        {
                            xml = eventRecord.ConvertPayloadToXml();
                            _swXml.WriteLine(xml);
                        }

                        if (_swJson != null)
                        {
                            JsConfig.IncludeNullValues = true;
                            JsConfig.DateHandler       = DateHandler.ISO8601;
                            var jsOut = eventRecord.ToJson();
                            if (_fluentCommandLineParser.Object.FullJson)
                            {
                                if (xml.IsNullOrEmpty())
                                {
                                    xml = eventRecord.ConvertPayloadToXml();
                                }
                                var xd = new XmlDocument();
                                xd.LoadXml(xml);

                                jsOut = JsonConvert.SerializeXmlNode(xd);
                            }

                            _swJson.WriteLine(jsOut);
                        }

                        seenRecords += 1;
                    }
                    catch (Exception e)
                    {
                        _logger.Error($"Error processing record #{eventRecord.RecordNumber}: {e.Message}");
                    }
                }

                if (evt.ErrorRecords.Count > 0)
                {
                    _errorFiles.Add(file, evt.ErrorRecords.Count);
                }

                _fileCount += 1;

                _logger.Info("");
                _logger.Fatal("Event log details");
                _logger.Info(evt);

                _logger.Info($"Records processed: {seenRecords:N0} Errors: {evt.ErrorRecords.Count:N0}");

                if (evt.ErrorRecords.Count > 0)
                {
                    _logger.Warn("\r\nErrors");
                    foreach (var evtErrorRecord in evt.ErrorRecords)
                    {
                        _logger.Info($"Record #{evtErrorRecord.Key}: Error: {evtErrorRecord.Value}");
                    }
                }

                if (_fluentCommandLineParser.Object.Metrics && evt.EventIdMetrics.Count > 0)
                {
                    _logger.Fatal("\r\nMetrics");
                    _logger.Warn("Event Id\tCount");
                    foreach (var esEventIdMetric in evt.EventIdMetrics.OrderBy(t => t.Key))
                    {
                        if (_includeIds.Count > 0)
                        {
                            if (_includeIds.Contains((int)esEventIdMetric.Key) == false)
                            {
                                //it is NOT in the list, so skip
                                continue;
                            }
                        }
                        else if (_excludeIds.Count > 0)
                        {
                            if (_excludeIds.Contains((int)esEventIdMetric.Key))
                            {
                                //it IS in the list, so skip
                                continue;
                            }
                        }

                        _logger.Info($"{esEventIdMetric.Key}\t\t{esEventIdMetric.Value:N0}");
                    }
                }
            }
            catch (Exception e)
            {
                if (e.Message.Contains("Invalid signature! Expected 'ElfFile"))
                {
                    _logger.Info($"'{file}' is not an evtx file! Message: {e.Message} Skipping...");
                }
                else
                {
                    _logger.Error($"Error processing '{file}'! Message: {e.Message}");
                }
            }

            fileS?.Close();
        }
Exemple #2
0
        private static void ProcessFile(string file)
        {
            if (File.Exists(file) == false)
            {
                _logger.Warn($"'{file}' does not exist! Skipping");
                return;
            }

            if (file.StartsWith(VssDir))
            {
                _logger.Warn($"\r\nProcessing 'VSS{file.Replace($"{VssDir}\\", "")}'");
            }
            else
            {
                _logger.Warn($"\r\nProcessing '{file}'...");
            }

            Stream fileS;

            try
            {
                fileS = new FileStream(file, FileMode.Open, FileAccess.Read);
            }
            catch (Exception)
            {
                //file is in use

                if (Helper.IsAdministrator() == false)
                {
                    _logger.Fatal("\r\nAdministrator privileges not found! Exiting!!\r\n");
                    Environment.Exit(0);
                }

                _logger.Warn($"\r\n'{file}' is in use. Rerouting...");

                var files = new List <string>();
                files.Add(file);

                var rawFiles = Helper.GetFiles(files);
                fileS = rawFiles.First().FileStream;
            }

            try
            {
                if (_fluentCommandLineParser.Object.Dedupe)
                {
                    var sha = Helper.GetSha1FromStream(fileS, 0);
                    if (_seenHashes.Contains(sha))
                    {
                        _logger.Debug($"Skipping '{file}' as a file with SHA-1 '{sha}' has already been processed");
                        return;
                    }

                    _seenHashes.Add(sha);
                }
                var evt = new EventLog(fileS);

                var seenRecords = 0;

                foreach (var eventRecord in evt.GetEventRecords())
                {
                    if (_includeIds.Count > 0)
                    {
                        if (_includeIds.Contains(eventRecord.EventId) == false)
                        {
                            //it is NOT in the list, so skip
                            _droppedEvents += 1;
                            continue;
                        }
                    }
                    else if (_excludeIds.Count > 0)
                    {
                        if (_excludeIds.Contains(eventRecord.EventId))
                        {
                            //it IS in the list, so skip
                            _droppedEvents += 1;
                            continue;
                        }
                    }

                    if (_startDate.HasValue)
                    {
                        if (eventRecord.TimeCreated < _startDate.Value)
                        {
                            //too old
                            _logger.Debug($"Dropping record Id '{eventRecord.EventRecordId}' with timestamp '{eventRecord.TimeCreated.ToUniversalTime().ToString(_fluentCommandLineParser.Object.DateTimeFormat)}' as its too old.");
                            _droppedEvents += 1;
                            continue;
                        }
                    }

                    if (_endDate.HasValue)
                    {
                        if (eventRecord.TimeCreated > _endDate.Value)
                        {
                            //too new
                            _logger.Debug($"Dropping record Id '{eventRecord.EventRecordId}' with timestamp '{eventRecord.TimeCreated.ToUniversalTime().ToString(_fluentCommandLineParser.Object.DateTimeFormat)}' as its too new.");
                            _droppedEvents += 1;
                            continue;
                        }
                    }

                    if (file.StartsWith(VssDir))
                    {
                        eventRecord.SourceFile = $"VSS{file.Replace($"{VssDir}\\", "")}";
                    }
                    else
                    {
                        eventRecord.SourceFile = file;
                    }

                    try
                    {
                        if (_fluentCommandLineParser.Object.PayloadAsJson)
                        {
                            var xdo = new XmlDocument();
                            xdo.LoadXml(eventRecord.Payload);

                            var payOut = JsonConvert.SerializeXmlNode(xdo);
                            eventRecord.Payload = payOut;
                        }

                        _csvWriter?.WriteRecord(eventRecord);
                        _csvWriter?.NextRecord();

                        var xml = string.Empty;
                        if (_swXml != null)
                        {
                            xml = eventRecord.ConvertPayloadToXml();
                            _swXml.WriteLine(xml);
                        }

                        if (_swJson != null)
                        {
                            var jsOut = eventRecord.ToJson();
                            if (_fluentCommandLineParser.Object.FullJson)
                            {
                                if (xml.IsNullOrEmpty())
                                {
                                    xml = eventRecord.ConvertPayloadToXml();
                                }

                                jsOut = GetPayloadAsJson(xml);
                            }

                            _swJson.WriteLine(jsOut);
                        }

                        seenRecords += 1;
                    }
                    catch (Exception e)
                    {
                        _logger.Error($"Error processing record #{eventRecord.RecordNumber}: {e.Message}");
                        evt.ErrorRecords.Add(21, e.Message);
                    }
                }

                if (evt.ErrorRecords.Count > 0)
                {
                    var fn = file;
                    if (file.StartsWith(VssDir))
                    {
                        fn = $"VSS{file.Replace($"{VssDir}\\", "")}";
                    }

                    _errorFiles.Add(fn, evt.ErrorRecords.Count);
                }

                _fileCount += 1;

                _logger.Info("");
                _logger.Fatal("Event log details");
                _logger.Info(evt);

                _logger.Info($"Records included: {seenRecords:N0} Errors: {evt.ErrorRecords.Count:N0} Events dropped: {_droppedEvents:N0}");

                if (evt.ErrorRecords.Count > 0)
                {
                    _logger.Warn("\r\nErrors");
                    foreach (var evtErrorRecord in evt.ErrorRecords)
                    {
                        _logger.Info($"Record #{evtErrorRecord.Key}: Error: {evtErrorRecord.Value}");
                    }
                }

                if (_fluentCommandLineParser.Object.Metrics && evt.EventIdMetrics.Count > 0)
                {
                    _logger.Fatal("\r\nMetrics (including dropped events)");
                    _logger.Warn("Event Id\tCount");
                    foreach (var esEventIdMetric in evt.EventIdMetrics.OrderBy(t => t.Key))
                    {
                        if (_includeIds.Count > 0)
                        {
                            if (_includeIds.Contains((int)esEventIdMetric.Key) == false)
                            {
                                //it is NOT in the list, so skip
                                continue;
                            }
                        }
                        else if (_excludeIds.Count > 0)
                        {
                            if (_excludeIds.Contains((int)esEventIdMetric.Key))
                            {
                                //it IS in the list, so skip
                                continue;
                            }
                        }

                        _logger.Info($"{esEventIdMetric.Key}\t\t{esEventIdMetric.Value:N0}");
                    }
                }
            }
            catch (Exception e)
            {
                var fn = file;
                if (file.StartsWith(VssDir))
                {
                    fn = $"VSS{file.Replace($"{VssDir}\\", "")}";
                }

                if (e.Message.Contains("Invalid signature! Expected 'ElfFile"))
                {
                    _logger.Info($"'{fn}' is not an evtx file! Message: {e.Message} Skipping...");
                }
                else
                {
                    _logger.Error($"Error processing '{fn}'! Message: {e.Message}");
                }
            }

            fileS?.Close();
        }
Exemple #3
0
        private static void Main(string[] args)
        {
            ExceptionlessClient.Default.Startup("tYeWS6A5K5uItgpB44dnNy2qSb2xJxiQWRRGWebq");

            SetupNLog();

            _logger = LogManager.GetLogger("EvtxECmd");

            _fluentCommandLineParser = new FluentCommandLineParser <ApplicationArguments>
            {
                IsCaseSensitive = false
            };

            _fluentCommandLineParser.Setup(arg => arg.File)
            .As('f')
            .WithDescription("File to process. This or -d is required\r\n");
            _fluentCommandLineParser.Setup(arg => arg.Directory)
            .As('d')
            .WithDescription("Directory to process that contains evtx files. This or -f is required");

            _fluentCommandLineParser.Setup(arg => arg.CsvDirectory)
            .As("csv")
            .WithDescription(
                "Directory to save CSV formatted results to.");     // This, --json, or --xml required

            _fluentCommandLineParser.Setup(arg => arg.CsvName)
            .As("csvf")
            .WithDescription(
                "File name to save CSV formatted results to. When present, overrides default name");

            _fluentCommandLineParser.Setup(arg => arg.JsonDirectory)
            .As("json")
            .WithDescription(
                "Directory to save JSON formatted results to.");     // This, --csv, or --xml required
            _fluentCommandLineParser.Setup(arg => arg.JsonName)
            .As("jsonf")
            .WithDescription(
                "File name to save JSON formatted results to. When present, overrides default name");

            _fluentCommandLineParser.Setup(arg => arg.XmlDirectory)
            .As("xml")
            .WithDescription(
                "Directory to save XML formatted results to.");     // This, --csv, or --json required

            _fluentCommandLineParser.Setup(arg => arg.XmlName)
            .As("xmlf")
            .WithDescription(
                "File name to save XML formatted results to. When present, overrides default name\r\n");

            _fluentCommandLineParser.Setup(arg => arg.DateTimeFormat)
            .As("dt")
            .WithDescription(
                "The custom date/time format to use when displaying time stamps. Default is: yyyy-MM-dd HH:mm:ss.fffffff")
            .SetDefault("yyyy-MM-dd HH:mm:ss.fffffff");

            _fluentCommandLineParser.Setup(arg => arg.IncludeIds)
            .As("inc")
            .WithDescription(
                "List of event IDs to process. All others are ignored. Overrides --exc Format is 4624,4625,5410")
            .SetDefault(string.Empty);

            _fluentCommandLineParser.Setup(arg => arg.ExcludeIds)
            .As("exc")
            .WithDescription(
                "List of event IDs to IGNORE. All others are included. Format is 4624,4625,5410")
            .SetDefault(string.Empty);

            _fluentCommandLineParser.Setup(arg => arg.FullJson)
            .As("fj")
            .WithDescription(
                "When true, export all available data when using --json. Default is FALSE.")
            .SetDefault(false);

            _fluentCommandLineParser.Setup(arg => arg.Metrics)
            .As("met")
            .WithDescription(
                "When true, show metrics about processed event log. Default is TRUE.\r\n")
            .SetDefault(true);

            _fluentCommandLineParser.Setup(arg => arg.MapsDirectory)
            .As("maps")
            .WithDescription(
                "The path where event maps are located. Defaults to 'Maps' folder where program was executed\r\n  ")
            .SetDefault(Path.Combine(BaseDirectory, "Maps"));

            _fluentCommandLineParser.Setup(arg => arg.Debug)
            .As("debug")
            .WithDescription("Show debug information during processing").SetDefault(false);

            _fluentCommandLineParser.Setup(arg => arg.Trace)
            .As("trace")
            .WithDescription("Show trace information during processing\r\n").SetDefault(false);

            var header =
                $"EvtxECmd version {Assembly.GetExecutingAssembly().GetName().Version}" +
                "\r\n\r\nAuthor: Eric Zimmerman ([email protected])" +
                "\r\nhttps://github.com/EricZimmerman/evtx";

            var footer =
                @"Examples: EvtxECmd.exe -f ""C:\Temp\Application.evtx"" --csv ""c:\temp\out"" --csvf MyOutputFile.csv" +
                "\r\n\t " +
                @" EvtxECmd.exe -f ""C:\Temp\Application.evtx"" --csv ""c:\temp\out""" + "\r\n\t " +
                @" EvtxECmd.exe -f ""C:\Temp\Application.evtx"" --json ""c:\temp\jsonout""" + "\r\n\t " +
                "\r\n\t" +
                "  Short options (single letter) are prefixed with a single dash. Long commands are prefixed with two dashes\r\n";

            _fluentCommandLineParser.SetupHelp("?", "help")
            .WithHeader(header)
            .Callback(text => _logger.Info(text + "\r\n" + footer));

            var result = _fluentCommandLineParser.Parse(args);

            if (result.HelpCalled)
            {
                return;
            }

            if (result.HasErrors)
            {
                _logger.Error("");
                _logger.Error(result.ErrorText);

                _fluentCommandLineParser.HelpOption.ShowHelp(_fluentCommandLineParser.Options);

                return;
            }

            if (_fluentCommandLineParser.Object.File.IsNullOrEmpty() &&
                _fluentCommandLineParser.Object.Directory.IsNullOrEmpty())
            {
                _fluentCommandLineParser.HelpOption.ShowHelp(_fluentCommandLineParser.Options);

                _logger.Warn("-f or -d is required. Exiting");
                return;
            }

            _logger.Info(header);
            _logger.Info("");
            _logger.Info($"Command line: {string.Join(" ", Environment.GetCommandLineArgs().Skip(1))}\r\n");

            if (IsAdministrator() == false)
            {
                _logger.Fatal("Warning: Administrator privileges not found!\r\n");
            }

            if (_fluentCommandLineParser.Object.Debug)
            {
                LogManager.Configuration.LoggingRules.First().EnableLoggingForLevel(LogLevel.Debug);
            }

            if (_fluentCommandLineParser.Object.Trace)
            {
                LogManager.Configuration.LoggingRules.First().EnableLoggingForLevel(LogLevel.Trace);
            }

            LogManager.ReconfigExistingLoggers();

            var sw = new Stopwatch();

            sw.Start();

            var ts = DateTimeOffset.UtcNow;

            _errorFiles = new Dictionary <string, int>();

            if (_fluentCommandLineParser.Object.JsonDirectory.IsNullOrEmpty() == false)
            {
                if (Directory.Exists(_fluentCommandLineParser.Object.JsonDirectory) == false)
                {
                    _logger.Warn(
                        $"Path to '{_fluentCommandLineParser.Object.JsonDirectory}' doesn't exist. Creating...");

                    try
                    {
                        Directory.CreateDirectory(_fluentCommandLineParser.Object.JsonDirectory);
                    }
                    catch (Exception)
                    {
                        _logger.Fatal(
                            $"Unable to create directory '{_fluentCommandLineParser.Object.JsonDirectory}'. Does a file with the same name exist? Exiting");
                        return;
                    }
                }

                var outName = $"{ts:yyyyMMddHHmmss}_EvtxECmd_Output.json";

                if (_fluentCommandLineParser.Object.JsonName.IsNullOrEmpty() == false)
                {
                    outName = Path.GetFileName(_fluentCommandLineParser.Object.JsonName);
                }

                var outFile = Path.Combine(_fluentCommandLineParser.Object.JsonDirectory, outName);

                _logger.Warn($"json output will be saved to '{outFile}'\r\n");



                try
                {
                    _swJson = new StreamWriter(outFile, false, Encoding.UTF8);
                }
                catch (Exception)
                {
                    _logger.Error($"Unable to open '{outFile}'! Is it in use? Exiting!\r\n");
                    Environment.Exit(0);
                }
            }

            if (_fluentCommandLineParser.Object.XmlDirectory.IsNullOrEmpty() == false)
            {
                if (Directory.Exists(_fluentCommandLineParser.Object.XmlDirectory) == false)
                {
                    _logger.Warn(
                        $"Path to '{_fluentCommandLineParser.Object.XmlDirectory}' doesn't exist. Creating...");

                    try
                    {
                        Directory.CreateDirectory(_fluentCommandLineParser.Object.XmlDirectory);
                    }
                    catch (Exception)
                    {
                        _logger.Fatal(
                            $"Unable to create directory '{_fluentCommandLineParser.Object.XmlDirectory}'. Does a file with the same name exist? Exiting");
                        return;
                    }
                }

                var outName = $"{ts:yyyyMMddHHmmss}_EvtxECmd_Output.xml";

                if (_fluentCommandLineParser.Object.XmlName.IsNullOrEmpty() == false)
                {
                    outName = Path.GetFileName(_fluentCommandLineParser.Object.XmlName);
                }

                var outFile = Path.Combine(_fluentCommandLineParser.Object.XmlDirectory, outName);

                _logger.Warn($"XML output will be saved to '{outFile}'\r\n");

                try
                {
                    _swXml = new StreamWriter(outFile, false, Encoding.UTF8);
                }
                catch (Exception)
                {
                    _logger.Error($"Unable to open '{outFile}'! Is it in use? Exiting!\r\n");
                    Environment.Exit(0);
                }
            }

            if (_fluentCommandLineParser.Object.CsvDirectory.IsNullOrEmpty() == false)
            {
                if (Directory.Exists(_fluentCommandLineParser.Object.CsvDirectory) == false)
                {
                    _logger.Warn(
                        $"Path to '{_fluentCommandLineParser.Object.CsvDirectory}' doesn't exist. Creating...");

                    try
                    {
                        Directory.CreateDirectory(_fluentCommandLineParser.Object.CsvDirectory);
                    }
                    catch (Exception)
                    {
                        _logger.Fatal(
                            $"Unable to create directory '{_fluentCommandLineParser.Object.CsvDirectory}'. Does a file with the same name exist? Exiting");
                        return;
                    }
                }

                var outName = $"{ts:yyyyMMddHHmmss}_EvtxECmd_Output.csv";

                if (_fluentCommandLineParser.Object.CsvName.IsNullOrEmpty() == false)
                {
                    outName = Path.GetFileName(_fluentCommandLineParser.Object.CsvName);
                }

                var outFile = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outName);

                _logger.Warn($"CSV output will be saved to '{outFile}'\r\n");

                try
                {
                    _swCsv = new StreamWriter(outFile, false, Encoding.UTF8);

                    _csvWriter = new CsvWriter(_swCsv);
                }
                catch (Exception)
                {
                    _logger.Error($"Unable to open '{outFile}'! Is it in use? Exiting!\r\n");
                    Environment.Exit(0);
                }

                var foo = _csvWriter.Configuration.AutoMap <EventRecord>();

                foo.Map(t => t.PayloadXml).Ignore();
                foo.Map(t => t.RecordPosition).Ignore();
                foo.Map(t => t.Size).Ignore();
                foo.Map(t => t.Timestamp).Ignore();

                foo.Map(t => t.RecordNumber).Index(0);
                foo.Map(t => t.TimeCreated).Index(1);
                foo.Map(t => t.TimeCreated).ConvertUsing(t =>
                                                         $"{t.TimeCreated.ToString(_fluentCommandLineParser.Object.DateTimeFormat)}");
                foo.Map(t => t.EventId).Index(2);
                foo.Map(t => t.Level).Index(3);
                foo.Map(t => t.Provider).Index(4);
                foo.Map(t => t.Channel).Index(5);
                foo.Map(t => t.ProcessId).Index(6);
                foo.Map(t => t.ThreadId).Index(7);
                foo.Map(t => t.Computer).Index(8);
                foo.Map(t => t.UserId).Index(9);
                foo.Map(t => t.MapDescription).Index(10);
                foo.Map(t => t.UserName).Index(11);
                foo.Map(t => t.RemoteHost).Index(12);
                foo.Map(t => t.PayloadData1).Index(13);
                foo.Map(t => t.PayloadData2).Index(14);
                foo.Map(t => t.PayloadData3).Index(15);
                foo.Map(t => t.PayloadData4).Index(16);
                foo.Map(t => t.PayloadData5).Index(17);
                foo.Map(t => t.PayloadData6).Index(18);
                foo.Map(t => t.ExecutableInfo).Index(19);
                foo.Map(t => t.SourceFile).Index(20);

                _csvWriter.Configuration.RegisterClassMap(foo);
                _csvWriter.WriteHeader <EventRecord>();
                _csvWriter.NextRecord();
            }

            if (Directory.Exists(_fluentCommandLineParser.Object.MapsDirectory) == false)
            {
                _logger.Warn(
                    $"Maps directory '{_fluentCommandLineParser.Object.MapsDirectory}' does not exist! Event ID maps will not be loaded!!");
            }
            else
            {
                _logger.Debug($"Loading maps from '{Path.GetFullPath(_fluentCommandLineParser.Object.MapsDirectory)}'");
                var errors = EventLog.LoadMaps(Path.GetFullPath(_fluentCommandLineParser.Object.MapsDirectory));


                if (errors)
                {
                    return;
                }

                _logger.Info($"Maps loaded: {EventLog.EventLogMaps.Count:N0}");
            }

            _includeIds = new HashSet <int>();
            _excludeIds = new HashSet <int>();

            if (_fluentCommandLineParser.Object.ExcludeIds.IsNullOrEmpty() == false)
            {
                var excSegs = _fluentCommandLineParser.Object.ExcludeIds.Split(',');

                foreach (var incSeg in excSegs)
                {
                    if (int.TryParse(incSeg, out var goodId))
                    {
                        _excludeIds.Add(goodId);
                    }
                }
            }

            if (_fluentCommandLineParser.Object.IncludeIds.IsNullOrEmpty() == false)
            {
                _excludeIds.Clear();
                var incSegs = _fluentCommandLineParser.Object.IncludeIds.Split(',');

                foreach (var incSeg in incSegs)
                {
                    if (int.TryParse(incSeg, out var goodId))
                    {
                        _includeIds.Add(goodId);
                    }
                }
            }


            if (_fluentCommandLineParser.Object.File.IsNullOrEmpty() == false)
            {
                if (File.Exists(_fluentCommandLineParser.Object.File) == false)
                {
                    _logger.Warn($"'{_fluentCommandLineParser.Object.File}' does not exist! Exiting");
                    return;
                }

                ProcessFile(_fluentCommandLineParser.Object.File);
            }
            else
            {
                _logger.Info($"Looking for event log files in '{_fluentCommandLineParser.Object.Directory}'");
                _logger.Info("");

                var f = new DirectoryEnumerationFilters();
                f.InclusionFilter = fsei => fsei.Extension.ToUpperInvariant() == ".EVTX";

                f.RecursionFilter = entryInfo => !entryInfo.IsMountPoint && !entryInfo.IsSymbolicLink;

                f.ErrorFilter = (errorCode, errorMessage, pathProcessed) => true;

                var dirEnumOptions =
                    DirectoryEnumerationOptions.Files | DirectoryEnumerationOptions.Recursive |
                    DirectoryEnumerationOptions.SkipReparsePoints | DirectoryEnumerationOptions.ContinueOnException |
                    DirectoryEnumerationOptions.BasicSearch;

                var files2 =
                    Directory.EnumerateFileSystemEntries(Path.GetFullPath(_fluentCommandLineParser.Object.Directory), dirEnumOptions, f);

                foreach (var file in files2)
                {
                    ProcessFile(file);
                }
            }

            _swCsv?.Flush();
            _swCsv?.Close();

            _swJson?.Flush();
            _swJson?.Close();

            _swXml?.Flush();
            _swXml?.Close();

            sw.Stop();
            _logger.Info("");

            var suff = string.Empty;

            if (_fileCount != 1)
            {
                suff = "s";
            }

            _logger.Error(
                $"Processed {_fileCount:N0} file{suff} in {sw.Elapsed.TotalSeconds:N4} seconds\r\n");

            if (_errorFiles.Count > 0)
            {
                _logger.Info("");
                _logger.Error("Files with errors");
                foreach (var errorFile in _errorFiles)
                {
                    _logger.Info($"'{errorFile.Key}' error count: {errorFile.Value:N0}");
                }

                _logger.Info("");
            }
        }
Exemple #4
0
        //private static readonly string VssDir = @"C:\____vssMount";


        private static void Main(string[] args)
        {
            ExceptionlessClient.Default.Startup("tYeWS6A5K5uItgpB44dnNy2qSb2xJxiQWRRGWebq");

            SetupNLog();

            _logger = LogManager.GetLogger("EvtxECmd");

            _fluentCommandLineParser = new FluentCommandLineParser <ApplicationArguments>
            {
                IsCaseSensitive = false
            };

            _fluentCommandLineParser.Setup(arg => arg.File)
            .As('f')
            .WithDescription("File to process. This or -d is required\r\n");
            _fluentCommandLineParser.Setup(arg => arg.Directory)
            .As('d')
            .WithDescription("Directory to process that contains evtx files. This or -f is required");

            _fluentCommandLineParser.Setup(arg => arg.CsvDirectory)
            .As("csv")
            .WithDescription(
                "Directory to save CSV formatted results to.");     // This, --json, or --xml required

            _fluentCommandLineParser.Setup(arg => arg.CsvName)
            .As("csvf")
            .WithDescription(
                "File name to save CSV formatted results to. When present, overrides default name");

            _fluentCommandLineParser.Setup(arg => arg.JsonDirectory)
            .As("json")
            .WithDescription(
                "Directory to save JSON formatted results to.");     // This, --csv, or --xml required
            _fluentCommandLineParser.Setup(arg => arg.JsonName)
            .As("jsonf")
            .WithDescription(
                "File name to save JSON formatted results to. When present, overrides default name");

            _fluentCommandLineParser.Setup(arg => arg.XmlDirectory)
            .As("xml")
            .WithDescription(
                "Directory to save XML formatted results to.");     // This, --csv, or --json required

            _fluentCommandLineParser.Setup(arg => arg.XmlName)
            .As("xmlf")
            .WithDescription(
                "File name to save XML formatted results to. When present, overrides default name\r\n");

            _fluentCommandLineParser.Setup(arg => arg.DateTimeFormat)
            .As("dt")
            .WithDescription(
                "The custom date/time format to use when displaying time stamps. Default is: yyyy-MM-dd HH:mm:ss.fffffff")
            .SetDefault("yyyy-MM-dd HH:mm:ss.fffffff");

            _fluentCommandLineParser.Setup(arg => arg.IncludeIds)
            .As("inc")
            .WithDescription(
                "List of event IDs to process. All others are ignored. Overrides --exc Format is 4624,4625,5410")
            .SetDefault(string.Empty);

            _fluentCommandLineParser.Setup(arg => arg.ExcludeIds)
            .As("exc")
            .WithDescription(
                "List of event IDs to IGNORE. All others are included. Format is 4624,4625,5410")
            .SetDefault(string.Empty);

            _fluentCommandLineParser.Setup(arg => arg.StartDate)
            .As("sd")
            .WithDescription(
                "Start date for including events (UTC). Anything OLDER than this is dropped. Format should match --dt")
            .SetDefault(string.Empty);

            _fluentCommandLineParser.Setup(arg => arg.EndDate)
            .As("ed")
            .WithDescription(
                "End date for including events (UTC). Anything NEWER than this is dropped. Format should match --dt")
            .SetDefault(string.Empty);

            _fluentCommandLineParser.Setup(arg => arg.FullJson)
            .As("fj")
            .WithDescription(
                "When true, export all available data when using --json. Default is FALSE.")
            .SetDefault(false);
            _fluentCommandLineParser.Setup(arg => arg.PayloadAsJson)
            .As("pj")
            .WithDescription(
                "When true, include event *payload* as json. Default is TRUE.")
            .SetDefault(true);

            _fluentCommandLineParser.Setup(arg => arg.TimeDiscrepancyThreshold)
            .As("tdt")
            .WithDescription(
                "The number of seconds to use for time discrepancy detection. Default is 1 second")
            .SetDefault(1);

            _fluentCommandLineParser.Setup(arg => arg.Metrics)
            .As("met")
            .WithDescription(
                "When true, show metrics about processed event log. Default is TRUE.\r\n")
            .SetDefault(true);

            _fluentCommandLineParser.Setup(arg => arg.MapsDirectory)
            .As("maps")
            .WithDescription(
                "The path where event maps are located. Defaults to 'Maps' folder where program was executed\r\n  ")
            .SetDefault(Path.Combine(BaseDirectory, "Maps"));

            /*_fluentCommandLineParser.Setup(arg => arg.Vss)
             *  .As("vss")
             *  .WithDescription(
             *      "Process all Volume Shadow Copies that exist on drive specified by -f or -d . Default is FALSE")
             *  .SetDefault(false);*/
            _fluentCommandLineParser.Setup(arg => arg.Dedupe)
            .As("dedupe")
            .WithDescription(
                "Deduplicate -f or -d & VSCs based on SHA-1. First file found wins. Default is TRUE\r\n")
            .SetDefault(true);

            _fluentCommandLineParser.Setup(arg => arg.Sync)
            .As("sync")
            .WithDescription(
                "If true, the latest maps from https://github.com/EricZimmerman/evtx/tree/master/evtx/Maps are downloaded and local maps updated. Default is FALSE\r\n")
            .SetDefault(false);

            _fluentCommandLineParser.Setup(arg => arg.Debug)
            .As("debug")
            .WithDescription("Show debug information during processing").SetDefault(false);

            _fluentCommandLineParser.Setup(arg => arg.Trace)
            .As("trace")
            .WithDescription("Show trace information during processing\r\n").SetDefault(false);

            var header =
                $"EvtxECmd version {Assembly.GetExecutingAssembly().GetName().Version}" +
                "\n\nAuthor: Eric Zimmerman ([email protected])" +
                "\nhttps://github.com/EricZimmerman/evtx" +
                "\nLinux Port : Scott Dermott ([email protected])" +
                "\nhttps://github.com/ScottDermott/evtx";

            var footer =
                @"Examples: EvtxECmd -f ""/Temp/Application.evtx"" --csv ""/temp/out"" --csvf MyOutputFile.csv" +
                "\r\n\t " +
                @" EvtxECmd -f ""/Temp/Application.evtx"" --csv ""/temp/out""" + "\r\n\t " +
                @" EvtxECmd -f ""/Temp/Application.evtx"" --json ""/temp/jsonout""" + "\r\n\t " +
                "\r\n\t" +
                "  Short options (single letter) are prefixed with a single dash. Long commands are prefixed with two dashes\r\n";

            _fluentCommandLineParser.SetupHelp("?", "help")
            .WithHeader(header)
            .Callback(text => _logger.Info(text + "\r\n" + footer));

            var result = _fluentCommandLineParser.Parse(args);

            if (result.HelpCalled)
            {
                return;
            }

            if (result.HasErrors)
            {
                _logger.Error("");
                _logger.Error(result.ErrorText);

                _fluentCommandLineParser.HelpOption.ShowHelp(_fluentCommandLineParser.Options);

                return;
            }

            if (_fluentCommandLineParser.Object.Sync)
            {
                try
                {
                    _logger.Info(header);
                    UpdateFromRepo();
                }
                catch (Exception e)
                {
                    _logger.Error(e, $"There was an error checking for updates: {e.Message}");
                }

                Environment.Exit(0);
            }

            if (_fluentCommandLineParser.Object.File.IsNullOrEmpty() &&
                _fluentCommandLineParser.Object.Directory.IsNullOrEmpty())
            {
                _fluentCommandLineParser.HelpOption.ShowHelp(_fluentCommandLineParser.Options);

                _logger.Warn("-f or -d is required. Exiting");
                return;
            }

            _logger.Info(header);
            _logger.Info("");
            _logger.Info($"Command line: {string.Join(" ", Environment.GetCommandLineArgs().Skip(1))}\r\n");



/*            if (IsAdministrator() == false)
 *          {
 *              _logger.Fatal("Warning: Administrator privileges not found!\r\n");
 *          }*/

            if (_fluentCommandLineParser.Object.Debug)
            {
                LogManager.Configuration.LoggingRules.First().EnableLoggingForLevel(LogLevel.Debug);
            }

            if (_fluentCommandLineParser.Object.Trace)
            {
                LogManager.Configuration.LoggingRules.First().EnableLoggingForLevel(LogLevel.Trace);
            }

            LogManager.ReconfigExistingLoggers();

            /* if (_fluentCommandLineParser.Object.Vss & (IsAdministrator() == false))
             * {
             *   _logger.Error("--vss is present, but administrator rights not found. Exiting\r\n");
             *   return;
             * }*/

            var sw = new Stopwatch();

            sw.Start();

            var ts = DateTimeOffset.UtcNow;

            _errorFiles = new Dictionary <string, int>();

            if (_fluentCommandLineParser.Object.JsonDirectory.IsNullOrEmpty() == false)
            {
                if (Directory.Exists(_fluentCommandLineParser.Object.JsonDirectory) == false)
                {
                    _logger.Warn(
                        $"Path to '{_fluentCommandLineParser.Object.JsonDirectory}' doesn't exist. Creating...");

                    try
                    {
                        Directory.CreateDirectory(_fluentCommandLineParser.Object.JsonDirectory);
                    }
                    catch (Exception)
                    {
                        _logger.Fatal(
                            $"Unable to create directory '{_fluentCommandLineParser.Object.JsonDirectory}'. Does a file with the same name exist? Exiting");
                        return;
                    }
                }

                var outName = $"{ts:yyyyMMddHHmmss}_EvtxECmd_Output.json";

                if (_fluentCommandLineParser.Object.JsonName.IsNullOrEmpty() == false)
                {
                    outName = Path.GetFileName(_fluentCommandLineParser.Object.JsonName);
                }

                var outFile = Path.Combine(_fluentCommandLineParser.Object.JsonDirectory, outName);

                _logger.Warn($"json output will be saved to '{outFile}'\r\n");

                try
                {
                    _swJson = new StreamWriter(outFile, false, Encoding.UTF8);
                }
                catch (Exception)
                {
                    _logger.Error($"Unable to open '{outFile}'! Is it in use? Exiting!\r\n");
                    Environment.Exit(0);
                }

                JsConfig.DateHandler = DateHandler.ISO8601;
            }

            if (_fluentCommandLineParser.Object.XmlDirectory.IsNullOrEmpty() == false)
            {
                if (Directory.Exists(_fluentCommandLineParser.Object.XmlDirectory) == false)
                {
                    _logger.Warn(
                        $"Path to '{_fluentCommandLineParser.Object.XmlDirectory}' doesn't exist. Creating...");

                    try
                    {
                        Directory.CreateDirectory(_fluentCommandLineParser.Object.XmlDirectory);
                    }
                    catch (Exception)
                    {
                        _logger.Fatal(
                            $"Unable to create directory '{_fluentCommandLineParser.Object.XmlDirectory}'. Does a file with the same name exist? Exiting");
                        return;
                    }
                }

                var outName = $"{ts:yyyyMMddHHmmss}_EvtxECmd_Output.xml";

                if (_fluentCommandLineParser.Object.XmlName.IsNullOrEmpty() == false)
                {
                    outName = Path.GetFileName(_fluentCommandLineParser.Object.XmlName);
                }

                var outFile = Path.Combine(_fluentCommandLineParser.Object.XmlDirectory, outName);

                _logger.Warn($"XML output will be saved to '{outFile}'\r\n");

                try
                {
                    _swXml = new StreamWriter(outFile, false, Encoding.UTF8);
                }
                catch (Exception)
                {
                    _logger.Error($"Unable to open '{outFile}'! Is it in use? Exiting!\r\n");
                    Environment.Exit(0);
                }
            }

            if (_fluentCommandLineParser.Object.StartDate.IsNullOrEmpty() == false)
            {
                if (DateTimeOffset.TryParse(_fluentCommandLineParser.Object.StartDate, null, DateTimeStyles.AssumeUniversal, out var dt))
                {
                    _startDate = dt;
                    _logger.Info($"Setting Start date to '{_startDate.Value.ToUniversalTime().ToString(_fluentCommandLineParser.Object.DateTimeFormat)}'");
                }
                else
                {
                    _logger.Warn($"Could not parse '{_fluentCommandLineParser.Object.StartDate}' to a valud datetime! Events will not be filtered by Start date!");
                }
            }
            if (_fluentCommandLineParser.Object.EndDate.IsNullOrEmpty() == false)
            {
                if (DateTimeOffset.TryParse(_fluentCommandLineParser.Object.EndDate, null, DateTimeStyles.AssumeUniversal, out var dt))
                {
                    _endDate = dt;
                    _logger.Info($"Setting End date to '{_endDate.Value.ToUniversalTime().ToString(_fluentCommandLineParser.Object.DateTimeFormat)}'");
                }
                else
                {
                    _logger.Warn($"Could not parse '{_fluentCommandLineParser.Object.EndDate}' to a valud datetime! Events will not be filtered by End date!");
                }
            }

            if (_startDate.HasValue || _endDate.HasValue)
            {
                _logger.Info("");
            }


            if (_fluentCommandLineParser.Object.CsvDirectory.IsNullOrEmpty() == false)
            {
                if (Directory.Exists(_fluentCommandLineParser.Object.CsvDirectory) == false)
                {
                    _logger.Warn(
                        $"Path to '{_fluentCommandLineParser.Object.CsvDirectory}' doesn't exist. Creating...");

                    try
                    {
                        Directory.CreateDirectory(_fluentCommandLineParser.Object.CsvDirectory);
                    }
                    catch (Exception)
                    {
                        _logger.Fatal(
                            $"Unable to create directory '{_fluentCommandLineParser.Object.CsvDirectory}'. Does a file with the same name exist? Exiting");
                        return;
                    }
                }

                var outName = $"{ts:yyyyMMddHHmmss}_EvtxECmd_Output.csv";

                if (_fluentCommandLineParser.Object.CsvName.IsNullOrEmpty() == false)
                {
                    outName = Path.GetFileName(_fluentCommandLineParser.Object.CsvName);
                }

                var outFile = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outName);

                _logger.Warn($"CSV output will be saved to '{outFile}'\r\n");

                try
                {
                    _swCsv = new StreamWriter(outFile, false, Encoding.UTF8);

                    _csvWriter = new CsvWriter(_swCsv, CultureInfo.InvariantCulture);
                }
                catch (Exception)
                {
                    _logger.Error($"Unable to open '{outFile}'! Is it in use? Exiting!\r\n");
                    Environment.Exit(0);
                }

                var foo = _csvWriter.Configuration.AutoMap <EventRecord>();

                if (_fluentCommandLineParser.Object.PayloadAsJson == false)
                {
                    foo.Map(t => t.Payload).Ignore();
                }
                else
                {
                    foo.Map(t => t.Payload).Index(22);
                }

                foo.Map(t => t.RecordPosition).Ignore();
                foo.Map(t => t.Size).Ignore();
                foo.Map(t => t.Timestamp).Ignore();

                foo.Map(t => t.RecordNumber).Index(0);
                foo.Map(t => t.EventRecordId).Index(1);
                foo.Map(t => t.TimeCreated).Index(2);
                foo.Map(t => t.TimeCreated).ConvertUsing(t =>
                                                         $"{t.TimeCreated.ToString(_fluentCommandLineParser.Object.DateTimeFormat)}");
                foo.Map(t => t.EventId).Index(3);
                foo.Map(t => t.Level).Index(4);
                foo.Map(t => t.Provider).Index(5);
                foo.Map(t => t.Channel).Index(6);
                foo.Map(t => t.ProcessId).Index(7);
                foo.Map(t => t.ThreadId).Index(8);
                foo.Map(t => t.Computer).Index(9);
                foo.Map(t => t.UserId).Index(10);
                foo.Map(t => t.MapDescription).Index(11);
                foo.Map(t => t.UserName).Index(12);
                foo.Map(t => t.RemoteHost).Index(13);
                foo.Map(t => t.PayloadData1).Index(14);
                foo.Map(t => t.PayloadData2).Index(15);
                foo.Map(t => t.PayloadData3).Index(16);
                foo.Map(t => t.PayloadData4).Index(17);
                foo.Map(t => t.PayloadData5).Index(18);
                foo.Map(t => t.PayloadData6).Index(19);
                foo.Map(t => t.ExecutableInfo).Index(20);
                foo.Map(t => t.SourceFile).Index(21);

                _csvWriter.Configuration.RegisterClassMap(foo);
                _csvWriter.WriteHeader <EventRecord>();
                _csvWriter.NextRecord();
            }

            if (Directory.Exists(_fluentCommandLineParser.Object.MapsDirectory) == false)
            {
                _logger.Warn(
                    $"Maps directory '{_fluentCommandLineParser.Object.MapsDirectory}' does not exist! Event ID maps will not be loaded!!");
            }
            else
            {
                _logger.Info($"Loading maps from '{Path.GetFullPath(_fluentCommandLineParser.Object.MapsDirectory)}'");
                var errors = EventLog.LoadMaps(Path.GetFullPath(_fluentCommandLineParser.Object.MapsDirectory));

                if (errors)
                {
                    return;
                }

                _logger.Info($"Maps loaded: {EventLog.EventLogMaps.Count:N0}");
            }

            _includeIds = new HashSet <int>();
            _excludeIds = new HashSet <int>();

            if (_fluentCommandLineParser.Object.ExcludeIds.IsNullOrEmpty() == false)
            {
                var excSegs = _fluentCommandLineParser.Object.ExcludeIds.Split(',');

                foreach (var incSeg in excSegs)
                {
                    if (int.TryParse(incSeg, out var goodId))
                    {
                        _excludeIds.Add(goodId);
                    }
                }
            }

            if (_fluentCommandLineParser.Object.IncludeIds.IsNullOrEmpty() == false)
            {
                _excludeIds.Clear();
                var incSegs = _fluentCommandLineParser.Object.IncludeIds.Split(',');

                foreach (var incSeg in incSegs)
                {
                    if (int.TryParse(incSeg, out var goodId))
                    {
                        _includeIds.Add(goodId);
                    }
                }
            }

            /*if (_fluentCommandLineParser.Object.Vss)
             * {
             *  string driveLetter;
             *  if (_fluentCommandLineParser.Object.File.IsEmpty() == false)
             *  {
             *      driveLetter = Path.GetPathRoot(Path.GetFullPath(_fluentCommandLineParser.Object.File))
             *          .Substring(0, 1);
             *  }
             *  else
             *  {
             *      driveLetter = Path.GetPathRoot(Path.GetFullPath(_fluentCommandLineParser.Object.Directory))
             *          .Substring(0, 1);
             *  }
             *
             *
             *  Helper.MountVss(driveLetter,VssDir);
             *  Console.WriteLine();
             * }*/

            EventLog.TimeDiscrepancyThreshold = _fluentCommandLineParser.Object.TimeDiscrepancyThreshold;

            if (_fluentCommandLineParser.Object.File.IsNullOrEmpty() == false)
            {
                if (File.Exists(_fluentCommandLineParser.Object.File) == false)
                {
                    _logger.Warn($"'{_fluentCommandLineParser.Object.File}' does not exist! Exiting");
                    return;
                }

                if (_swXml == null && _swJson == null && _swCsv == null)
                {
                    //no need for maps
                    _logger.Debug("Clearing map collection since no output specified");
                    EventLog.EventLogMaps.Clear();
                }

                _fluentCommandLineParser.Object.Dedupe = false;

                ProcessFile(Path.GetFullPath(_fluentCommandLineParser.Object.File));

                /*if (_fluentCommandLineParser.Object.Vss)
                 * {
                 *  var vssDirs = Directory.GetDirectories(VssDir);
                 *
                 *  var root = Path.GetPathRoot(Path.GetFullPath(_fluentCommandLineParser.Object.File));
                 *  var stem = Path.GetFullPath(_fluentCommandLineParser.Object.File).Replace(root, "");
                 *
                 *  foreach (var vssDir in vssDirs)
                 *  {
                 *      var newPath = Path.Combine(vssDir, stem);
                 *      if (File.Exists(newPath))
                 *      {
                 *          ProcessFile(newPath);
                 *      }
                 *  }
                 * }*/
            }
            else
            {
                _logger.Info($"Looking for event log files in '{_fluentCommandLineParser.Object.Directory}'");
                _logger.Info("");

/*                var f = new DirectoryEnumerationFilters
 *              {
 *                  InclusionFilter = fsei => fsei.Extension.ToUpperInvariant() == ".EVTX",
 *                  RecursionFilter = entryInfo => !entryInfo.IsMountPoint && !entryInfo.IsSymbolicLink,
 *                  ErrorFilter = (errorCode, errorMessage, pathProcessed) => true
 *              };*/

/*                var dirEnumOptions =
 *                  DirectoryEnumerationOptions.Files | DirectoryEnumerationOptions.Recursive |
 *                  DirectoryEnumerationOptions.SkipReparsePoints | DirectoryEnumerationOptions.ContinueOnException |
 *                  DirectoryEnumerationOptions.BasicSearch;*/

                var files2 = Directory.EnumerateFileSystemEntries(Path.GetFullPath(_fluentCommandLineParser.Object.Directory), "*.evtx");

                if (_swXml == null && _swJson == null && _swCsv == null)
                {
                    //no need for maps
                    _logger.Debug("Clearing map collection since no output specified");
                    EventLog.EventLogMaps.Clear();
                }

                foreach (var file in files2)
                {
                    ProcessFile(file);
                }

                /*if (_fluentCommandLineParser.Object.Vss)
                 * {
                 *  var vssDirs = Directory.GetDirectories(VssDir);
                 *
                 *  Console.WriteLine();
                 *
                 *  foreach (var vssDir in vssDirs)
                 *  {
                 *      var root = Path.GetPathRoot(Path.GetFullPath(_fluentCommandLineParser.Object.Directory));
                 *      var stem = Path.GetFullPath(_fluentCommandLineParser.Object.Directory).Replace(root, "");
                 *
                 *      var target = Path.Combine(vssDir, stem);
                 *
                 *      _logger.Fatal($"\r\nSearching 'VSS{target.Replace($"{VssDir}\\","")}' for event logs...");
                 *
                 *      var vssFiles = Helper.GetFilesFromPath(target, true, "*.evtx");
                 *
                 *      foreach (var file in vssFiles)
                 *      {
                 *          ProcessFile(file);
                 *      }
                 *  }
                 *
                 * }*/
            }

            _swCsv?.Flush();
            _swCsv?.Close();

            _swJson?.Flush();
            _swJson?.Close();

            _swXml?.Flush();
            _swXml?.Close();

            sw.Stop();
            _logger.Info("");

            var suff = string.Empty;

            if (_fileCount != 1)
            {
                suff = "s";
            }

            _logger.Error(
                $"Processed {_fileCount:N0} file{suff} in {sw.Elapsed.TotalSeconds:N4} seconds\r\n");

            if (_errorFiles.Count > 0)
            {
                _logger.Info("");
                _logger.Error("Files with errors");
                foreach (var errorFile in _errorFiles)
                {
                    _logger.Info($"'{errorFile.Key}' error count: {errorFile.Value:N0}");
                }

                _logger.Info("");
            }

            /*if (_fluentCommandLineParser.Object.Vss)
             * {
             *  if (Directory.Exists(VssDir))
             *  {
             *      foreach (var directory in Directory.GetDirectories(VssDir))
             *      {
             *          Directory.Delete(directory);
             *      }
             *      Directory.Delete(VssDir,true);
             *  }
             * }*/
        }
Exemple #5
0
        private static void ProcessFile(string file)
        {
            if (File.Exists(file) == false)
            {
                _logger.Warn($"'{file}' does not exist! Skipping");
                return;
            }

            _logger.Warn($"\r\nProcessing '{file}'...");

            using (var fs = new FileStream(file, FileMode.Open))
            {
                try
                {
                    var evt = new EventLog(fs);

                    var seenRecords = 0;

                    foreach (var eventRecord in evt.GetEventRecords())
                    {
                        eventRecord.SourceFile = file;
                        try
                        {
                            if (_fluentCommandLineParser.Object.ShowXml)
                            {
                                _logger.Info(eventRecord.ConvertPayloadToXml());
                            }
                            _csvWriter?.WriteRecord(eventRecord);
                            _csvWriter?.NextRecord();

                            seenRecords += 1;
                        }
                        catch (Exception e)
                        {
                            _logger.Error($"Error processing record #{eventRecord.RecordNumber}: {e.Message}");
                        }
                    }

                    if (evt.ErrorRecords.Count > 0)
                    {
                        _errorFiles.Add(file, evt.ErrorRecords.Count);
                    }

                    _fileCount += 1;

                    _logger.Info("");
                    _logger.Fatal("Event log details");
                    _logger.Info(evt);

                    _logger.Info($"Records processed: {seenRecords:N0} Errors: {evt.ErrorRecords.Count:N0}");

                    if (evt.ErrorRecords.Count > 0)
                    {
                        _logger.Warn("\r\nErrors");
                    }

                    foreach (var evtErrorRecord in evt.ErrorRecords)
                    {
                        _logger.Info($"Record #{evtErrorRecord.Key}: Error: {evtErrorRecord.Value}");
                    }
                }
                catch (Exception e)
                {
                    if (e.Message.Contains("Invalid signature! Expected 'ElfFile"))
                    {
                        _logger.Info($"'{file}' is not an evtx file! Message: {e.Message} Skipping...");
                    }
                    else
                    {
                        _logger.Error($"Error processing '{file}'! Message: {e.Message}");
                    }
                }
            }
        }
Exemple #6
0
        private static void ProcessFile(string file)
        {
            if (File.Exists(file) == false)
            {
                _logger.Warn($"'{file}' does not exist! Skipping");
                return;
            }

            _logger.Warn($"\r\nProcessing '{file}'...");

            Stream fileS;

            try
            {
                fileS = new FileStream(file, FileMode.Open, FileAccess.Read);
            }
            catch (Exception)
            {
                //file is in use

                if (Helper.IsAdministrator() == false)
                {
                    _logger.Fatal("\r\nAdministrator privileges not found! Exiting!!\r\n");
                    Environment.Exit(0);
                }

                _logger.Warn($"\r\n'{file}' is in use. Rerouting...");

                var files = new List <string>();
                files.Add(file);

                var rawFiles = Helper.GetFiles(files);
                fileS = rawFiles.First().FileStream;
            }

            try
            {
                var evt = new EventLog(fileS);

                var seenRecords = 0;

                foreach (var eventRecord in evt.GetEventRecords())
                {
                    if (_includeIds.Count > 0)
                    {
                        if (_includeIds.Contains(eventRecord.EventId) == false)
                        {
                            //it is NOT in the list, so skip
                            continue;
                        }
                    }
                    else if (_excludeIds.Count > 0)
                    {
                        if (_excludeIds.Contains(eventRecord.EventId))
                        {
                            //it IS in the list, so skip
                            continue;
                        }
                    }

                    // If not between start and stop we do not print
                    if (_from.ToString() != "01/01/0001 00:00:00" && _to.ToString() != "01/01/0001 00:00:00")
                    {
                        if (eventRecord.TimeCreated.DateTime < _from || eventRecord.TimeCreated.DateTime > _to)
                        {
                            continue;
                        }
                    }

                    // If before start we do not print
                    if (_from.ToString() != "01/01/0001 00:00:00")
                    {
                        if (eventRecord.TimeCreated.DateTime < _from)
                        {
                            continue;
                        }
                    }

                    if (_to.ToString() != "01/01/0001 00:00:00")
                    {
                        if (eventRecord.TimeCreated.DateTime > _to)
                        {
                            continue;
                        }
                    }

                    eventRecord.SourceFile = file;
                    try
                    {
                        var xdo = new XmlDocument();
                        xdo.LoadXml(eventRecord.Payload);

                        var payOut = JsonConvert.SerializeXmlNode(xdo);
                        eventRecord.Payload = payOut.Replace("\"#text\":", "").Replace("\"@Name\":", "").Replace("\",\"", ": ").Replace("\"\"}", "}").Replace("{\"\"", "").Replace("\"},{\"", ", ").Replace("{\"EventData\":{\"Data\":[{\"", "").Replace("\"}]}}", "").Replace("\":\"", ": ").Replace("\"}}}", "").Replace("\":{\"", ": ").Replace("{\"", "");

                        _csvWriter?.WriteRecord(eventRecord);
                        _csvWriter?.NextRecord();

                        seenRecords += 1;
                    }
                    catch (Exception e)
                    {
                        _logger.Error($"Error processing record #{eventRecord.RecordNumber}: {e.Message}");
                    }
                }

                _csvWriter?.Flush();
                _swCsv?.Flush();

                if (evt.ErrorRecords.Count > 0)
                {
                    _errorFiles.Add(file, evt.ErrorRecords.Count);
                }

                _fileCount += 1;

                _logger.Info("");
                _logger.Fatal("Event log details");
                _logger.Info(evt);

                _logger.Info($"Records processed: {seenRecords:N0} Errors: {evt.ErrorRecords.Count:N0}");

                if (evt.ErrorRecords.Count > 0)
                {
                    _logger.Warn("\r\nErrors");
                    foreach (var evtErrorRecord in evt.ErrorRecords)
                    {
                        _logger.Info($"Record #{evtErrorRecord.Key}: Error: {evtErrorRecord.Value}");
                    }
                }

                if (_fluentCommandLineParser.Object.Metrics && evt.EventIdMetrics.Count > 0)
                {
                    _logger.Fatal("\r\nMetrics");
                    _logger.Warn("Event Id\tCount");
                    foreach (var esEventIdMetric in evt.EventIdMetrics.OrderBy(t => t.Key))
                    {
                        if (_includeIds.Count > 0)
                        {
                            if (_includeIds.Contains((int)esEventIdMetric.Key) == false)
                            {
                                //it is NOT in the list, so skip
                                continue;
                            }
                        }
                        else if (_excludeIds.Count > 0)
                        {
                            if (_excludeIds.Contains((int)esEventIdMetric.Key))
                            {
                                //it IS in the list, so skip
                                continue;
                            }
                        }

                        _logger.Info($"{esEventIdMetric.Key}\t\t{esEventIdMetric.Value:N0}");
                    }
                }
            }
            catch (Exception e)
            {
                if (e.Message.Contains("Invalid signature! Expected 'ElfFile"))
                {
                    _logger.Info($"'{file}' is not an evtx file! Message: {e.Message} Skipping...");
                }
                else
                {
                    _logger.Error($"Error processing '{file}'! Message: {e.Message}");
                }
            }

            fileS?.Close();
        }
Exemple #7
0
    private static void ProcessFile(string file, bool dedupe, bool fj, bool met)
    {
        if (File.Exists(file) == false)
        {
            Log.Warning("{File} does not exist! Skipping", file);
            return;
        }

        if (file.StartsWith(VssDir))
        {
            Console.WriteLine();
            Log.Information("Processing {Vss}", $"VSS{file.Replace($"{VssDir}\\", "")}");
        }
        else
        {
            Console.WriteLine();
            Log.Information("Processing {File}...", file);
        }

        Stream fileS;

        try
        {
            fileS = new FileStream(file, FileMode.Open, FileAccess.Read);
        }
        catch (Exception)
        {
            //file is in use

            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                Console.WriteLine();
                Log.Fatal("Raw disk reads not supported on non-Windows platforms! Exiting!!");
                Console.WriteLine();
                Environment.Exit(0);
            }

            if (Helper.IsAdministrator() == false)
            {
                Console.WriteLine();
                Log.Fatal("Administrator privileges not found! Exiting!!");
                Console.WriteLine();
                Environment.Exit(0);
            }

            if (file.StartsWith("\\\\"))
            {
                Log.Fatal($"Raw access across UNC shares is not supported! Run locally on the system or extract logs via other means and try again. Exiting");
                Environment.Exit(0);
            }

            Console.WriteLine();
            Log.Warning("{File} is in use. Rerouting...", file);

            var files = new List <string>
            {
                file
            };

            var rawFiles = Helper.GetRawFiles(files);
            fileS = rawFiles.First().FileStream;
        }

        try
        {
            if (dedupe)
            {
                var sha = Helper.GetSha1FromStream(fileS, 0);
                fileS.Seek(0, SeekOrigin.Begin);
                if (SeenHashes.Contains(sha))
                {
                    Log.Debug("Skipping {File} as a file with SHA-1 {Sha} has already been processed", file, sha);
                    return;
                }

                SeenHashes.Add(sha);
            }

            EventLog.LastSeenTicks = 0;
            var evt = new EventLog(fileS);

            Log.Information("Chunk count: {ChunkCount:N0}, Iterating records...", evt.ChunkCount);

            var seenRecords = 0;

            var fsw = new Stopwatch();
            fsw.Start();

            foreach (var eventRecord in evt.GetEventRecords())
            {
                if (seenRecords % 10 == 0)
                {
                    Console.Title = $"Processing chunk {eventRecord.ChunkNumber:N0} of {evt.ChunkCount} % complete: {(eventRecord.ChunkNumber / (double)evt.ChunkCount):P} Records found: {seenRecords:N0}";
                }

                if (_includeIds.Count > 0)
                {
                    if (_includeIds.Contains(eventRecord.EventId) == false)
                    {
                        //it is NOT in the list, so skip
                        _droppedEvents += 1;
                        continue;
                    }
                }
                else if (_excludeIds.Count > 0)
                {
                    if (_excludeIds.Contains(eventRecord.EventId))
                    {
                        //it IS in the list, so skip
                        _droppedEvents += 1;
                        continue;
                    }
                }

                if (_startDate.HasValue)
                {
                    if (eventRecord.TimeCreated < _startDate.Value)
                    {
                        //too old
                        Log.Debug("Dropping record Id {EventRecordId} with timestamp {TimeCreated} as its too old", eventRecord.EventRecordId, eventRecord.TimeCreated);
                        _droppedEvents += 1;
                        continue;
                    }
                }

                if (_endDate.HasValue)
                {
                    if (eventRecord.TimeCreated > _endDate.Value)
                    {
                        //too new
                        Log.Debug("Dropping record Id {EventRecordId} with timestamp {TimeCreated} as its too new", eventRecord.EventRecordId, eventRecord.TimeCreated);
                        _droppedEvents += 1;
                        continue;
                    }
                }

                if (file.StartsWith(VssDir))
                {
                    eventRecord.SourceFile = $"VSS{file.Replace($"{VssDir}\\", "")}";
                }
                else
                {
                    eventRecord.SourceFile = file;
                }

                try
                {
                    var xdo = new XmlDocument();
                    xdo.LoadXml(eventRecord.Payload);

                    var payOut = JsonConvert.SerializeXmlNode(xdo);
                    eventRecord.Payload = payOut;

                    _csvWriter?.WriteRecord(eventRecord);
                    _csvWriter?.NextRecord();

                    var xml = string.Empty;
                    if (_swXml != null)
                    {
                        xml = eventRecord.ConvertPayloadToXml();
                        _swXml.WriteLine(xml);
                    }

                    if (_swJson != null)
                    {
                        var jsOut = eventRecord.ToJson();
                        if (fj)
                        {
                            if (xml.IsNullOrEmpty())
                            {
                                xml = eventRecord.ConvertPayloadToXml();
                            }

                            jsOut = GetPayloadAsJson(xml);
                        }

                        _swJson.WriteLine(jsOut);
                    }

                    seenRecords += 1;
                }
                catch (Exception e)
                {
                    Log.Error("Error processing record #{RecordNumber}: {Message}", eventRecord.RecordNumber, e.Message);
                    evt.ErrorRecords.Add(21, e.Message);
                }
            }

            fsw.Stop();

            if (evt.ErrorRecords.Count > 0)
            {
                var fn = file;
                if (file.StartsWith(VssDir))
                {
                    fn = $"VSS{file.Replace($"{VssDir}\\", "")}";
                }

                _errorFiles.Add(fn, evt.ErrorRecords.Count);
            }

            _fileCount += 1;

            Console.WriteLine();
            Log.Information("Event log details");
            Log.Information("{Evt}", evt);

            Log.Information("Records included: {SeenRecords:N0} Errors: {ErrorRecordsCount:N0} Events dropped: {DroppedEvents:N0}", seenRecords, evt.ErrorRecords.Count, _droppedEvents);

            if (evt.ErrorRecords.Count > 0)
            {
                Console.WriteLine();
                Log.Information("Errors");
                foreach (var evtErrorRecord in evt.ErrorRecords)
                {
                    Log.Information("Record #{Key}: Error: {Value}", evtErrorRecord.Key, evtErrorRecord.Value);
                }
            }

            if (met && evt.EventIdMetrics.Count > 0)
            {
                Console.WriteLine();
                Log.Information("Metrics (including dropped events)");
                Log.Information("Event ID\tCount");
                foreach (var esEventIdMetric in evt.EventIdMetrics.OrderBy(t => t.Key))
                {
                    if (_includeIds.Count > 0)
                    {
                        if (_includeIds.Contains((int)esEventIdMetric.Key) == false)
                        {
                            //it is NOT in the list, so skip
                            continue;
                        }
                    }
                    else if (_excludeIds.Count > 0)
                    {
                        if (_excludeIds.Contains((int)esEventIdMetric.Key))
                        {
                            //it IS in the list, so skip
                            continue;
                        }
                    }

                    Log.Information("{Key}\t\t{Value:N0}", esEventIdMetric.Key, esEventIdMetric.Value);
                }
            }
        }
        catch (Exception e)
        {
            var fn = file;
            if (file.StartsWith(VssDir))
            {
                fn = $"VSS{file.Replace($"{VssDir}\\", "")}";
            }

            if (e.Message.Contains("Invalid signature! Expected 'ElfFile"))
            {
                Log.Information("{Fn} is not an evtx file! Message: {Message} Skipping...", fn, e.Message);
            }
            else
            {
                Log.Error("Error processing {Fn}! Message: {Message}", fn, e.Message);
            }
        }

        fileS?.Close();
    }
Exemple #8
0
    private static void DoWork(string f, string d, string csv, string csvf, string json, string jsonf, string xml, string xmlf, string dt, string inc, string exc, string sd, string ed, bool fj, int tdt, bool met, string maps, bool vss, bool dedupe, bool sync, bool debug, bool trace)
    {
        var levelSwitch = new LoggingLevelSwitch();

        _activeDateTimeFormat = dt;

        var formatter =
            new DateTimeOffsetFormatter(CultureInfo.CurrentCulture);

        var template = "{Message:lj}{NewLine}{Exception}";

        if (debug)
        {
            levelSwitch.MinimumLevel = LogEventLevel.Debug;
            template = "[{Timestamp:HH:mm:ss.fff} {Level:u3}] {Message:lj}{NewLine}{Exception}";
        }

        if (trace)
        {
            levelSwitch.MinimumLevel = LogEventLevel.Verbose;
            template = "[{Timestamp:HH:mm:ss.fff} {Level:u3}] {Message:lj}{NewLine}{Exception}";
        }

        var conf = new LoggerConfiguration()
                   .WriteTo.Console(outputTemplate: template, formatProvider: formatter)
                   .MinimumLevel.ControlledBy(levelSwitch);

        Log.Logger = conf.CreateLogger();

        if (sync)
        {
            try
            {
                Log.Information("{Header}", Header);
                UpdateFromRepo();
            }
            catch (Exception e)
            {
                Log.Error(e, "There was an error checking for updates: {Message}", e.Message);
            }

            Environment.Exit(0);
        }

        if (f.IsNullOrEmpty() &&
            d.IsNullOrEmpty())
        {
            var helpBld = new HelpBuilder(LocalizationResources.Instance, Console.WindowWidth);
            var hc      = new HelpContext(helpBld, _rootCommand, Console.Out);

            helpBld.Write(hc);

            Log.Warning("-f or -d is required. Exiting");
            Console.WriteLine();
            return;
        }

        Log.Information("{Header}", Header);
        Console.WriteLine();
        Log.Information("Command line: {Args}", string.Join(" ", Environment.GetCommandLineArgs().Skip(1)));
        Console.WriteLine();

        if (IsAdministrator() == false)
        {
            Log.Warning("Warning: Administrator privileges not found!");
            Console.WriteLine();
        }

        if (vss & !RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            vss = false;
            Log.Warning("{Vss} not supported on non-Windows platforms. Disabling...", "--vss");
            Console.WriteLine();
        }

        if (vss & (IsAdministrator() == false))
        {
            Log.Error("{Vss} is present, but administrator rights not found. Exiting", "--vss");
            Console.WriteLine();
            return;
        }

        var sw = new Stopwatch();

        sw.Start();

        var ts = DateTimeOffset.UtcNow;

        _errorFiles = new Dictionary <string, int>();

        if (json.IsNullOrEmpty() == false)
        {
            if (Directory.Exists(json) == false)
            {
                Log.Information("Path to {Json} doesn't exist. Creating...", json);

                try
                {
                    Directory.CreateDirectory(json);
                }
                catch (Exception ex)
                {
                    Log.Fatal(ex,
                              "Unable to create directory {Json}. Does a file with the same name exist? Exiting", json);
                    Console.WriteLine();
                    return;
                }
            }

            var outName = $"{ts:yyyyMMddHHmmss}_EvtxECmd_Output.json";

            if (jsonf.IsNullOrEmpty() == false)
            {
                outName = Path.GetFileName(jsonf);
            }

            var outFile = Path.Combine(json, outName);

            Log.Information("json output will be saved to {OutFile}", outFile);
            Console.WriteLine();

            try
            {
                _swJson = new StreamWriter(outFile, false, Encoding.UTF8);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Unable to open {OutFile}! Is it in use? Exiting!", outFile);
                Console.WriteLine();
                Environment.Exit(0);
            }

            JsConfig.DateHandler = DateHandler.ISO8601;
        }

        if (xml.IsNullOrEmpty() == false)
        {
            if (Directory.Exists(xml) == false)
            {
                Log.Information("Path to {Xml} doesn't exist. Creating...", xml);

                try
                {
                    Directory.CreateDirectory(xml);
                }
                catch (Exception ex)
                {
                    Log.Fatal(ex,
                              "Unable to create directory {Xml}. Does a file with the same name exist? Exiting", xml);
                    return;
                }
            }

            var outName = $"{ts:yyyyMMddHHmmss}_EvtxECmd_Output.xml";

            if (xmlf.IsNullOrEmpty() == false)
            {
                outName = Path.GetFileName(xmlf);
            }

            var outFile = Path.Combine(xml, outName);

            Log.Information("XML output will be saved to {OutFile}", outFile);
            Console.WriteLine();

            try
            {
                _swXml = new StreamWriter(outFile, false, Encoding.UTF8);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Unable to open {OutFile}! Is it in use? Exiting!", outFile);
                Console.WriteLine();
                Environment.Exit(0);
            }
        }

        if (sd.IsNullOrEmpty() == false)
        {
            if (DateTimeOffset.TryParse(sd, null, DateTimeStyles.AssumeUniversal, out var dateTimeOffset))
            {
                _startDate = dateTimeOffset;
                Log.Information("Setting Start date to {StartDate}", _startDate.Value);
            }
            else
            {
                Log.Warning("Could not parse {Sd} to a valid datetime! Events will not be filtered by Start date!", sd);
            }
        }

        if (ed.IsNullOrEmpty() == false)
        {
            if (DateTimeOffset.TryParse(ed, null, DateTimeStyles.AssumeUniversal, out var dateTimeOffset))
            {
                _endDate = dateTimeOffset;
                Log.Information("Setting End date to {EndDate}", _endDate.Value);
            }
            else
            {
                Log.Warning("Could not parse {Ed} to a valid datetime! Events will not be filtered by End date!", ed);
            }
        }

        if (_startDate.HasValue || _endDate.HasValue)
        {
            Console.WriteLine();
        }


        if (csv.IsNullOrEmpty() == false)
        {
            if (Directory.Exists(csv) == false)
            {
                Log.Information(
                    "Path to {Csv} doesn't exist. Creating...", csv);

                try
                {
                    Directory.CreateDirectory(csv);
                }
                catch (Exception ex)
                {
                    Log.Fatal(ex,
                              "Unable to create directory {Csv}. Does a file with the same name exist? Exiting", csv);
                    return;
                }
            }

            var outName = $"{ts:yyyyMMddHHmmss}_EvtxECmd_Output.csv";

            if (csvf.IsNullOrEmpty() == false)
            {
                outName = Path.GetFileName(csvf);
            }

            var outFile = Path.Combine(csv, outName);

            Log.Information("CSV output will be saved to {OutFile}", outFile);
            Console.WriteLine();

            try
            {
                _swCsv = new StreamWriter(outFile, false, Encoding.UTF8);

                var opt = new CsvConfiguration(CultureInfo.InvariantCulture)
                {
                    ShouldUseConstructorParameters = _ => false
                };

                _csvWriter = new CsvWriter(_swCsv, opt);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Unable to open {OutFile}! Is it in use? Exiting!", outFile);
                Console.WriteLine();
                Environment.Exit(0);
            }


            var foo = _csvWriter.Context.AutoMap <EventRecord>();

            foo.Map(t => t.RecordPosition).Ignore();
            foo.Map(t => t.Size).Ignore();
            foo.Map(t => t.Timestamp).Ignore();

            foo.Map(t => t.RecordNumber).Index(0);
            foo.Map(t => t.EventRecordId).Index(1);
            foo.Map(t => t.TimeCreated).Index(2);
            foo.Map(t => t.TimeCreated).Convert(t =>
                                                $"{t.Value.TimeCreated.ToString(dt)}");
            foo.Map(t => t.EventId).Index(3);
            foo.Map(t => t.Level).Index(4);
            foo.Map(t => t.Provider).Index(5);
            foo.Map(t => t.Channel).Index(6);
            foo.Map(t => t.ProcessId).Index(7);
            foo.Map(t => t.ThreadId).Index(8);
            foo.Map(t => t.Computer).Index(9);
            foo.Map(t => t.UserId).Index(10);
            foo.Map(t => t.MapDescription).Index(11);
            foo.Map(t => t.UserName).Index(12);
            foo.Map(t => t.RemoteHost).Index(13);
            foo.Map(t => t.PayloadData1).Index(14);
            foo.Map(t => t.PayloadData2).Index(15);
            foo.Map(t => t.PayloadData3).Index(16);
            foo.Map(t => t.PayloadData4).Index(17);
            foo.Map(t => t.PayloadData5).Index(18);
            foo.Map(t => t.PayloadData6).Index(19);
            foo.Map(t => t.ExecutableInfo).Index(20);
            foo.Map(t => t.HiddenRecord).Index(21);
            foo.Map(t => t.SourceFile).Index(22);
            foo.Map(t => t.Keywords).Index(23);
            foo.Map(t => t.Payload).Index(24);

            _csvWriter.Context.RegisterClassMap(foo);
            _csvWriter.WriteHeader <EventRecord>();
            _csvWriter.NextRecord();
        }

        if (Directory.Exists(maps) == false)
        {
            Log.Warning("Maps directory {Maps} does not exist! Event ID maps will not be loaded!!", maps);
        }
        else
        {
            Log.Debug("Loading maps from {Path}", Path.GetFullPath(maps));
            var errors = EventLog.LoadMaps(Path.GetFullPath(maps));

            if (errors)
            {
                return;
            }

            Log.Information("Maps loaded: {Count:N0}", EventLog.EventLogMaps.Count);
        }

        _includeIds = new HashSet <int>();
        _excludeIds = new HashSet <int>();

        if (exc.IsNullOrEmpty() == false)
        {
            var excSegs = exc.Split(',');

            foreach (var incSeg in excSegs)
            {
                if (int.TryParse(incSeg, out var goodId))
                {
                    _excludeIds.Add(goodId);
                }
            }
        }

        if (inc.IsNullOrEmpty() == false)
        {
            _excludeIds.Clear();
            var incSegs = inc.Split(',');

            foreach (var incSeg in incSegs)
            {
                if (int.TryParse(incSeg, out var goodId))
                {
                    _includeIds.Add(goodId);
                }
            }
        }

        if (vss)
        {
            string driveLetter;
            if (f.IsEmpty() == false)
            {
                driveLetter = Path.GetPathRoot(Path.GetFullPath(f))
                              .Substring(0, 1);
            }
            else
            {
                driveLetter = Path.GetPathRoot(Path.GetFullPath(d))
                              .Substring(0, 1);
            }


            Helper.MountVss(driveLetter, VssDir);
            Console.WriteLine();
        }

        EventLog.TimeDiscrepancyThreshold = tdt;

        if (f.IsNullOrEmpty() == false)
        {
            if (File.Exists(f) == false)
            {
                Log.Warning("\t{F} does not exist! Exiting", f);
                Console.WriteLine();
                return;
            }

            if (_swXml == null && _swJson == null && _swCsv == null)
            {
                //no need for maps
                Log.Debug("Clearing map collection since no output specified");
                EventLog.EventLogMaps.Clear();
            }

            dedupe = false;

            ProcessFile(Path.GetFullPath(f), dedupe, fj, met);

            if (vss)
            {
                var vssDirs = Directory.GetDirectories(VssDir);

                var root = Path.GetPathRoot(Path.GetFullPath(f));
                var stem = Path.GetFullPath(f).Replace(root, "");

                foreach (var vssDir in vssDirs)
                {
                    var newPath = Path.Combine(vssDir, stem);
                    if (File.Exists(newPath))
                    {
                        ProcessFile(newPath, dedupe, fj, met);
                    }
                }
            }
        }
        else
        {
            if (Directory.Exists(d) == false)
            {
                Log.Warning("\t{D} does not exist! Exiting", d);
                Console.WriteLine();
                return;
            }

            Log.Information("Looking for event log files in {D}", d);
            Console.WriteLine();

#if !NET6_0
            var directoryEnumerationFilters = new DirectoryEnumerationFilters
            {
                InclusionFilter = fsei => fsei.Extension.ToUpperInvariant() == ".EVTX",
                RecursionFilter = entryInfo => !entryInfo.IsMountPoint && !entryInfo.IsSymbolicLink,
                ErrorFilter     = (errorCode, errorMessage, pathProcessed) => true
            };

            var dirEnumOptions =
                DirectoryEnumerationOptions.Files | DirectoryEnumerationOptions.Recursive |
                DirectoryEnumerationOptions.SkipReparsePoints | DirectoryEnumerationOptions.ContinueOnException |
                DirectoryEnumerationOptions.BasicSearch;

            var files2 =
                Directory.EnumerateFileSystemEntries(Path.GetFullPath(d), dirEnumOptions, directoryEnumerationFilters);
#else
            var enumerationOptions = new EnumerationOptions
            {
                IgnoreInaccessible    = true,
                MatchCasing           = MatchCasing.CaseInsensitive,
                RecurseSubdirectories = true,
                AttributesToSkip      = 0
            };

            var files2 =
                Directory.EnumerateFileSystemEntries(d, "*.evtx", enumerationOptions);
#endif

            if (_swXml == null && _swJson == null && _swCsv == null)
            {
                //no need for maps
                Log.Debug("Clearing map collection since no output specified");
                EventLog.EventLogMaps.Clear();
            }

            foreach (var file in files2)
            {
                ProcessFile(file, dedupe, fj, met);
            }

            if (vss)
            {
                var vssDirs = Directory.GetDirectories(VssDir);

                Console.WriteLine();

                foreach (var vssDir in vssDirs)
                {
                    var root = Path.GetPathRoot(Path.GetFullPath(d));
                    var stem = Path.GetFullPath(d).Replace(root, "");

                    var target = Path.Combine(vssDir, stem);

                    Console.WriteLine();
                    Log.Information("Searching {Vss} for event logs...", $"VSS{target.Replace($"{VssDir}\\", "")}");

                    var vssFiles = Helper.GetFilesFromPath(target, "*.evtx", true);

                    foreach (var file in vssFiles)
                    {
                        ProcessFile(file, dedupe, fj, met);
                    }
                }
            }
        }

        try
        {
            _swCsv?.Flush();
            _swCsv?.Close();

            _swJson?.Flush();
            _swJson?.Close();

            _swXml?.Flush();
            _swXml?.Close();
        }
        catch (Exception e)
        {
            Log.Error(e, "Error when flushing output files to disk! Error message: {Message}", e.Message);
        }

        sw.Stop();
        Console.WriteLine();

        if (_fileCount == 1)
        {
            Log.Information("Processed {FileCount:N0} file in {TotalSeconds:N4} seconds", _fileCount, sw.Elapsed.TotalSeconds);
        }
        else
        {
            Log.Information("Processed {FileCount:N0} files in {TotalSeconds:N4} seconds", _fileCount, sw.Elapsed.TotalSeconds);
        }

        Console.WriteLine();

        if (_errorFiles.Count > 0)
        {
            Console.WriteLine();
            Log.Information("Files with errors");
            foreach (var errorFile in _errorFiles)
            {
                Log.Information("{Key} error count: {Value:N0}", errorFile.Key, errorFile.Value);
            }

            Console.WriteLine();
        }

        if (vss)
        {
            if (Directory.Exists(VssDir))
            {
                foreach (var directory in Directory.GetDirectories(VssDir))
                {
                    Directory.Delete(directory);
                }

#if !NET6_0
                Directory.Delete(VssDir, true, true);
#else
                Directory.Delete(VssDir, true);
#endif
            }
        }
    }