private void CreateOutputMods() { Directory.EnumerateFiles(Path.Combine(OutputFolder, "profiles"), "settings.ini", DirectoryEnumerationOptions.Recursive).Do(f => { var ini = f.LoadIniFile(); if (ini == null) { Utils.Log($"settings.ini is null for {f}, skipping"); return; } var overwrites = ini.custom_overwrites; if (overwrites == null) { Utils.Log("No custom overwrites found, skipping"); return; } if (overwrites is SectionData data) { data.Coll.Do(keyData => { var v = keyData.Value; var mod = Path.Combine(OutputFolder, "mods", v); if (!Directory.Exists(mod)) { Directory.CreateDirectory(mod); } }); } }); }
private static void SaveJson(IPrefetch pf, bool pretty, string outDir) { try { if (Directory.Exists(outDir) == false) { Directory.CreateDirectory(outDir); } var outName = $"{DateTimeOffset.UtcNow:yyyyMMddHHmmss}_{Path.GetFileName(pf.SourceFilename)}.json"; var outFile = Path.Combine(outDir, outName); if (pretty) { File.WriteAllText(outFile, pf.Dump()); } else { File.WriteAllText(outFile, pf.ToJson()); } } catch (Exception ex) { _logger.Error($"Error exporting json. Error: {ex.Message}"); } }
/// <summary> /// Attempt to extract a file from an archive /// </summary> /// <param name="entryName">Name of the entry to be extracted</param> /// <param name="outDir">Output directory for archive extraction</param> /// <returns>Name of the extracted file, null on error</returns> public virtual string CopyToFile(string entryName, string outDir) { string realentry = null; // Copy single file from the current folder to the output directory, if exists try { // Make sure the folders exist Directory.CreateDirectory(_filename); Directory.CreateDirectory(outDir); // Get all files from the input directory List <string> files = Utilities.RetrieveFiles(_filename, new List <string>()); // Now sort through to find the first file that matches string match = files.Where(s => s.EndsWith(entryName)).FirstOrDefault(); // If we had a file, copy that over to the new name if (!String.IsNullOrWhiteSpace(match)) { realentry = match; File.Copy(match, Path.Combine(outDir, entryName)); } } catch (Exception ex) { Globals.Logger.Error(ex.ToString()); return(realentry); } return(realentry); }
/// <summary> /// Attempt to extract a stream from an archive /// </summary> /// <param name="entryName">Name of the entry to be extracted</param> /// <param name="realEntry">Output representing the entry name that was found</param> /// <returns>MemoryStream representing the entry, null on error</returns> public virtual (MemoryStream, string) CopyToStream(string entryName) { MemoryStream ms = new MemoryStream(); string realentry = null; // Copy single file from the current folder to the output directory, if exists try { // Make sure the folders exist Directory.CreateDirectory(_filename); // Get all files from the input directory List <string> files = Utilities.RetrieveFiles(_filename, new List <string>()); // Now sort through to find the first file that matches string match = files.Where(s => s.EndsWith(entryName)).FirstOrDefault(); // If we had a file, copy that over to the new name if (!String.IsNullOrWhiteSpace(match)) { Utilities.TryOpenRead(match).CopyTo(ms); realentry = match; } } catch (Exception ex) { Globals.Logger.Error(ex.ToString()); return(ms, realentry); } return(ms, realentry); }
public string AddProfile(string name = null) { string profile_name = name ?? RandomName(); Directory.CreateDirectory(Path.Combine(MO2Folder, "profiles", profile_name)); Profiles.Add(profile_name); return(profile_name); }
public TemporaryDirectory(string name) { FullName = name; if (!Directory.Exists(FullName)) { Directory.CreateDirectory(FullName); } }
/// <summary> /// Adds a file to the given mod with a given path in the mod. Fills it with random data unless /// random_fill == 0; /// </summary> /// <param name="mod_name"></param> /// <param name="path"></param> /// <param name="random_fill"></param> /// <returns></returns> public string AddModFile(string mod_name, string path, int random_fill = 128) { var full_path = Path.Combine(ModsFolder, mod_name, path); Directory.CreateDirectory(Path.GetDirectoryName(full_path)); GenerateRandomFileData(full_path, random_fill); return(full_path); }
public string AddMod(string name = null) { string mod_name = name ?? RandomName(); var mod_folder = Path.Combine(MO2Folder, "mods", mod_name); Directory.CreateDirectory(mod_folder); File.WriteAllText(Path.Combine(mod_folder, "meta.ini"), "[General]"); Mods.Add(mod_name); return(mod_name); }
public string AddGameFile(string path, int i) { var full_path = Path.Combine(GameFolder, path); var dir = Path.GetDirectoryName(full_path); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } GenerateRandomFileData(full_path, i); return(full_path); }
public void BuildFolderStructure() { Info("Building Folder Structure"); ModList.Directives .Select(d => Path.Combine(OutputFolder, Path.GetDirectoryName(d.To))) .Distinct() .Do(f => { if (Directory.Exists(f)) { return; } Directory.CreateDirectory(f); }); }
public static async Task Setup(TestContext testContext) { Queue = new WorkQueue(); Utils.LogMessages.Subscribe(f => testContext.WriteLine(f.ShortDescription)); if (!Directory.Exists(_stagingFolder)) { Directory.CreateDirectory(_stagingFolder); } if (!Directory.Exists(_bsaFolder)) { Directory.CreateDirectory(_bsaFolder); } var modIDs = new[]
static VirtualFileSystem() { VFS = new VirtualFileSystem(); RootFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); _stagedRoot = Path.Combine(RootFolder, "vfs_staged_files"); Utils.OnQueue(() => { if (Directory.Exists(_stagedRoot)) { DeleteDirectory(_stagedRoot); } }); Directory.CreateDirectory(_stagedRoot); }
public void Directory_GetFileSystemEntries_LongPathWithoutPrefix_ShouldReturnCorrectEntries() { using (var tempDir = new TemporaryDirectory(MethodBase.GetCurrentMethod().Name)) { var longDir = Path.Combine(tempDir.Directory.FullName, new string('x', 128), new string('x', 128), new string('x', 128), new string('x', 128)); Directory.CreateDirectory(longDir); Directory.CreateDirectory(Path.Combine(longDir, "A")); Directory.CreateDirectory(Path.Combine(longDir, "B")); File.WriteAllText(Path.Combine(longDir, "C"), "C"); var entries = Directory.GetFileSystemEntries(longDir).ToArray(); Assert.AreEqual(3, entries.Length); } }
public bool Go(ref bool pause, TVRenameStats stats) { // "try" and silently fail. eg. when file is use by other... StreamWriter writer; try { // create folder if it does not exist. (Only really applies when .meta\ folder is being used.) if (!this.Where.Directory.Exists) { Directory.CreateDirectory(this.Where.Directory.FullName); } writer = new System.IO.StreamWriter(this.Where.FullName, false, System.Text.Encoding.GetEncoding(1252)); if (writer == null) { return(false); } } catch (Exception) { this.Done = true; return(true); } // See: http://pytivo.sourceforge.net/wiki/index.php/Metadata writer.WriteLine(string.Format("title : {0}", this.Episode.SI.ShowName)); writer.WriteLine(string.Format("seriesTitle : {0}", this.Episode.SI.ShowName)); writer.WriteLine(string.Format("episodeTitle : {0}", this.Episode.Name)); writer.WriteLine(string.Format("episodeNumber : {0}{1:0#}", this.Episode.SeasonNumber, this.Episode.EpNum)); writer.WriteLine("isEpisode : true"); writer.WriteLine(string.Format("description : {0}", this.Episode.Overview)); if (this.Episode.FirstAired != null) { writer.WriteLine(string.Format("originalAirDate : {0:yyyy-MM-dd}T00:00:00Z", this.Episode.FirstAired.Value)); } writer.WriteLine(string.Format("callsign : {0}", this.Episode.SI.TheSeries().getNetwork())); WriteEntries(writer, "vDirector", this.Episode.EpisodeDirector); WriteEntries(writer, "vWriter", this.Episode.Writer); WriteEntries(writer, "vActor", String.Join("|", this.Episode.SI.TheSeries().GetActors())); WriteEntries(writer, "vGuestStar", this.Episode.EpisodeGuestStars); // not worring about actors being repeated WriteEntries(writer, "vProgramGenre", String.Join("|", this.Episode.SI.TheSeries().GetGenres())); writer.Close(); this.Done = true; return(true); }
/// <summary> /// Attempt to extract a file as an archive /// </summary> /// <param name="outDir">Output directory for archive extraction</param> /// <returns>True if the extraction was a success, false otherwise</returns> public virtual bool CopyAll(string outDir) { // Copy all files from the current folder to the output directory recursively try { // Make sure the folders exist Directory.CreateDirectory(_filename); Directory.CreateDirectory(outDir); Directory.Copy(_filename, outDir, true, PathFormat.FullPath); } catch (Exception ex) { Globals.Logger.Error(ex.ToString()); return(false); } return(true); }
public void Configure() { File.WriteAllLines(Path.Combine(MO2Folder, "ModOrganizer.ini"), new [] { "[General]", $"gameName={Game.MetaData().MO2Name}", $"gamePath={GameFolder.Replace("\\", "\\\\")}", $"download_directory={DownloadsFolder}" }); Directory.CreateDirectory(DownloadsFolder); Directory.CreateDirectory(Path.Combine(GameFolder, "Data")); Profiles.Do(profile => { File.WriteAllLines(Path.Combine(MO2Folder, "profiles", profile, "modlist.txt"), Mods.Select(s => $"+{s}").ToArray()); }); }
public void SetVolumeMountPoint() { Console.WriteLine("Volume.SetVolumeMountPoint()\n"); if (!IsAdmin()) { Assert.Fail(); } #region Logical Drives int cnt = 0; string destFolder = Path.Combine(TempFolder, "Volume.SetVolumeMountPoint()-" + Path.GetRandomFileName()); Directory.CreateDirectory(destFolder); string guid = Volume.GetUniqueVolumeNameForPath(SysDrive); try { StopWatcher(true); Volume.SetVolumeMountPoint(destFolder, guid); Console.WriteLine( "\t#{0:000}\tSystem Drive: [{1}]\tGUID: [{2}]\n\t\tDestination : [{3}]\n\t\tCreated Mount Point.\n\t{4}", ++cnt, SysDrive, guid, destFolder, Reporter(true)); Console.WriteLine("\n"); EnumerateVolumeMountPoints(); Console.WriteLine("\n\nFile.GetLinkTargetInfo()"); LinkTargetInfo lti = File.GetLinkTargetInfo(destFolder); Assert.IsTrue(!string.IsNullOrWhiteSpace(lti.PrintName)); Assert.IsTrue(!string.IsNullOrWhiteSpace(lti.SubstituteName)); Assert.IsTrue(Dump(lti, -14), "Unable to dump object."); // Cleanup. StopWatcher(true); bool deleteOk = false; try { Volume.DeleteVolumeMountPoint(destFolder); deleteOk = true; } catch (Exception ex) { Console.WriteLine("\nCaught Exception: [{0}]\n", ex.Message.Replace(Environment.NewLine, " ")); } Console.WriteLine("\n\nVolume.DeleteVolumeMountPoint() (Should be True): [{0}]\tFolder: [{1}]\n{2}\n", deleteOk, destFolder, Reporter()); Directory.Delete(destFolder, true, true); Assert.IsTrue(deleteOk && !Directory.Exists(destFolder)); EnumerateVolumeMountPoints(); } catch (Exception ex) { Console.WriteLine("\nCaught Exception: [{0}]\n", ex.Message.Replace(Environment.NewLine, " ")); cnt = 0; } finally { // Always remove mount point. // Experienced: CCleaner deletes through mount points! try { Volume.DeleteVolumeMountPoint(destFolder); } catch { } } Assert.IsTrue(cnt > 0, "Nothing was enumerated."); #endregion // Logical Drives }
// Pattern: <class>_<function>_<scenario>_<expected result> #region Unit Tests private void Dump83Path(bool isLocal) { #region Setup Console.WriteLine("\n=== TEST {0} ===", isLocal ? UnitTestConstants.Local : UnitTestConstants.Network); var myLongPath = Path.GetTempPath("My Long Data File Or Directory"); if (!isLocal) { myLongPath = Path.LocalToUnc(myLongPath); } Console.WriteLine("\nInput Path: [{0}]\n", myLongPath); #endregion // Setup #region File string short83Path; try { using (File.Create(myLongPath)) UnitTestConstants.StopWatcher(true); short83Path = Path.GetShort83Path(myLongPath); Console.WriteLine("Short 8.3 file path : [{0}]\t\t\t{1}", short83Path, UnitTestConstants.Reporter(true)); Assert.IsTrue(!short83Path.Equals(myLongPath)); Assert.IsTrue(short83Path.EndsWith(@"~1")); UnitTestConstants.StopWatcher(true); var longFrom83Path = Path.GetLongFrom83ShortPath(short83Path); Console.WriteLine("Long path from 8.3 path: [{0}]{1}", longFrom83Path, UnitTestConstants.Reporter(true)); Assert.IsTrue(longFrom83Path.Equals(myLongPath)); Assert.IsFalse(longFrom83Path.EndsWith(@"~1")); } catch (Exception ex) { Console.WriteLine("Caught (unexpected) {0}: [{1}]", ex.GetType().FullName, ex.Message.Replace(Environment.NewLine, " ")); } finally { if (File.Exists(myLongPath)) { File.Delete(myLongPath); } } Console.WriteLine(); #endregion // File #region Directory try { Directory.CreateDirectory(myLongPath); UnitTestConstants.StopWatcher(true); short83Path = Path.GetShort83Path(myLongPath); Console.WriteLine("Short 8.3 directory path: [{0}]\t\t\t{1}", short83Path, UnitTestConstants.Reporter(true)); Assert.IsFalse(short83Path.Equals(myLongPath)); Assert.IsTrue(short83Path.EndsWith(@"~1")); UnitTestConstants.StopWatcher(true); var longFrom83Path = Path.GetLongFrom83ShortPath(short83Path); Console.WriteLine("Long path from 8.3 path : [{0}]{1}", longFrom83Path, UnitTestConstants.Reporter(true)); Assert.IsTrue(longFrom83Path.Equals(myLongPath)); Assert.IsFalse(longFrom83Path.EndsWith(@"~1")); } catch (Exception ex) { Console.WriteLine("Caught (unexpected) {0}: [{1}]", ex.GetType().FullName, ex.Message.Replace(Environment.NewLine, " ")); } finally { if (Directory.Exists(myLongPath)) { Directory.Delete(myLongPath); } } Console.WriteLine(); #endregion // Directory }
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(""); } }
private static void Main(string[] args) { ExceptionlessClient.Default.Startup("x3MPpeQSBUUsXl3DjekRQ9kYjyN3cr5JuwdoOBpZ"); SetupNLog(); _keywords = new HashSet <string> { "temp", "tmp" }; _logger = LogManager.GetCurrentClassLogger(); _fluentCommandLineParser = new FluentCommandLineParser <ApplicationArguments> { IsCaseSensitive = false }; _fluentCommandLineParser.Setup(arg => arg.File) .As('f') .WithDescription("File to process. Either this or -d is required"); _fluentCommandLineParser.Setup(arg => arg.Directory) .As('d') .WithDescription("Directory to recursively process. Either this or -f is required"); _fluentCommandLineParser.Setup(arg => arg.Keywords) .As('k') .WithDescription( "Comma separated list of keywords to highlight in output. By default, 'temp' and 'tmp' are highlighted. Any additional keywords will be added to these."); _fluentCommandLineParser.Setup(arg => arg.OutFile) .As('o') .WithDescription( "When specified, save prefetch file bytes to the given path. Useful to look at decompressed Win10 files"); _fluentCommandLineParser.Setup(arg => arg.Quiet) .As('q') .WithDescription( "Do not dump full details about each file processed. Speeds up processing when using --json or --csv. Default is FALSE\r\n") .SetDefault(false); _fluentCommandLineParser.Setup(arg => arg.JsonDirectory) .As("json") .WithDescription( "Directory to save json representation to. Use --pretty for a more human readable layout"); _fluentCommandLineParser.Setup(arg => arg.CsvDirectory) .As("csv") .WithDescription( "Directory to save CSV results to. Be sure to include the full path in double quotes"); _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.xHtmlDirectory) .As("html") .WithDescription( "Directory to save xhtml formatted results to. Be sure to include the full path in double quotes"); _fluentCommandLineParser.Setup(arg => arg.JsonPretty) .As("pretty") .WithDescription( "When exporting to json, use a more human readable layout. Default is FALSE\r\n").SetDefault(false); _fluentCommandLineParser.Setup(arg => arg.DateTimeFormat) .As("dt") .WithDescription( "The custom date/time format to use when displaying timestamps. See https://goo.gl/CNVq0k for options. Default is: yyyy-MM-dd HH:mm:ss") .SetDefault("yyyy-MM-dd HH:mm:ss"); _fluentCommandLineParser.Setup(arg => arg.PreciseTimestamps) .As("mp") .WithDescription( "When true, display higher precision for timestamps. Default is FALSE").SetDefault(false); var header = $"PECmd version {Assembly.GetExecutingAssembly().GetName().Version}" + "\r\n\r\nAuthor: Eric Zimmerman ([email protected])" + "\r\nhttps://github.com/EricZimmerman/PECmd"; var footer = @"Examples: PECmd.exe -f ""C:\Temp\CALC.EXE-3FBEF7FD.pf""" + "\r\n\t " + @" PECmd.exe -f ""C:\Temp\CALC.EXE-3FBEF7FD.pf"" --json ""D:\jsonOutput"" --jsonpretty" + "\r\n\t " + @" PECmd.exe -d ""C:\Temp"" -k ""system32, fonts""" + "\r\n\t " + @" PECmd.exe -d ""C:\Temp"" --csv ""c:\temp"" --csvf foo.csv --json c:\temp\json" + "\r\n\t " + @" PECmd.exe -d ""C:\Windows\Prefetch""" + "\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 (UsefulExtension.IsNullOrEmpty(_fluentCommandLineParser.Object.File) && UsefulExtension.IsNullOrEmpty(_fluentCommandLineParser.Object.Directory)) { _fluentCommandLineParser.HelpOption.ShowHelp(_fluentCommandLineParser.Options); _logger.Warn("Either -f or -d is required. Exiting"); return; } if (UsefulExtension.IsNullOrEmpty(_fluentCommandLineParser.Object.File) == false && !File.Exists(_fluentCommandLineParser.Object.File)) { _logger.Warn($"File '{_fluentCommandLineParser.Object.File}' not found. Exiting"); return; } if (UsefulExtension.IsNullOrEmpty(_fluentCommandLineParser.Object.Directory) == false && !Directory.Exists(_fluentCommandLineParser.Object.Directory)) { _logger.Warn($"Directory '{_fluentCommandLineParser.Object.Directory}' not found. Exiting"); return; } if (_fluentCommandLineParser.Object.Keywords?.Length > 0) { var kws = _fluentCommandLineParser.Object.Keywords.ToLowerInvariant().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (var kw in kws) { _keywords.Add(kw.Trim()); } } _logger.Info(header); _logger.Info(""); _logger.Info($"Command line: {string.Join(" ", Environment.GetCommandLineArgs().Skip(1))}"); if (IsAdministrator() == false) { _logger.Fatal("\r\nWarning: Administrator privileges not found!"); } _logger.Info(""); _logger.Info($"Keywords: {string.Join(", ", _keywords)}"); _logger.Info(""); if (_fluentCommandLineParser.Object.PreciseTimestamps) { _fluentCommandLineParser.Object.DateTimeFormat = _preciseTimeFormat; } _processedFiles = new List <IPrefetch>(); _failedFiles = new List <string>(); if (_fluentCommandLineParser.Object.File?.Length > 0) { IPrefetch pf = null; try { pf = LoadFile(_fluentCommandLineParser.Object.File); if (pf != null) { if (_fluentCommandLineParser.Object.OutFile.IsNullOrEmpty() == false) { try { if (Directory.Exists(Path.GetDirectoryName(_fluentCommandLineParser.Object.OutFile)) == false) { Directory.CreateDirectory( Path.GetDirectoryName(_fluentCommandLineParser.Object.OutFile)); } PrefetchFile.SavePrefetch(_fluentCommandLineParser.Object.OutFile, pf); _logger.Info($"Saved prefetch bytes to '{_fluentCommandLineParser.Object.OutFile}'"); } catch (Exception e) { _logger.Error($"Unable to save prefetch file. Error: {e.Message}"); } } _processedFiles.Add(pf); } } catch (UnauthorizedAccessException ex) { _logger.Error( $"Unable to access '{_fluentCommandLineParser.Object.File}'. Are you running as an administrator? Error: {ex.Message}"); } catch (Exception ex) { _logger.Error( $"Error getting prefetch files in '{_fluentCommandLineParser.Object.Directory}'. Error: {ex.Message}"); } } else { _logger.Info($"Looking for prefetch files in '{_fluentCommandLineParser.Object.Directory}'"); _logger.Info(""); string[] pfFiles = null; var f = new DirectoryEnumerationFilters(); f.InclusionFilter = fsei => { if (fsei.Extension.ToUpperInvariant() == ".PF") { return(true); } return(false); }; 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 = Alphaleonis.Win32.Filesystem.Directory.EnumerateFileSystemEntries(_fluentCommandLineParser.Object.Directory, dirEnumOptions, f); try { pfFiles = files2.ToArray(); //Directory.GetFiles(_fluentCommandLineParser.Object.Directory, "*.pf", SearchOption.AllDirectories); } catch (UnauthorizedAccessException ua) { _logger.Error( $"Unable to access '{_fluentCommandLineParser.Object.Directory}'. Are you running as an administrator? Error: {ua.Message}"); return; } catch (Exception ex) { _logger.Error( $"Error getting prefetch files in '{_fluentCommandLineParser.Object.Directory}'. Error: {ex.Message}"); return; } _logger.Info($"Found {pfFiles.Length:N0} Prefetch files"); _logger.Info(""); var sw = new Stopwatch(); sw.Start(); foreach (var file in pfFiles) { var pf = LoadFile(file); if (pf != null) { _processedFiles.Add(pf); } } sw.Stop(); if (_fluentCommandLineParser.Object.Quiet) { _logger.Info(""); } _logger.Info( $"Processed {pfFiles.Length - _failedFiles.Count:N0} out of {pfFiles.Length:N0} files in {sw.Elapsed.TotalSeconds:N4} seconds"); if (_failedFiles.Count > 0) { _logger.Info(""); _logger.Warn("Failed files"); foreach (var failedFile in _failedFiles) { _logger.Info($" {failedFile}"); } } } if (_processedFiles.Count > 0) { _logger.Info(""); try { CsvWriter csv = null; StreamWriter streamWriter = null; CsvWriter csvTl = null; StreamWriter streamWriterTl = null; if (_fluentCommandLineParser.Object.CsvDirectory?.Length > 0) { var outName = $"{DateTimeOffset.Now:yyyyMMddHHmmss}_PECmd_Output.csv"; if (_fluentCommandLineParser.Object.CsvName.IsNullOrEmpty() == false) { outName = Path.GetFileName(_fluentCommandLineParser.Object.CsvName); } var outNameTl = $"{DateTimeOffset.Now:yyyyMMddHHmmss}_PECmd_Output_Timeline.csv"; if (_fluentCommandLineParser.Object.CsvName.IsNullOrEmpty() == false) { outNameTl = $"{Path.GetFileNameWithoutExtension(_fluentCommandLineParser.Object.CsvName)}_Timeline{Path.GetExtension(_fluentCommandLineParser.Object.CsvName)}"; } var outFile = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outName); var outFileTl = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outNameTl); if (Directory.Exists(_fluentCommandLineParser.Object.CsvDirectory) == false) { _logger.Warn( $"Path to '{_fluentCommandLineParser.Object.CsvDirectory}' does not exist. Creating..."); Directory.CreateDirectory(_fluentCommandLineParser.Object.CsvDirectory); } _logger.Warn($"CSV output will be saved to '{outFile}'"); _logger.Warn($"CSV time line output will be saved to '{outFileTl}'"); try { streamWriter = new StreamWriter(outFile); csv = new CsvWriter(streamWriter); csv.WriteHeader(typeof(CsvOut)); csv.NextRecord(); streamWriterTl = new StreamWriter(outFileTl); csvTl = new CsvWriter(streamWriterTl); csvTl.WriteHeader(typeof(CsvOutTl)); csvTl.NextRecord(); } catch (Exception ex) { _logger.Error( $"Unable to open '{outFile}' for writing. CSV export canceled. Error: {ex.Message}"); } } if (_fluentCommandLineParser.Object.JsonDirectory?.Length > 0) { if (Directory.Exists(_fluentCommandLineParser.Object.JsonDirectory) == false) { _logger.Warn( $"'{_fluentCommandLineParser.Object.JsonDirectory} does not exist. Creating...'"); Directory.CreateDirectory(_fluentCommandLineParser.Object.JsonDirectory); } _logger.Warn($"Saving json output to '{_fluentCommandLineParser.Object.JsonDirectory}'"); } XmlTextWriter xml = null; if (_fluentCommandLineParser.Object.xHtmlDirectory?.Length > 0) { if (Directory.Exists(_fluentCommandLineParser.Object.xHtmlDirectory) == false) { _logger.Warn( $"'{_fluentCommandLineParser.Object.xHtmlDirectory} does not exist. Creating...'"); Directory.CreateDirectory(_fluentCommandLineParser.Object.xHtmlDirectory); } var outDir = Path.Combine(_fluentCommandLineParser.Object.xHtmlDirectory, $"{DateTimeOffset.UtcNow:yyyyMMddHHmmss}_PECmd_Output_for_{_fluentCommandLineParser.Object.xHtmlDirectory.Replace(@":\", "_").Replace(@"\", "_")}"); if (Directory.Exists(outDir) == false) { Directory.CreateDirectory(outDir); } var styleDir = Path.Combine(outDir, "styles"); if (Directory.Exists(styleDir) == false) { Directory.CreateDirectory(styleDir); } File.WriteAllText(Path.Combine(styleDir, "normalize.css"), Resources.normalize); File.WriteAllText(Path.Combine(styleDir, "style.css"), Resources.style); Resources.directories.Save(Path.Combine(styleDir, "directories.png")); Resources.filesloaded.Save(Path.Combine(styleDir, "filesloaded.png")); var outFile = Path.Combine(_fluentCommandLineParser.Object.xHtmlDirectory, outDir, "index.xhtml"); _logger.Warn($"Saving HTML output to '{outFile}'"); xml = new XmlTextWriter(outFile, Encoding.UTF8) { Formatting = Formatting.Indented, Indentation = 4 }; xml.WriteStartDocument(); xml.WriteProcessingInstruction("xml-stylesheet", "href=\"styles/normalize.css\""); xml.WriteProcessingInstruction("xml-stylesheet", "href=\"styles/style.css\""); xml.WriteStartElement("document"); } if (_fluentCommandLineParser.Object.CsvDirectory.IsNullOrEmpty() == false || _fluentCommandLineParser.Object.JsonDirectory.IsNullOrEmpty() == false || _fluentCommandLineParser.Object.xHtmlDirectory.IsNullOrEmpty() == false) { foreach (var processedFile in _processedFiles) { var o = GetCsvFormat(processedFile); try { foreach (var dateTimeOffset in processedFile.LastRunTimes) { var t = new CsvOutTl(); var exePath = processedFile.Filenames.FirstOrDefault( y => y.EndsWith(processedFile.Header.ExecutableFilename)); if (exePath == null) { exePath = processedFile.Header.ExecutableFilename; } t.ExecutableName = exePath; t.RunTime = dateTimeOffset.ToString(_fluentCommandLineParser.Object.DateTimeFormat); csvTl?.WriteRecord(t); csvTl?.NextRecord(); } } catch (Exception ex) { _logger.Error( $"Error getting time line record for '{processedFile.SourceFilename}' to '{_fluentCommandLineParser.Object.CsvDirectory}'. Error: {ex.Message}"); } try { csv?.WriteRecord(o); csv?.NextRecord(); } catch (Exception ex) { _logger.Error( $"Error writing CSV record for '{processedFile.SourceFilename}' to '{_fluentCommandLineParser.Object.CsvDirectory}'. Error: {ex.Message}"); } if (_fluentCommandLineParser.Object.JsonDirectory?.Length > 0) { SaveJson(processedFile, _fluentCommandLineParser.Object.JsonPretty, _fluentCommandLineParser.Object.JsonDirectory); } //XHTML xml?.WriteStartElement("Container"); xml?.WriteElementString("SourceFile", o.SourceFilename); xml?.WriteElementString("SourceCreated", o.SourceCreated); xml?.WriteElementString("SourceModified", o.SourceModified); xml?.WriteElementString("SourceAccessed", o.SourceAccessed); xml?.WriteElementString("LastRun", o.LastRun); xml?.WriteElementString("PreviousRun0", $"{o.PreviousRun0}"); xml?.WriteElementString("PreviousRun1", $"{o.PreviousRun1}"); xml?.WriteElementString("PreviousRun2", $"{o.PreviousRun2}"); xml?.WriteElementString("PreviousRun3", $"{o.PreviousRun3}"); xml?.WriteElementString("PreviousRun4", $"{o.PreviousRun4}"); xml?.WriteElementString("PreviousRun5", $"{o.PreviousRun5}"); xml?.WriteElementString("PreviousRun6", $"{o.PreviousRun6}"); xml?.WriteStartElement("ExecutableName"); xml?.WriteAttributeString("title", "Note: The name of the executable tracked by the pf file"); xml?.WriteString(o.ExecutableName); xml?.WriteEndElement(); xml?.WriteElementString("RunCount", $"{o.RunCount}"); xml?.WriteStartElement("Size"); xml?.WriteAttributeString("title", "Note: The size of the executable in bytes"); xml?.WriteString(o.Size); xml?.WriteEndElement(); xml?.WriteStartElement("Hash"); xml?.WriteAttributeString("title", "Note: The calculated hash for the pf file that should match the hash in the source file name"); xml?.WriteString(o.Hash); xml?.WriteEndElement(); xml?.WriteStartElement("Version"); xml?.WriteAttributeString("title", "Note: The operating system that generated the prefetch file"); xml?.WriteString(o.Version); xml?.WriteEndElement(); xml?.WriteElementString("Note", o.Note); xml?.WriteElementString("Volume0Name", o.Volume0Name); xml?.WriteElementString("Volume0Serial", o.Volume0Serial); xml?.WriteElementString("Volume0Created", o.Volume0Created); xml?.WriteElementString("Volume1Name", o.Volume1Name); xml?.WriteElementString("Volume1Serial", o.Volume1Serial); xml?.WriteElementString("Volume1Created", o.Volume1Created); xml?.WriteStartElement("Directories"); xml?.WriteAttributeString("title", "A comma separated list of all directories accessed by the executable"); xml?.WriteString(o.Directories); xml?.WriteEndElement(); xml?.WriteStartElement("FilesLoaded"); xml?.WriteAttributeString("title", "A comma separated list of all files that were loaded by the executable"); xml?.WriteString(o.FilesLoaded); xml?.WriteEndElement(); xml?.WriteEndElement(); } //Close CSV stuff streamWriter?.Flush(); streamWriter?.Close(); streamWriterTl?.Flush(); streamWriterTl?.Close(); //Close XML xml?.WriteEndElement(); xml?.WriteEndDocument(); xml?.Flush(); } } catch (Exception ex) { _logger.Error($"Error exporting data! Error: {ex.Message}"); } } }
protected override async Task <bool> _Begin(CancellationToken cancel) { if (cancel.IsCancellationRequested) { return(false); } var metric = Metrics.Send(Metrics.BeginInstall, ModList.Name); ConfigureProcessor(20, ConstructDynamicNumThreads(await RecommendQueueSize())); var game = ModList.GameType.MetaData(); if (GameFolder == null) { GameFolder = game.GameLocation(); } if (GameFolder == null) { await Utils.Log(new CriticalFailureIntervention( $"In order to do a proper install Wabbajack needs to know where your {game.MO2Name} folder resides. We tried looking the " + "game location up in the Windows Registry but were unable to find it, please make sure you launch the game once before running this installer. ", "Could not find game location")).Task; Utils.Log("Exiting because we couldn't find the game folder."); return(false); } if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Validating Game ESMs"); ValidateGameESMs(); if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Validating Modlist"); await ValidateModlist.RunValidation(Queue, ModList); Directory.CreateDirectory(OutputFolder); Directory.CreateDirectory(DownloadFolder); if (Directory.Exists(Path.Combine(OutputFolder, "mods")) && WarnOnOverwrite) { if ((await Utils.Log(new ConfirmUpdateOfExistingInstall { ModListName = ModList.Name, OutputFolder = OutputFolder }).Task) == ConfirmUpdateOfExistingInstall.Choice.Abort) { Utils.Log("Exiting installation at the request of the user, existing mods folder found."); return(false); } } if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Optimizing ModList"); await OptimizeModlist(); if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Hashing Archives"); await HashArchives(); if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Downloading Missing Archives"); await DownloadArchives(); if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Hashing Remaining Archives"); await HashArchives(); var missing = ModList.Archives.Where(a => !HashedArchives.ContainsKey(a.Hash)).ToList(); if (missing.Count > 0) { foreach (var a in missing) { Info($"Unable to download {a.Name}"); } if (IgnoreMissingFiles) { Info("Missing some archives, but continuing anyways at the request of the user"); } else { Error("Cannot continue, was unable to download one or more archives"); } } if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Priming VFS"); await PrimeVFS(); if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Building Folder Structure"); BuildFolderStructure(); if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Installing Archives"); await InstallArchives(); if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Installing Included files"); await InstallIncludedFiles(); if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Installing Archive Metas"); await InstallIncludedDownloadMetas(); if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Building BSAs"); await BuildBSAs(); if (cancel.IsCancellationRequested) { return(false); } UpdateTracker.NextStep("Generating Merges"); await zEditIntegration.GenerateMerges(this); UpdateTracker.NextStep("Set MO2 into portable"); ForcePortable(); UpdateTracker.NextStep("Create Empty Output Mods"); CreateOutputMods(); UpdateTracker.NextStep("Updating System-specific ini settings"); SetScreenSizeInPrefs(); UpdateTracker.NextStep("Installation complete! You may exit the program."); var metric2 = Metrics.Send(Metrics.FinishInstall, ModList.Name); return(true); }
private static void Main(string[] args) { ExceptionlessClient.Default.Startup("IudF6lFjzvdMldPtlYyPmSMHnSEL89n2WmYbCHoy"); SetupNLog(); _logger = LogManager.GetCurrentClassLogger(); _fluentCommandLineParser = new FluentCommandLineParser <ApplicationArguments> { IsCaseSensitive = false }; _fluentCommandLineParser.Setup(arg => arg.File) .As('f') .WithDescription("File to process. Either this or -d is required"); _fluentCommandLineParser.Setup(arg => arg.Directory) .As('d') .WithDescription("Directory to recursively process. Either this or -f is required"); _fluentCommandLineParser.Setup(arg => arg.CsvDirectory) .As("csv") .WithDescription( "Directory to save CSV formatted results to. Be sure to include the full path in double quotes"); _fluentCommandLineParser.Setup(arg => arg.CsvName) .As("csvf") .WithDescription("File name to save CSV formatted results to. When present, overrides default name\r\n"); _fluentCommandLineParser.Setup(arg => arg.Quiet) .As('q') .WithDescription( "Only show the filename being processed vs all output. Useful to speed up exporting to json and/or csv\r\n") .SetDefault(false); _fluentCommandLineParser.Setup(arg => arg.DateTimeFormat) .As("dt") .WithDescription( "The custom date/time format to use when displaying time stamps. See https://goo.gl/CNVq0k for options. Default is: yyyy-MM-dd HH:mm:ss\r\n") .SetDefault(_preciseTimeFormat); _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 = $"RBCmd version {Assembly.GetExecutingAssembly().GetName().Version}" + "\r\n\r\nAuthor: Eric Zimmerman ([email protected])" + "\r\nhttps://github.com/EricZimmerman/RBCmd"; var footer = @"Examples: RBCmd.exe -f ""C:\Temp\INFO2""" + "\r\n\t " + @" RBCmd.exe -f ""C:\Temp\$I3VPA17"" --csv ""D:\csvOutput"" " + "\r\n\t " + @" RBCmd.exe -d ""C:\Temp"" --csv ""c:\temp"" " + "\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("Either -f or -d is required. Exiting"); return; } if (_fluentCommandLineParser.Object.File.IsNullOrEmpty() == false && !File.Exists(_fluentCommandLineParser.Object.File)) { _logger.Warn($"File '{_fluentCommandLineParser.Object.File}' not found. Exiting"); return; } if (_fluentCommandLineParser.Object.Directory.IsNullOrEmpty() == false && !Directory.Exists(_fluentCommandLineParser.Object.Directory)) { _logger.Warn($"Directory '{_fluentCommandLineParser.Object.Directory}' not found. 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) { foreach (var r in LogManager.Configuration.LoggingRules) { r.EnableLoggingForLevel(LogLevel.Debug); } LogManager.ReconfigExistingLoggers(); _logger.Debug("Enabled debug messages..."); } if (_fluentCommandLineParser.Object.Trace) { foreach (var r in LogManager.Configuration.LoggingRules) { r.EnableLoggingForLevel(LogLevel.Trace); } LogManager.ReconfigExistingLoggers(); _logger.Trace("Enabled trace messages..."); } _csvOuts = new List <CsvOut>(); _failedFiles = new List <string>(); var files = new List <string>(); var sw = new Stopwatch(); sw.Start(); if (_fluentCommandLineParser.Object.File?.Length > 0) { files.Add(_fluentCommandLineParser.Object.File); } else { if (_fluentCommandLineParser.Object.Quiet) { _logger.Info(""); } files = GetRecycleBinFiles(_fluentCommandLineParser.Object.Directory); } foreach (var file in files) { ProcessFile(file); } sw.Stop(); _logger.Info( $"Processed {files.Count - _failedFiles.Count:N0} out of {files.Count:N0} files in {sw.Elapsed.TotalSeconds:N4} seconds\r\n"); if (_failedFiles.Count > 0) { _logger.Info(""); _logger.Warn("Failed files"); foreach (var failedFile in _failedFiles) { _logger.Info($" {failedFile}"); } } if (_fluentCommandLineParser.Object.CsvDirectory.IsNullOrEmpty() == false && files.Count > 0) { if (Directory.Exists(_fluentCommandLineParser.Object.CsvDirectory) == false) { _logger.Warn($"'{_fluentCommandLineParser.Object.CsvDirectory} does not exist. Creating...'"); Directory.CreateDirectory(_fluentCommandLineParser.Object.CsvDirectory); } var outName = $"{DateTimeOffset.Now:yyyyMMddHHmmss}_RBCmd_Output.csv"; if (_fluentCommandLineParser.Object.CsvName.IsNullOrEmpty() == false) { outName = Path.GetFileName(_fluentCommandLineParser.Object.CsvName); } var outFile = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outName); _fluentCommandLineParser.Object.CsvDirectory = Path.GetFullPath(outFile); _logger.Warn( $"CSV output will be saved to '{Path.GetFullPath(outFile)}'"); try { var sw1 = new StreamWriter(outFile); var csv = new CsvWriter(sw1, CultureInfo.InvariantCulture); csv.WriteHeader(typeof(CsvOut)); csv.NextRecord(); foreach (var csvOut in _csvOuts) { csv.WriteRecord(csvOut); csv.NextRecord(); } sw1.Flush(); sw1.Close(); } catch (Exception ex) { _logger.Error( $"Unable to open '{outFile}' for writing. CSV export canceled. Error: {ex.Message}"); } } }
private static void DoWork(string d, string f, bool q, string csv, string csvf, string dt, bool debug, bool trace) { ActiveDateTimeFormat = dt; var formatter = new DateTimeOffsetFormatter(CultureInfo.CurrentCulture); var levelSwitch = new LoggingLevelSwitch(); 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 (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("Either -f or -d is required. Exiting"); return; } if (f.IsNullOrEmpty() == false && !File.Exists(f)) { Log.Warning("File {F} not found. Exiting", f); return; } if (d.IsNullOrEmpty() == false && !Directory.Exists(d)) { Log.Warning("Directory {D} not found. Exiting", d); return; } Log.Information("{Header}", Header); Console.WriteLine(); Log.Information("Command line: {Args}", string.Join(" ", Environment.GetCommandLineArgs().Skip(1))); if (IsAdministrator() == false) { Log.Warning("Warning: Administrator privileges not found!"); Console.WriteLine(); } _csvOuts = new List <CsvOut>(); _failedFiles = new List <string>(); var files = new List <string>(); var sw = new Stopwatch(); sw.Start(); if (f?.Length > 0) { files.Add(f); } else { Console.WriteLine(); Log.Information("Looking for files in {Dir}", d); if (!q) { Console.WriteLine(); } files = GetRecycleBinFiles(d); } Log.Information("Found {Count:N0} files. Processing...", files.Count); if (!q) { Console.WriteLine(); } foreach (var file in files) { ProcessFile(file, q, dt); } sw.Stop(); Console.WriteLine(); Log.Information( "Processed {FailedFilesCount:N0} out of {Count:N0} files in {TotalSeconds:N4} seconds", files.Count - _failedFiles.Count, files.Count, sw.Elapsed.TotalSeconds); Console.WriteLine(); if (_failedFiles.Count > 0) { Console.WriteLine(); Log.Information("Failed files"); foreach (var failedFile in _failedFiles) { Log.Information(" {FailedFile}", failedFile); } } if (csv.IsNullOrEmpty() == false && files.Count > 0) { if (Directory.Exists(csv) == false) { Log.Information("{Csv} does not exist. Creating...", csv); Directory.CreateDirectory(csv); } var outName = $"{DateTimeOffset.Now:yyyyMMddHHmmss}_RBCmd_Output.csv"; if (csvf.IsNullOrEmpty() == false) { outName = Path.GetFileName(csvf); } var outFile = Path.Combine(csv, outName); outFile = Path.GetFullPath(outFile); Log.Warning("CSV output will be saved to {Path}", Path.GetFullPath(outFile)); try { var sw1 = new StreamWriter(outFile); var csvWriter = new CsvWriter(sw1, CultureInfo.InvariantCulture); csvWriter.WriteHeader(typeof(CsvOut)); csvWriter.NextRecord(); foreach (var csvOut in _csvOuts) { csvWriter.WriteRecord(csvOut); csvWriter.NextRecord(); } sw1.Flush(); sw1.Close(); } catch (Exception ex) { Log.Error(ex, "Unable to open {OutFile} for writing. CSV export canceled. Error: {Message}", outFile, ex.Message); } } }
private static void Main(string[] args) { ExceptionlessClient.Default.Startup("wPXTiiouhEbK0s19lCgjiDThpfrW0ODU8RskdPEk"); SetupNLog(); _logger = LogManager.GetCurrentClassLogger(); _fluentCommandLineParser = new FluentCommandLineParser <ApplicationArguments> { IsCaseSensitive = false }; _fluentCommandLineParser.Setup(arg => arg.FileDb) .As('f') .WithDescription("SRUDB.dat file to process. Either this or -d is required"); _fluentCommandLineParser.Setup(arg => arg.FileReg) .As('r') .WithDescription("SOFTWARE hive to process. This is optional, but recommended\r\n"); _fluentCommandLineParser.Setup(arg => arg.Directory) .As('d') .WithDescription("Directory to recursively process, looking for SRUDB.dat and SOFTWARE hive. This mode is primarily used with KAPE so both SRUDB.dat and SOFTWARE hive can be located"); _fluentCommandLineParser.Setup(arg => arg.CsvDirectory) .As("csv") .WithDescription( "Directory to save CSV formatted results to. Be sure to include the full path in double quotes\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\r\n") .SetDefault("yyyy-MM-dd HH:mm:ss.fffffff"); _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 = $"SrumECmd version {Assembly.GetExecutingAssembly().GetName().Version}" + "\r\n\r\nAuthor: Eric Zimmerman ([email protected])" + "\r\nhttps://github.com/EricZimmerman/Srum"; var footer = @"Examples: SrumECmd.exe -f ""C:\Temp\SRUDB.dat"" -r ""C:\Temp\SOFTWARE"" --csv ""C:\Temp\"" " + "\r\n\t " + @" SrumECmd.exe -f ""C:\Temp\SRUDB.dat"" --csv ""c:\temp""" + "\r\n\t " + @" SrumECmd.exe -d ""C:\Temp"" --csv ""c:\temp""" + "\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.FileDb.IsNullOrEmpty() && _fluentCommandLineParser.Object.Directory.IsNullOrEmpty()) { _fluentCommandLineParser.HelpOption.ShowHelp(_fluentCommandLineParser.Options); _logger.Warn("Either -f or -d is required. Exiting\r\n"); return; } if (_fluentCommandLineParser.Object.FileDb.IsNullOrEmpty() == false && !File.Exists(_fluentCommandLineParser.Object.FileDb)) { _logger.Warn($"File '{_fluentCommandLineParser.Object.FileDb}' not found. Exiting"); return; } if (_fluentCommandLineParser.Object.Directory.IsNullOrEmpty() == false && !Directory.Exists(_fluentCommandLineParser.Object.Directory)) { _logger.Warn($"Directory '{_fluentCommandLineParser.Object.Directory}' not found. Exiting"); return; } if (_fluentCommandLineParser.Object.CsvDirectory.IsNullOrEmpty()) { _fluentCommandLineParser.HelpOption.ShowHelp(_fluentCommandLineParser.Options); _logger.Warn("--csv is required. Exiting\r\n"); 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; CsvWriter _csvWriter = null; StreamWriter _swCsv = null; Srum sr = null; if (_fluentCommandLineParser.Object.Directory.IsNullOrEmpty() == false) { //kape mode, so find the files var f = new DirectoryEnumerationFilters(); f.InclusionFilter = fsei => { if (fsei.FileSize == 0) { return(false); } if (fsei.FileName.ToUpperInvariant() == "SRUDB.DAT") { return(true); } return(false); }; 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(_fluentCommandLineParser.Object.Directory, dirEnumOptions, f); _fluentCommandLineParser.Object.FileDb = files2.FirstOrDefault(); if (_fluentCommandLineParser.Object.FileDb.IsNullOrEmpty()) { _logger.Warn("Did not locate any files named 'SRUDB.dat'! Exiting"); return; } _logger.Info($"Found SRUM database file '{_fluentCommandLineParser.Object.FileDb}'!"); f = new DirectoryEnumerationFilters(); f.InclusionFilter = fsei => { if (fsei.FileSize == 0) { return(false); } if (fsei.FileName.ToUpperInvariant() == "SOFTWARE") { return(true); } return(false); }; f.RecursionFilter = entryInfo => !entryInfo.IsMountPoint && !entryInfo.IsSymbolicLink; f.ErrorFilter = (errorCode, errorMessage, pathProcessed) => true; files2 = Directory.EnumerateFileSystemEntries(_fluentCommandLineParser.Object.Directory, dirEnumOptions, f); _fluentCommandLineParser.Object.FileReg = files2.FirstOrDefault(); if (_fluentCommandLineParser.Object.FileReg.IsNullOrEmpty()) { _logger.Warn("Did not locate any files named 'SOFTWARE'! Registry data will not be extracted"); } else { _logger.Info($"Found SOFTWARE hive '{_fluentCommandLineParser.Object.FileReg}'!"); } Console.WriteLine(); } try { _logger.Info($"Processing '{_fluentCommandLineParser.Object.FileDb}'..."); sr = new Srum(_fluentCommandLineParser.Object.FileDb, _fluentCommandLineParser.Object.FileReg); _logger.Warn("\r\nProcessing complete!\r\n"); _logger.Info($"{"Energy Usage count:".PadRight(30)} {sr.EnergyUsages.Count:N0}"); _logger.Info($"{"Unknown 312 count:".PadRight(30)} {sr.Unknown312s.Count:N0}"); _logger.Info($"{"Unknown D8F count:".PadRight(30)} {sr.UnknownD8Fs.Count:N0}"); _logger.Info($"{"App Resource Usage count:".PadRight(30)} {sr.AppResourceUseInfos.Count:N0}"); _logger.Info($"{"Network Connection count:".PadRight(30)} {sr.NetworkConnections.Count:N0}"); _logger.Info($"{"Network Usage count:".PadRight(30)} {sr.NetworkUsages.Count:N0}"); _logger.Info($"{"Push Notification count:".PadRight(30)} {sr.PushNotifications.Count:N0}"); Console.WriteLine(); } catch (Exception e) { _logger.Error($"Error processing file! Message: {e.Message}.\r\n\r\nThis almost always means the database is dirty and must be repaired. This can be verified by running 'esentutl.exe /mh SRUDB.dat' and examining the 'State' property"); Console.WriteLine(); _logger.Info("If the database is dirty, **make a copy of your files**, ensure all files in the directory are not Read-only, open a PowerShell session as an admin, and repair by using the following commands (change directories to the location of SRUDB.dat first):\r\n\r\n'esentutl.exe /r sru /i'\r\n'esentutl.exe /p SRUDB.dat'\r\n\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 = string.Empty; var outFile = string.Empty; _logger.Warn($"CSV output will be saved to '{_fluentCommandLineParser.Object.CsvDirectory}'\r\n"); try { _logger.Debug($"Dumping Energy Usage tables '{EnergyUsage.TableName}'"); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_EnergyUsage_Output.csv"; outFile = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outName); _swCsv = new StreamWriter(outFile, false, Encoding.UTF8); _csvWriter = new CsvWriter(_swCsv, CultureInfo.InvariantCulture); var foo = _csvWriter.Configuration.AutoMap <EnergyUsage>(); foo.Map(t => t.Timestamp).ConvertUsing(t => $"{t.Timestamp:yyyy-MM-dd HH:mm:ss}"); foo.Map(t => t.EventTimestamp).ConvertUsing(t => $"{t.EventTimestamp?.ToString(_fluentCommandLineParser.Object.DateTimeFormat)}"); _csvWriter.Configuration.RegisterClassMap(foo); _csvWriter.WriteHeader <EnergyUsage>(); _csvWriter.NextRecord(); _csvWriter.WriteRecords(sr.EnergyUsages.Values); _csvWriter.Flush(); _swCsv.Flush(); } catch (Exception e) { _logger.Error($"Error exporting 'EnergyUsage' data! Error: {e.Message}"); } try { _logger.Debug($"Dumping Unknown 312 table '{Unknown312.TableName}'"); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_Unknown312_Output.csv"; outFile = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outName); _swCsv = new StreamWriter(outFile, false, Encoding.UTF8); _csvWriter = new CsvWriter(_swCsv, CultureInfo.InvariantCulture); var foo = _csvWriter.Configuration.AutoMap <Unknown312>(); foo.Map(t => t.Timestamp).ConvertUsing(t => $"{t.Timestamp:yyyy-MM-dd HH:mm:ss}"); foo.Map(t => t.EndTime).ConvertUsing(t => $"{t.EndTime.ToString(_fluentCommandLineParser.Object.DateTimeFormat)}"); _csvWriter.Configuration.RegisterClassMap(foo); _csvWriter.WriteHeader <Unknown312>(); _csvWriter.NextRecord(); _csvWriter.WriteRecords(sr.Unknown312s.Values); _csvWriter.Flush(); _swCsv.Flush(); } catch (Exception e) { _logger.Error($"Error exporting 'Unknown312' data! Error: {e.Message}"); } try { _logger.Debug($"Dumping Unknown D8F table '{UnknownD8F.TableName}'"); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_UnknownD8F_Output.csv"; outFile = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outName); _swCsv = new StreamWriter(outFile, false, Encoding.UTF8); _csvWriter = new CsvWriter(_swCsv, CultureInfo.InvariantCulture); var foo = _csvWriter.Configuration.AutoMap <UnknownD8F>(); foo.Map(t => t.Timestamp).ConvertUsing(t => $"{t.Timestamp:yyyy-MM-dd HH:mm:ss}"); foo.Map(t => t.EndTime).ConvertUsing(t => $"{t.EndTime.ToString(_fluentCommandLineParser.Object.DateTimeFormat)}"); foo.Map(t => t.StartTime).ConvertUsing(t => $"{t.StartTime.ToString(_fluentCommandLineParser.Object.DateTimeFormat)}"); _csvWriter.Configuration.RegisterClassMap(foo); _csvWriter.WriteHeader <UnknownD8F>(); _csvWriter.NextRecord(); _csvWriter.WriteRecords(sr.UnknownD8Fs.Values); _csvWriter.Flush(); _swCsv.Flush(); } catch (Exception e) { _logger.Error($"Error exporting 'UnknownD8F' data! Error: {e.Message}"); } try { _logger.Debug($"Dumping AppResourceUseInfo table '{AppResourceUseInfo.TableName}'"); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_AppResourceUseInfo_Output.csv"; outFile = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outName); _swCsv = new StreamWriter(outFile, false, Encoding.UTF8); _csvWriter = new CsvWriter(_swCsv, CultureInfo.InvariantCulture); var foo = _csvWriter.Configuration.AutoMap <AppResourceUseInfo>(); foo.Map(t => t.Timestamp).ConvertUsing(t => $"{t.Timestamp:yyyy-MM-dd HH:mm:ss}"); _csvWriter.Configuration.RegisterClassMap(foo); _csvWriter.WriteHeader <AppResourceUseInfo>(); _csvWriter.NextRecord(); _csvWriter.WriteRecords(sr.AppResourceUseInfos.Values); _csvWriter.Flush(); _swCsv.Flush(); } catch (Exception e) { _logger.Error($"Error exporting 'AppResourceUseInfo' data! Error: {e.Message}"); } try { _logger.Debug($"Dumping NetworkConnection table '{NetworkConnection.TableName}'"); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_NetworkConnections_Output.csv"; outFile = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outName); _swCsv = new StreamWriter(outFile, false, Encoding.UTF8); _csvWriter = new CsvWriter(_swCsv, CultureInfo.InvariantCulture); var foo = _csvWriter.Configuration.AutoMap <NetworkConnection>(); foo.Map(t => t.Timestamp).ConvertUsing(t => $"{t.Timestamp:yyyy-MM-dd HH:mm:ss}"); foo.Map(t => t.ConnectStartTime).ConvertUsing(t => $"{t.ConnectStartTime.ToString(_fluentCommandLineParser.Object.DateTimeFormat)}"); _csvWriter.Configuration.RegisterClassMap(foo); _csvWriter.WriteHeader <NetworkConnection>(); _csvWriter.NextRecord(); _csvWriter.WriteRecords(sr.NetworkConnections.Values); _csvWriter.Flush(); _swCsv.Flush(); } catch (Exception e) { _logger.Error($"Error exporting 'NetworkConnection' data! Error: {e.Message}"); } try { _logger.Debug($"Dumping NetworkUsage table '{NetworkUsage.TableName}'"); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_NetworkUsages_Output.csv"; outFile = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outName); _swCsv = new StreamWriter(outFile, false, Encoding.UTF8); _csvWriter = new CsvWriter(_swCsv, CultureInfo.InvariantCulture); var foo = _csvWriter.Configuration.AutoMap <NetworkUsage>(); foo.Map(t => t.Timestamp).ConvertUsing(t => $"{t.Timestamp:yyyy-MM-dd HH:mm:ss}"); _csvWriter.Configuration.RegisterClassMap(foo); _csvWriter.WriteHeader <NetworkUsage>(); _csvWriter.NextRecord(); _csvWriter.WriteRecords(sr.NetworkUsages.Values); _csvWriter.Flush(); _swCsv.Flush(); } catch (Exception e) { _logger.Error($"Error exporting 'NetworkUsage' data! Error: {e.Message}"); } try { _logger.Debug($"Dumping PushNotification table '{PushNotification.TableName}'"); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_PushNotifications_Output.csv"; outFile = Path.Combine(_fluentCommandLineParser.Object.CsvDirectory, outName); _swCsv = new StreamWriter(outFile, false, Encoding.UTF8); _csvWriter = new CsvWriter(_swCsv, CultureInfo.InvariantCulture); var foo = _csvWriter.Configuration.AutoMap <PushNotification>(); foo.Map(t => t.Timestamp).ConvertUsing(t => $"{t.Timestamp:yyyy-MM-dd HH:mm:ss}"); _csvWriter.Configuration.RegisterClassMap(foo); _csvWriter.WriteHeader <PushNotification>(); _csvWriter.NextRecord(); _csvWriter.WriteRecords(sr.PushNotifications.Values); _csvWriter.Flush(); _swCsv.Flush(); } catch (Exception e) { _logger.Error($"Error exporting 'PushNotification' data! Error: {e.Message}"); } sw.Stop(); _logger.Debug(""); _logger.Error( $"Processing completed in {sw.Elapsed.TotalSeconds:N4} seconds\r\n"); } }
private static void DoWork(string f, string r, string d, string csv, string dt, bool debug, bool trace) { var levelSwitch = new LoggingLevelSwitch(); 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) .MinimumLevel.ControlledBy(levelSwitch); Log.Logger = conf.CreateLogger(); if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Console.WriteLine(); Log.Fatal("Non-Windows platforms not supported due to the need to load ESI specific Windows libraries! Exiting..."); Console.WriteLine(); Environment.Exit(0); return; } 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("Either -f or -d is required. Exiting\r\n"); return; } if (f.IsNullOrEmpty() == false && !File.Exists(f)) { Log.Warning("File '{File}' not found. Exiting", f); return; } if (d.IsNullOrEmpty() == false && !Directory.Exists(d)) { Log.Warning("Directory '{D}' not found. Exiting", d); return; } if (csv.IsNullOrEmpty()) { var helpBld = new HelpBuilder(LocalizationResources.Instance, Console.WindowWidth); var hc = new HelpContext(helpBld, _rootCommand, Console.Out); helpBld.Write(hc); Log.Warning("--csv is required. Exiting\r\n"); return; } Log.Information("{Header}", Header); Console.WriteLine(); Log.Information("Command line: {Args}\r\n", string.Join(" ", _args)); if (IsAdministrator() == false) { Log.Warning("Warning: Administrator privileges not found!\r\n"); } var sw = new Stopwatch(); sw.Start(); var ts = DateTimeOffset.UtcNow; Srum sr = null; if (d.IsNullOrEmpty() == false) { IEnumerable <string> files2; #if NET6_0 var enumerationOptions = new EnumerationOptions { IgnoreInaccessible = true, MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = true, AttributesToSkip = 0 }; files2 = Directory.EnumerateFileSystemEntries(d, "SRUDB.DAT", enumerationOptions); f = files2.FirstOrDefault(); if (f.IsNullOrEmpty()) { Log.Warning("Did not locate any files named 'SRUDB.dat'! Exiting"); return; } Log.Information("Found SRUM database file '{F}'!", f); files2 = Directory.EnumerateFileSystemEntries(d, "SOFTWARE", enumerationOptions); r = files2.FirstOrDefault(); if (r.IsNullOrEmpty()) { Log.Warning("Did not locate any files named 'SOFTWARE'! Registry data will not be extracted"); } else { Log.Information("Found SOFTWARE hive '{R}'!", r); } #elif NET462 //kape mode, so find the files var ilter = new DirectoryEnumerationFilters(); ilter.InclusionFilter = fsei => { if (fsei.FileSize == 0) { return(false); } if (fsei.FileName.ToUpperInvariant() == "SRUDB.DAT") { return(true); } return(false); }; ilter.RecursionFilter = entryInfo => !entryInfo.IsMountPoint && !entryInfo.IsSymbolicLink; ilter.ErrorFilter = (errorCode, errorMessage, pathProcessed) => true; const DirectoryEnumerationOptions dirEnumOptions = DirectoryEnumerationOptions.Files | DirectoryEnumerationOptions.Recursive | DirectoryEnumerationOptions.SkipReparsePoints | DirectoryEnumerationOptions.ContinueOnException | DirectoryEnumerationOptions.BasicSearch; files2 = Directory.EnumerateFileSystemEntries(d, dirEnumOptions, ilter); f = files2.FirstOrDefault(); if (f.IsNullOrEmpty()) { Log.Warning("Did not locate any files named 'SRUDB.dat'! Exiting"); return; } Log.Information("Found SRUM database file '{F}'!", f); ilter = new DirectoryEnumerationFilters(); ilter.InclusionFilter = fsei => { if (fsei.FileSize == 0) { return(false); } if (fsei.FileName.ToUpperInvariant() == "SOFTWARE") { return(true); } return(false); }; ilter.RecursionFilter = entryInfo => !entryInfo.IsMountPoint && !entryInfo.IsSymbolicLink; ilter.ErrorFilter = (errorCode, errorMessage, pathProcessed) => true; files2 = Directory.EnumerateFileSystemEntries(d, dirEnumOptions, ilter); r = files2.FirstOrDefault(); if (r.IsNullOrEmpty()) { Log.Warning("Did not locate any files named 'SOFTWARE'! Registry data will not be extracted"); } else { Log.Information("Found SOFTWARE hive '{R}'!", r); } #endif Console.WriteLine(); } try { Log.Information("Processing '{F}'...", f); sr = new Srum(f, r); Console.WriteLine(); Log.Information("Processing complete!"); Console.WriteLine(); Log.Information("{EnergyUse} {EnergyUsagesCount:N0}", "Energy Usage count:".PadRight(30), sr.EnergyUsages.Count); Log.Information("{Unknown312s} {Unknown312sCount:N0}", "Unknown 312 count:".PadRight(30), sr.TimelineProviders.Count); Log.Information("{UnknownD8Fs} {UnknownD8FsCount:N0}", "Unknown D8F count:".PadRight(30), sr.Vfuprovs.Count); Log.Information("{AppResourceUseInfos} {AppResourceUseInfosCount:N0}", "App Resource Usage count:".PadRight(30), sr.AppResourceUseInfos.Count); Log.Information("{NetworkConnections} {NetworkConnectionsCount:N0}", "Network Connection count:".PadRight(30), sr.NetworkConnections.Count); Log.Information("{NetworkUsages} {NetworkUsagesCount}", "Network Usage count:".PadRight(30), sr.NetworkUsages.Count); Log.Information("{PushNotifications} {PushNotificationsCount:N0}", "Push Notification count:".PadRight(30), sr.PushNotifications.Count); Console.WriteLine(); } catch (Exception e) { Log.Error(e, "Error processing file! Message: {Message}.\r\n\r\nThis almost always means the database is dirty and must be repaired. This can be verified by running 'esentutl.exe /mh SRUDB.dat' and examining the 'State' property", e.Message); Console.WriteLine(); Log.Information( "If the database is dirty, **make a copy of your files**, ensure all files in the directory are not Read-only, open a PowerShell session as an admin, and repair by using the following commands (change directories to the location of SRUDB.dat first):\r\n\r\n'esentutl.exe /r sru /i'\r\n'esentutl.exe /p SRUDB.dat'\r\n\r\n"); Environment.Exit(0); } 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) { Log.Fatal( "Unable to create directory '{Csv}'. Does a file with the same name exist? Exiting", csv); return; } } string outName; string outFile; Log.Information("CSV output will be saved to '{Csv}'\r\n", csv); StreamWriter swCsv; CsvWriter csvWriter; try { Log.Debug("Dumping Energy Usage tables '{TableName}'", EnergyUsage.TableName); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_EnergyUsage_Output.csv"; outFile = Path.Combine(csv, outName); swCsv = new StreamWriter(outFile, false, Encoding.UTF8); csvWriter = new CsvWriter(swCsv, CultureInfo.InvariantCulture); var foo = csvWriter.Context.AutoMap <EnergyUsage>(); foo.Map(t => t.Timestamp).Convert(t => $"{t.Value.Timestamp:yyyy-MM-dd HH:mm:ss}"); foo.Map(t => t.EventTimestamp).Convert(t => $"{t.Value.EventTimestamp?.ToString(dt)}"); csvWriter.Context.RegisterClassMap(foo); csvWriter.WriteHeader <EnergyUsage>(); csvWriter.NextRecord(); csvWriter.WriteRecords(sr.EnergyUsages.Values); csvWriter.Flush(); swCsv.Flush(); } catch (Exception e) { Log.Error(e, "Error exporting 'EnergyUsage' data! Error: {Message}", e.Message); } try { Log.Debug("Dumping Unknown 312 table '{TableName}'", TimelineProvider.TableName); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_Unknown312_Output.csv"; outFile = Path.Combine(csv, outName); swCsv = new StreamWriter(outFile, false, Encoding.UTF8); csvWriter = new CsvWriter(swCsv, CultureInfo.InvariantCulture); var foo = csvWriter.Context.AutoMap <TimelineProvider>(); foo.Map(t => t.Timestamp).Convert(t => $"{t.Value.Timestamp:yyyy-MM-dd HH:mm:ss}"); foo.Map(t => t.EndTime).Convert(t => $"{t.Value.EndTime.ToString(dt)}"); csvWriter.Context.RegisterClassMap(foo); csvWriter.WriteHeader <TimelineProvider>(); csvWriter.NextRecord(); csvWriter.WriteRecords(sr.TimelineProviders.Values); csvWriter.Flush(); swCsv.Flush(); } catch (Exception e) { Log.Error(e, "Error exporting 'Unknown312' data! Error: {Message}", e.Message); } try { Log.Debug("Dumping Unknown D8F table '{TableName}'", Vfuprov.TableName); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_UnknownD8F_Output.csv"; outFile = Path.Combine(csv, outName); swCsv = new StreamWriter(outFile, false, Encoding.UTF8); csvWriter = new CsvWriter(swCsv, CultureInfo.InvariantCulture); var foo = csvWriter.Context.AutoMap <Vfuprov>(); foo.Map(t => t.Timestamp).Convert(t => $"{t.Value.Timestamp:yyyy-MM-dd HH:mm:ss}"); foo.Map(t => t.EndTime).Convert(t => $"{t.Value.EndTime.ToString(dt)}"); foo.Map(t => t.StartTime).Convert(t => $"{t.Value.StartTime.ToString(dt)}"); csvWriter.Context.RegisterClassMap(foo); csvWriter.WriteHeader <Vfuprov>(); csvWriter.NextRecord(); csvWriter.WriteRecords(sr.Vfuprovs.Values); csvWriter.Flush(); swCsv.Flush(); } catch (Exception e) { Log.Error(e, "Error exporting 'UnknownD8F' data! Error: {Message}", e.Message); } try { Log.Debug("Dumping App Resource Use Info table '{TableName}'", AppResourceUseInfo.TableName); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_AppResourceUseInfo_Output.csv"; outFile = Path.Combine(csv, outName); swCsv = new StreamWriter(outFile, false, Encoding.UTF8); csvWriter = new CsvWriter(swCsv, CultureInfo.InvariantCulture); var foo = csvWriter.Context.AutoMap <AppResourceUseInfo>(); foo.Map(t => t.Timestamp).Convert(t => $"{t.Value.Timestamp:yyyy-MM-dd HH:mm:ss}"); csvWriter.Context.RegisterClassMap(foo); csvWriter.WriteHeader <AppResourceUseInfo>(); csvWriter.NextRecord(); csvWriter.WriteRecords(sr.AppResourceUseInfos.Values); csvWriter.Flush(); swCsv.Flush(); } catch (Exception e) { Log.Error(e, "Error exporting 'AppResourceUseInfo' data! Error: {Message}", e.Message); } try { Log.Debug("Dumping Network Connection table '{TableName}'", NetworkConnection.TableName); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_NetworkConnections_Output.csv"; outFile = Path.Combine(csv, outName); swCsv = new StreamWriter(outFile, false, Encoding.UTF8); csvWriter = new CsvWriter(swCsv, CultureInfo.InvariantCulture); var foo = csvWriter.Context.AutoMap <NetworkConnection>(); foo.Map(t => t.Timestamp).Convert(t => $"{t.Value.Timestamp:yyyy-MM-dd HH:mm:ss}"); foo.Map(t => t.ConnectStartTime).Convert(t => $"{t.Value.ConnectStartTime.ToString(dt)}"); csvWriter.Context.RegisterClassMap(foo); csvWriter.WriteHeader <NetworkConnection>(); csvWriter.NextRecord(); csvWriter.WriteRecords(sr.NetworkConnections.Values); csvWriter.Flush(); swCsv.Flush(); } catch (Exception e) { Log.Error(e, "Error exporting 'NetworkConnection' data! Error: {Message}", e.Message); } try { Log.Debug("Dumping Network Usage table '{TableName}'", NetworkUsage.TableName); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_NetworkUsages_Output.csv"; outFile = Path.Combine(csv, outName); swCsv = new StreamWriter(outFile, false, Encoding.UTF8); csvWriter = new CsvWriter(swCsv, CultureInfo.InvariantCulture); var foo = csvWriter.Context.AutoMap <NetworkUsage>(); foo.Map(t => t.Timestamp).Convert(t => $"{t.Value.Timestamp:yyyy-MM-dd HH:mm:ss}"); csvWriter.Context.RegisterClassMap(foo); csvWriter.WriteHeader <NetworkUsage>(); csvWriter.NextRecord(); csvWriter.WriteRecords(sr.NetworkUsages.Values); csvWriter.Flush(); swCsv.Flush(); } catch (Exception e) { Log.Error(e, "Error exporting 'NetworkUsage' data! Error: {Message}", e.Message); } try { Log.Debug("Dumping Push Notification table '{TableName}'", PushNotification.TableName); outName = $"{ts:yyyyMMddHHmmss}_SrumECmd_PushNotifications_Output.csv"; outFile = Path.Combine(csv, outName); swCsv = new StreamWriter(outFile, false, Encoding.UTF8); csvWriter = new CsvWriter(swCsv, CultureInfo.InvariantCulture); var foo = csvWriter.Context.AutoMap <PushNotification>(); foo.Map(t => t.Timestamp).Convert(t => $"{t.Value.Timestamp:yyyy-MM-dd HH:mm:ss}"); csvWriter.Context.RegisterClassMap(foo); csvWriter.WriteHeader <PushNotification>(); csvWriter.NextRecord(); csvWriter.WriteRecords(sr.PushNotifications.Values); csvWriter.Flush(); swCsv.Flush(); } catch (Exception e) { Log.Error(e, "Error exporting 'PushNotification' data! Error: {Message}", e.Message); } sw.Stop(); Log.Information("Processing completed in {TotalSeconds:N4} seconds\r\n", sw.Elapsed.TotalSeconds); } }
private static void Main(string[] args) { ExceptionlessClient.Default.Startup("Kruacm8p1B6RFAw2WMnKcEqkQcnWRkF3RmPSOzlW"); SetupNLog(); SetupPatterns(); _logger = LogManager.GetCurrentClassLogger(); _fluentCommandLineParser = new FluentCommandLineParser <ApplicationArguments> { IsCaseSensitive = false }; _fluentCommandLineParser.Setup(arg => arg.File) .As('f') .WithDescription("File to search. Either this or -d is required"); _fluentCommandLineParser.Setup(arg => arg.Directory) .As('d') .WithDescription("Directory to recursively process. Either this or -f is required"); _fluentCommandLineParser.Setup(arg => arg.SaveTo) .As('o') .WithDescription("File to save results to"); _fluentCommandLineParser.Setup(arg => arg.GetAscii) .As('a') .SetDefault(true) .WithDescription("If set, look for ASCII strings. Default is true. Use -a false to disable"); _fluentCommandLineParser.Setup(arg => arg.GetUnicode) .As('u') .SetDefault(true) .WithDescription("If set, look for Unicode strings. Default is true. Use -u false to disable"); _fluentCommandLineParser.Setup(arg => arg.MinimumLength) .As('m').SetDefault(3).WithDescription("Minimum string length. Default is 3"); _fluentCommandLineParser.Setup(arg => arg.BlockSizeMb) .As('b').SetDefault(512).WithDescription("Chunk size in MB. Valid range is 1 to 1024. Default is 512"); _fluentCommandLineParser.Setup(arg => arg.Quiet) .As('q').SetDefault(false).WithDescription("Quiet mode (Do not show header or total number of hits)"); _fluentCommandLineParser.Setup(arg => arg.QuietQuiet) .As('s') .SetDefault(false) .WithDescription( "Really Quiet mode (Do not display hits to console. Speeds up processing when using -o)"); _fluentCommandLineParser.Setup(arg => arg.MaximumLength) .As('x').SetDefault(-1).WithDescription("Maximum string length. Default is unlimited\r\n"); _fluentCommandLineParser.Setup(arg => arg.GetPatterns) .As('p').SetDefault(false).WithDescription("Display list of built in regular expressions"); _fluentCommandLineParser.Setup(arg => arg.LookForString) .As("ls") .SetDefault(string.Empty) .WithDescription("String to look for. When set, only matching strings are returned"); _fluentCommandLineParser.Setup(arg => arg.LookForRegex) .As("lr") .SetDefault(string.Empty) .WithDescription("Regex to look for. When set, only strings matching the regex are returned"); _fluentCommandLineParser.Setup(arg => arg.StringFile) .As("fs") .SetDefault(string.Empty) .WithDescription("File containing strings to look for. When set, only matching strings are returned"); _fluentCommandLineParser.Setup(arg => arg.RegexFile) .As("fr") .SetDefault(string.Empty) .WithDescription( "File containing regex patterns to look for. When set, only strings matching regex patterns are returned\r\n"); _fluentCommandLineParser.Setup(arg => arg.AsciiRange) .As("ar") .SetDefault("[\x20-\x7E]") .WithDescription( @"Range of characters to search for in 'Code page' strings. Specify as a range of characters in hex format and enclose in quotes. Default is [\x20 -\x7E]"); _fluentCommandLineParser.Setup(arg => arg.UnicodeRange) .As("ur") .SetDefault("[\u0020-\u007E]") .WithDescription( "Range of characters to search for in Unicode strings. Specify as a range of characters in hex format and enclose in quotes. Default is [\\u0020-\\u007E]\r\n"); _fluentCommandLineParser.Setup(arg => arg.CodePage) .As("cp") .SetDefault(1252) .WithDescription( "Code page to use. Default is 1252. Use the Identifier value for code pages at https://goo.gl/ig6DxW"); _fluentCommandLineParser.Setup(arg => arg.FileMask) .As("mask") .SetDefault(string.Empty) .WithDescription( "When using -d, file mask to search for. * and ? are supported. This option has no effect when using -f"); _fluentCommandLineParser.Setup(arg => arg.RegexOnly) .As("ro") .SetDefault(false) .WithDescription( "When true, list the string matched by regex pattern vs string the pattern was found in (This may result in duplicate strings in output. ~ denotes approx. offset)"); _fluentCommandLineParser.Setup(arg => arg.ShowOffset) .As("off") .SetDefault(false) .WithDescription( $"Show offset to hit after string, followed by the encoding (A={_fluentCommandLineParser.Object.CodePage}, U=Unicode)\r\n"); _fluentCommandLineParser.Setup(arg => arg.SortAlpha) .As("sa").SetDefault(false).WithDescription("Sort results alphabetically"); _fluentCommandLineParser.Setup(arg => arg.SortLength) .As("sl").SetDefault(false).WithDescription("Sort results by length"); var header = $"bstrings version {Assembly.GetExecutingAssembly().GetName().Version}" + "\r\n\r\nAuthor: Eric Zimmerman ([email protected])" + "\r\nhttps://github.com/EricZimmerman/bstrings"; var footer = @"Examples: bstrings.exe -f ""C:\Temp\UsrClass 1.dat"" --ls URL" + "\r\n\t " + @" bstrings.exe -f ""C:\Temp\someFile.txt"" --lr guid" + "\r\n\t " + @" bstrings.exe -f ""C:\Temp\aBigFile.bin"" --fs c:\temp\searchStrings.txt --fr c:\temp\searchRegex.txt -s" + "\r\n\t " + @" bstrings.exe -d ""C:\Temp"" --mask ""*.dll""" + "\r\n\t " + @" bstrings.exe -d ""C:\Temp"" --ar ""[\x20-\x37]""" + "\r\n\t " + @" bstrings.exe -d ""C:\Temp"" --cp 10007" + "\r\n\t " + @" bstrings.exe -d ""C:\Temp"" --ls test" + "\r\n\t " + @" bstrings.exe -f ""C:\Temp\someOtherFile.txt"" --lr cc -sa" + "\r\n\t " + @" bstrings.exe -f ""C:\Temp\someOtherFile.txt"" --lr cc -sa -m 15 -x 22" + "\r\n\t " + @" bstrings.exe -f ""C:\Temp\UsrClass 1.dat"" --ls mui -sl" + "\r\n\t "; _fluentCommandLineParser.SetupHelp("?", "help") .WithHeader(header) .Callback(text => _logger.Info(text + "\r\n" + footer)); var result = _fluentCommandLineParser.Parse(args); if (result.HelpCalled) { return; } if (_fluentCommandLineParser.Object.GetPatterns) { _logger.Warn("Name \t\tDescription"); foreach (var regExPattern in RegExPatterns.OrderBy(t => t.Key)) { var desc = RegExDesc[regExPattern.Key]; _logger.Info($"{regExPattern.Key}\t{desc}"); } _logger.Info(""); _logger.Info("To use a built in pattern, supply the Name to the --lr switch\r\n"); 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("Either -f or -d is required. Exiting"); return; } if (_fluentCommandLineParser.Object.File.IsNullOrEmpty() == false && !File.Exists(_fluentCommandLineParser.Object.File) && _fluentCommandLineParser.Object.FileMask.Length == 0) { _logger.Warn($"File '{_fluentCommandLineParser.Object.File}' not found. Exiting"); return; } if (_fluentCommandLineParser.Object.Directory.IsNullOrEmpty() == false && !Directory.Exists(_fluentCommandLineParser.Object.Directory) && _fluentCommandLineParser.Object.FileMask.Length == 0) { _logger.Warn($"Directory '{_fluentCommandLineParser.Object.Directory}' not found. Exiting"); return; } if (!_fluentCommandLineParser.Object.Quiet) { _logger.Info(header); _logger.Info(""); } var files = new List <string>(); if (_fluentCommandLineParser.Object.File.IsNullOrEmpty() == false) { files.Add(Path.GetFullPath(_fluentCommandLineParser.Object.File)); } else { try { if (_fluentCommandLineParser.Object.FileMask.Length > 0) { files.AddRange(Directory.EnumerateFiles(Path.GetFullPath(_fluentCommandLineParser.Object.Directory), _fluentCommandLineParser.Object.FileMask, SearchOption.AllDirectories)); } else { files.AddRange(Directory.EnumerateFiles(Path.GetFullPath(_fluentCommandLineParser.Object.Directory), "*", SearchOption.AllDirectories)); } } catch (Exception ex) { _logger.Error( $"Error getting files in '{_fluentCommandLineParser.Object.Directory}'. Error message: {ex.Message}"); return; } } if (!_fluentCommandLineParser.Object.Quiet) { _logger.Info($"Command line: {string.Join(" ", args)}"); _logger.Info(""); } StreamWriter sw = null; var globalCounter = 0; var globalHits = 0; double globalTimespan = 0; var withBoundaryHits = false; if (_fluentCommandLineParser.Object.SaveTo.IsNullOrEmpty() == false && _fluentCommandLineParser.Object.SaveTo.Length > 0) { _fluentCommandLineParser.Object.SaveTo = _fluentCommandLineParser.Object.SaveTo.TrimEnd('\\'); var dir = Path.GetDirectoryName(_fluentCommandLineParser.Object.SaveTo); if (dir != null && Directory.Exists(dir) == false) { try { Directory.CreateDirectory(dir); } catch (Exception) { _logger.Warn( $"Invalid path: '{_fluentCommandLineParser.Object.SaveTo}'. Results will not be saved to a file."); _logger.Info(""); _fluentCommandLineParser.Object.SaveTo = string.Empty; } } else { if (dir == null) { _logger.Warn($"Invalid path: '{_fluentCommandLineParser.Object.SaveTo}"); _fluentCommandLineParser.Object.SaveTo = string.Empty; } } if (_fluentCommandLineParser.Object.SaveTo.Length > 0 && !_fluentCommandLineParser.Object.Quiet) { _logger.Info($"Saving hits to '{_fluentCommandLineParser.Object.SaveTo}'"); _logger.Info(""); } if (_fluentCommandLineParser.Object.SaveTo.Length > 0) { // try // { // File.Create(_fluentCommandLineParser.Object.SaveTo); // } // catch (Exception e) // { // _logger.Fatal($"Unable to create output file '{_fluentCommandLineParser.Object.SaveTo}'! Check permissions and try again! Error: {e.Message}"); // return; // } sw = new StreamWriter(_fluentCommandLineParser.Object.SaveTo, true); } } foreach (var file in files) { if (File.Exists(file) == false) { _logger.Warn($"'{file}' does not exist! Skipping"); } _sw = new Stopwatch(); _sw.Start(); var counter = 0; var hits = new HashSet <string>(); var regPattern = _fluentCommandLineParser.Object.LookForRegex; if (RegExPatterns.ContainsKey(_fluentCommandLineParser.Object.LookForRegex)) { regPattern = RegExPatterns[_fluentCommandLineParser.Object.LookForRegex]; } if (regPattern.Length > 0 && !_fluentCommandLineParser.Object.Quiet) { _logger.Info($"Searching via RegEx pattern: {regPattern}"); _logger.Info(""); } var minLength = 3; if (_fluentCommandLineParser.Object.MinimumLength > 0) { minLength = _fluentCommandLineParser.Object.MinimumLength; } var maxLength = -1; if (_fluentCommandLineParser.Object.MaximumLength > minLength) { maxLength = _fluentCommandLineParser.Object.MaximumLength; } var chunkSizeMb = _fluentCommandLineParser.Object.BlockSizeMb < 1 || _fluentCommandLineParser.Object.BlockSizeMb > 1024 ? 512 : _fluentCommandLineParser.Object.BlockSizeMb; var chunkSizeBytes = chunkSizeMb * 1024 * 1024; var fileSizeBytes = new FileInfo(file).Length; var bytesRemaining = fileSizeBytes; long offset = 0; var chunkIndex = 1; var totalChunks = fileSizeBytes / chunkSizeBytes + 1; var hsuffix = totalChunks == 1 ? "" : "s"; if (!_fluentCommandLineParser.Object.Quiet) { _logger.Info( $"Searching {totalChunks:N0} chunk{hsuffix} ({chunkSizeMb} MB each) across {GetSizeReadable(fileSizeBytes)} in '{file}'"); _logger.Info(""); } try { MappedStream ms = null; try { var fs = File.Open(File.GetFileSystemEntryInfo(file).LongFullPath, FileMode.Open, FileAccess.Read, FileShare.Read, PathFormat.LongFullPath); ms = MappedStream.FromStream(fs, Ownership.None); } catch (Exception) { _logger.Warn($"Unable to open file directly. This usually means the file is in use. Switching to raw access\r\n"); } if (ms == null) { //raw mode var ss = OpenFile(file); ms = MappedStream.FromStream(ss, Ownership.None); } using (ms) { while (bytesRemaining > 0) { if (bytesRemaining <= chunkSizeBytes) { chunkSizeBytes = (int)bytesRemaining; } var chunk = new byte[chunkSizeBytes]; ms.Read(chunk, 0, chunkSizeBytes); if (_fluentCommandLineParser.Object.GetUnicode) { var uh = GetUnicodeHits(chunk, minLength, maxLength, offset, _fluentCommandLineParser.Object.ShowOffset); foreach (var h in uh) { hits.Add(h); } } if (_fluentCommandLineParser.Object.GetAscii) { var ah = GetAsciiHits(chunk, minLength, maxLength, offset, _fluentCommandLineParser.Object.ShowOffset); foreach (var h in ah) { hits.Add(h); } } offset += chunkSizeBytes; bytesRemaining -= chunkSizeBytes; if (!_fluentCommandLineParser.Object.Quiet) { _logger.Info( $"Chunk {chunkIndex:N0} of {totalChunks:N0} finished. Total strings so far: {hits.Count:N0} Elapsed time: {_sw.Elapsed.TotalSeconds:N3} seconds. Average strings/sec: {hits.Count/_sw.Elapsed.TotalSeconds:N0}"); } chunkIndex += 1; } //do chunk boundary checks to make sure we get everything and not split things if (!_fluentCommandLineParser.Object.Quiet) { _logger.Info( "Primary search complete. Looking for strings across chunk boundaries..."); } bytesRemaining = fileSizeBytes; chunkSizeBytes = chunkSizeMb * 1024 * 1024; offset = chunkSizeBytes - _fluentCommandLineParser.Object.MinimumLength * 10 * 2; //move starting point backwards for our starting point chunkIndex = 0; var boundaryChunkSize = _fluentCommandLineParser.Object.MinimumLength * 10 * 2 * 2; //grab the same # of bytes on both sides of the boundary while (bytesRemaining > 0) { if (offset + boundaryChunkSize > fileSizeBytes) { break; } var chunk = new byte[boundaryChunkSize]; ms.Read(chunk, 0, boundaryChunkSize); if (_fluentCommandLineParser.Object.GetUnicode) { var uh = GetUnicodeHits(chunk, minLength, maxLength, offset, _fluentCommandLineParser.Object.ShowOffset); foreach (var h in uh) { hits.Add(" " + h); } if (withBoundaryHits == false && uh.Count > 0) { withBoundaryHits = uh.Count > 0; } } if (_fluentCommandLineParser.Object.GetAscii) { var ah = GetAsciiHits(chunk, minLength, maxLength, offset, _fluentCommandLineParser.Object.ShowOffset); foreach (var h in ah) { hits.Add(" " + h); } if (withBoundaryHits == false && ah.Count > 0) { withBoundaryHits = true; } } offset += chunkSizeBytes; bytesRemaining -= chunkSizeBytes; chunkIndex += 1; } } } catch (Exception ex) { _logger.Info(""); _logger.Error($"Error: {ex.Message}"); } _sw.Stop(); if (!_fluentCommandLineParser.Object.Quiet) { _logger.Info("Search complete."); _logger.Info(""); } if (_fluentCommandLineParser.Object.SortAlpha) { _logger.Info("Sorting alphabetically..."); _logger.Info(""); var tempList = hits.ToList(); tempList.Sort(); hits = new HashSet <string>(tempList); } else if (_fluentCommandLineParser.Object.SortLength) { _logger.Info("Sorting by length..."); _logger.Info(""); var tempList = SortByLength(hits.ToList()).ToList(); hits = new HashSet <string>(tempList); } var fileStrings = new HashSet <string>(); var regexStrings = new HashSet <string>(); //set up highlighting if (_fluentCommandLineParser.Object.LookForString.Length > 0) { fileStrings.Add(_fluentCommandLineParser.Object.LookForString); } if (_fluentCommandLineParser.Object.LookForRegex.Length > 0) { regexStrings.Add(regPattern); } if (_fluentCommandLineParser.Object.StringFile.IsNullOrEmpty() == false || _fluentCommandLineParser.Object.RegexFile.IsNullOrEmpty() == false) { if (_fluentCommandLineParser.Object.StringFile.Length > 0) { if (File.Exists(_fluentCommandLineParser.Object.StringFile)) { fileStrings.UnionWith(new HashSet <string>(File.ReadAllLines(_fluentCommandLineParser.Object.StringFile))); } else { _logger.Error($"Strings file '{_fluentCommandLineParser.Object.StringFile}' not found."); } } if (_fluentCommandLineParser.Object.RegexFile.Length > 0) { if (File.Exists(_fluentCommandLineParser.Object.RegexFile)) { regexStrings.UnionWith(new HashSet <string>(File.ReadAllLines(_fluentCommandLineParser.Object.RegexFile))); } else { _logger.Error($"Regex file '{_fluentCommandLineParser.Object.RegexFile}' not found."); } } } AddHighlightingRules(fileStrings.ToList()); if (_fluentCommandLineParser.Object.RegexOnly == false) { AddHighlightingRules(regexStrings.ToList(), true); } if (!_fluentCommandLineParser.Object.Quiet) { _logger.Info("Processing strings..."); _logger.Info(""); } foreach (var hit in hits) { if (hit.Length == 0) { continue; } if (fileStrings.Count > 0 || regexStrings.Count > 0) { foreach (var fileString in fileStrings) { if (fileString.Trim().Length == 0) { continue; } if (hit.IndexOf(fileString, StringComparison.InvariantCultureIgnoreCase) < 0) { continue; } counter += 1; if (_fluentCommandLineParser.Object.QuietQuiet == false) { _logger.Info(hit); } sw?.WriteLine(hit); } var hitoffset = ""; if (_fluentCommandLineParser.Object.ShowOffset) { hitoffset = $"~{hit.Split('\t').Last()}"; } foreach (var regString in regexStrings) { if (regString.Trim().Length == 0) { continue; } try { var reg1 = new Regex(regString, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); if (reg1.IsMatch(hit) == false) { continue; } counter += 1; if (_fluentCommandLineParser.Object.RegexOnly) { foreach (var match in reg1.Matches(hit)) { if (_fluentCommandLineParser.Object.QuietQuiet == false) { _logger.Info($"{match}\t{hitoffset}"); } sw?.WriteLine($"{match}\t{hitoffset}"); } } else { if (_fluentCommandLineParser.Object.QuietQuiet == false) { _logger.Info(hit); } sw?.WriteLine(hit); } } catch (Exception ex) { _logger.Error($"Error setting up regular expression '{regString}': {ex.Message}"); } } } else { //dump all strings counter += 1; if (_fluentCommandLineParser.Object.QuietQuiet == false) { _logger.Info(hit); } sw?.WriteLine(hit); } } if (_fluentCommandLineParser.Object.Quiet) { continue; } var suffix = counter == 1 ? "" : "s"; _logger.Info(""); if (withBoundaryHits) { _logger.Info("** Strings prefixed with 2 spaces are hits found across chunk boundaries **"); _logger.Info(""); } _logger.Info( $"Found {counter:N0} string{suffix} in {_sw.Elapsed.TotalSeconds:N3} seconds. Average strings/sec: {hits.Count/_sw.Elapsed.TotalSeconds:N0}"); globalCounter += counter; globalHits += hits.Count; globalTimespan += _sw.Elapsed.TotalSeconds; if (files.Count > 1) { _logger.Info( "-------------------------------------------------------------------------------------\r\n"); } } if (sw != null) { sw.Flush(); sw.Close(); } if (!_fluentCommandLineParser.Object.Quiet && files.Count > 1) { var suffix = globalCounter == 1 ? "" : "s"; _logger.Info(""); _logger.Info( $"Found {globalCounter:N0} string{suffix} in {globalTimespan:N3} seconds. Average strings/sec: {globalHits/globalTimespan:N0}"); } }
protected override async Task <int> Run() { if (!File.Exists(Modlist)) { Log($"The file {Modlist} does not exist!"); return(-1); } if (!Directory.Exists(Input)) { Log($"The input directory {Input} does not exist!"); return(-1); } if (!Directory.Exists(Output)) { Log($"The output directory {Output} does not exist, it will be created."); Directory.CreateDirectory(Output); } if (!Modlist.EndsWith(Consts.ModListExtension) && !Modlist.EndsWith("modlist.txt")) { Log($"The file {Modlist} is not a valid modlist file!"); return(-1); } if (Copy && Move) { Log("You can't set both copy and move flags!"); return(-1); } var isModlist = Modlist.EndsWith(Consts.ModListExtension); var list = new List <TransferFile>(); if (isModlist) { ModList modlist; try { modlist = AInstaller.LoadFromFile(Modlist); } catch (Exception e) { Log($"Error while loading the Modlist!\n{e}"); return(1); } if (modlist == null) { Log("The Modlist could not be loaded!"); return(1); } Log($"Modlist contains {modlist.Archives.Count} archives."); modlist.Archives.Do(a => { var inputPath = Path.Combine(Input, a.Name); var outputPath = Path.Combine(Output, a.Name); if (!File.Exists(inputPath)) { Log($"File {inputPath} does not exist, skipping."); return; } Log($"Adding {inputPath} to the transfer list."); list.Add(new TransferFile(inputPath, outputPath)); var metaInputPath = Path.Combine(inputPath, ".meta"); var metaOutputPath = Path.Combine(outputPath, ".meta"); if (File.Exists(metaInputPath)) { Log($"Found meta file {metaInputPath}"); if (IncludeMeta) { Log($"Adding {metaInputPath} to the transfer list."); list.Add(new TransferFile(metaInputPath, metaOutputPath)); } else { Log($"Meta file {metaInputPath} will be ignored."); } } else { Log($"Found no meta file for {inputPath}"); if (IncludeMeta) { if (string.IsNullOrWhiteSpace(a.Meta)) { Log($"Meta for {a.Name} is empty, this should not be possible but whatever."); return; } Log("Adding meta from archive info the transfer list"); list.Add(new TransferFile(a.Meta, metaOutputPath, true)); } else { Log($"Meta will be ignored for {a.Name}"); } } }); } else { if (!Directory.Exists(Mods)) { Log($"Mods directory {Mods} does not exist!"); return(-1); } Log($"Reading modlist.txt from {Modlist}"); string[] modlist = File.ReadAllLines(Modlist); if (modlist == null || modlist.Length == 0) { Log($"Provided modlist.txt file at {Modlist} is empty or could not be read!"); return(-1); } var mods = modlist.Where(s => s.StartsWith("+")).Select(s => s.Substring(1)).ToHashSet(); if (mods.Count == 0) { Log("Counted mods from modlist.txt are 0!"); return(-1); } Log($"Found {mods.Count} mods in modlist.txt"); var downloads = new HashSet <string>(); Directory.EnumerateDirectories(Mods, "*", SearchOption.TopDirectoryOnly) .Where(d => mods.Contains(Path.GetRelativePath(Path.GetDirectoryName(d), d))) .Do(d => { var meta = Path.Combine(d, "meta.ini"); if (!File.Exists(meta)) { Log($"Mod meta file {meta} does not exist, skipping"); return; } string[] ini = File.ReadAllLines(meta); if (ini == null || ini.Length == 0) { Log($"Mod meta file {meta} could not be read or is empty!"); return; } ini.Where(i => !string.IsNullOrWhiteSpace(i) && i.StartsWith("installationFile=")) .Select(i => i.Replace("installationFile=", "")) .Do(i => { Log($"Found installationFile {i}"); downloads.Add(i); }); }); Log($"Found {downloads.Count} installationFiles from mod metas."); Directory.EnumerateFiles(Input, "*", SearchOption.TopDirectoryOnly) .Where(f => downloads.Contains(Path.GetFileNameWithoutExtension(f))) .Do(f => { Log($"Found archive {f}"); var outputPath = Path.Combine(Output, Path.GetFileName(f)); Log($"Adding {f} to the transfer list"); list.Add(new TransferFile(f, outputPath)); var metaInputPath = Path.Combine(f, ".meta"); if (File.Exists(metaInputPath)) { Log($"Found meta file for {f} at {metaInputPath}"); if (IncludeMeta) { var metaOutputPath = Path.Combine(outputPath, ".meta"); Log($"Adding {metaInputPath} to the transfer list."); list.Add(new TransferFile(metaInputPath, metaOutputPath)); } else { Log("Meta file will be ignored"); } } else { Log($"Found no meta file for {f}"); } }); } Log($"Transfer list contains {list.Count} items"); var success = 0; var failed = 0; var skipped = 0; list.Do(f => { if (File.Exists(f.Output)) { if (Overwrite) { Log($"Output file {f.Output} already exists, it will be overwritten"); if (f.IsMeta || Move) { Log($"Deleting file at {f.Output}"); try { File.Delete(f.Output); } catch (Exception e) { Log($"Could not delete file {f.Output}!\n{e}"); failed++; } } } else { Log($"Output file {f.Output} already exists, skipping"); skipped++; return; } } if (f.IsMeta) { Log($"Writing meta data to {f.Output}"); try { File.WriteAllText(f.Output, f.Input, Encoding.UTF8); success++; } catch (Exception e) { Log($"Error while writing meta data to {f.Output}!\n{e}"); failed++; } } else { if (Copy) { Log($"Copying file {f.Input} to {f.Output}"); try { File.Copy(f.Input, f.Output, Overwrite ? CopyOptions.None : CopyOptions.FailIfExists, CopyMoveProgressHandler, null); success++; } catch (Exception e) { Log($"Error while copying file {f.Input} to {f.Output}!\n{e}"); failed++; } } else if (Move) { Log($"Moving file {f.Input} to {f.Output}"); try { File.Move(f.Input, f.Output, Overwrite ? MoveOptions.ReplaceExisting : MoveOptions.None, CopyMoveProgressHandler, null); success++; } catch (Exception e) { Log($"Error while moving file {f.Input} to {f.Output}!\n{e}"); failed++; } } } }); Log($"Skipped transfers: {skipped}"); Log($"Failed transfers: {failed}"); Log($"Successful transfers: {success}"); return(0); }
public void AlphaFS_Volume_SetVolumeMountPoint() { Console.WriteLine("Volume.SetVolumeMountPoint()"); if (!UnitTestConstants.IsAdmin()) { Assert.Inconclusive(); } #region Logical Drives var cnt = 0; var destFolder = Path.Combine(TempFolder, "Volume.SetVolumeMountPoint()-" + Path.GetRandomFileName()); Directory.CreateDirectory(destFolder); var guid = Volume.GetUniqueVolumeNameForPath(UnitTestConstants.SysDrive); try { UnitTestConstants.StopWatcher(true); Volume.SetVolumeMountPoint(destFolder, guid); Console.WriteLine( "\t#{0:000}\tSystem Drive: [{1}]\tGUID: [{2}]\n\t\tDestination : [{3}]\n\t\tCreated Mount Point.\n\t{4}", ++cnt, UnitTestConstants.SysDrive, guid, destFolder, UnitTestConstants.Reporter(true)); Console.WriteLine("\n"); AlphaFS_Volume_EnumerateVolumeMountPoints(); Console.WriteLine("\n\nFile.GetLinkTargetInfo()"); var lti = File.GetLinkTargetInfo(destFolder); Assert.IsTrue(!string.IsNullOrWhiteSpace(lti.PrintName)); Assert.IsTrue(!string.IsNullOrWhiteSpace(lti.SubstituteName)); Assert.IsTrue(UnitTestConstants.Dump(lti, -14), "Unable to dump object."); // Cleanup. UnitTestConstants.StopWatcher(true); var deleteOk = false; try { Volume.DeleteVolumeMountPoint(destFolder); deleteOk = true; } catch (Exception ex) { Console.WriteLine("\nCaught (unexpected) {0}: [{1}]", ex.GetType().FullName, ex.Message.Replace(Environment.NewLine, " ")); } Console.WriteLine("\n\nVolume.DeleteVolumeMountPoint() (Should be True): [{0}]\tFolder: [{1}]\n{2}\n", deleteOk, destFolder, UnitTestConstants.Reporter()); Directory.Delete(destFolder, true, true); Assert.IsTrue(deleteOk && !Directory.Exists(destFolder)); AlphaFS_Volume_EnumerateVolumeMountPoints(); } catch (Exception ex) { cnt = 0; Console.WriteLine("\nCaught (unexpected) {0}: [{1}]", ex.GetType().FullName, ex.Message.Replace(Environment.NewLine, " ")); } finally { // Always remove mount point. // Experienced: CCleaner deletes through mount points! try { Volume.DeleteVolumeMountPoint(destFolder); } catch { } } if (cnt == 0) { Assert.Inconclusive("Nothing was enumerated, but it was expected."); } #endregion // Logical Drives }
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}" + "\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.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); var opt = new CsvConfiguration(CultureInfo.InvariantCulture) { ShouldUseConstructorParameters = _ => false }; _csvWriter = new CsvWriter(_swCsv, opt); } catch (Exception) { _logger.Error($"Unable to open '{outFile}'! Is it in use? Exiting!\r\n"); Environment.Exit(0); } var foo = _csvWriter.Context.AutoMap <EventRecord>(); // if (_fluentCommandLineParser.Object.PayloadAsJson == false) // { // foo.Map(t => t.Payload).Ignore(); // } // else // { // // } 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(_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.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(_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.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), dirEnumOptions, f); 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); } } } } try { _swCsv?.Flush(); _swCsv?.Close(); _swJson?.Flush(); _swJson?.Close(); _swXml?.Flush(); _swXml?.Close(); } catch (Exception e) { _logger.Error($"Error when flushing output files to disk! Error message: {e.Message}"); } 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, true); } } }
private static void UpdateFromRepo() { Console.WriteLine(); _logger.Info( "Checking for updated maps at https://github.com/EricZimmerman/evtx/tree/master/evtx/Maps..."); Console.WriteLine(); var archivePath = Path.Combine(BaseDirectory, "____master.zip"); if (File.Exists(archivePath)) { File.Delete(archivePath); } using (var client = new WebClient()) { ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; client.DownloadFile("https://github.com/EricZimmerman/evtx/archive/master.zip", archivePath); } var fff = new FastZip(); if (Directory.Exists(Path.Combine(BaseDirectory, "Maps")) == false) { Directory.CreateDirectory(Path.Combine(BaseDirectory, "Maps")); } var directoryFilter = "Maps"; // Will prompt to overwrite if target file names already exist fff.ExtractZip(archivePath, BaseDirectory, FastZip.Overwrite.Always, null, null, directoryFilter, true); if (File.Exists(archivePath)) { File.Delete(archivePath); } var newMapPath = Path.Combine(BaseDirectory, "evtx-master", "evtx", "Maps"); var orgMapPath = Path.Combine(BaseDirectory, "Maps"); var newMaps = Directory.GetFiles(newMapPath); var newlocalMaps = new List <string>(); var updatedlocalMaps = new List <string>(); if (File.Exists(Path.Combine(orgMapPath, "Security_4624.map"))) { _logger.Warn($"Old map format found. Zipping to '!!oldMaps.zip' and cleaning up old maps"); //old maps found, so zip em first var oldZip = Path.Combine(orgMapPath, "!!oldMaps.zip"); fff.CreateZip(oldZip, orgMapPath, false, @"\.map$"); foreach (var m in Directory.GetFiles(orgMapPath, "*.map")) { File.Delete(m); } } if (File.Exists(Path.Combine(orgMapPath, "!!!!README.txt"))) { File.Delete(Path.Combine(orgMapPath, "!!!!README.txt")); } foreach (var newMap in newMaps) { var mName = Path.GetFileName(newMap); var dest = Path.Combine(orgMapPath, mName); if (File.Exists(dest) == false) { //new target newlocalMaps.Add(mName); } else { //current destination file exists, so compare to new var fiNew = new FileInfo(newMap); var fi = new FileInfo(dest); if (fiNew.GetHash(HashType.SHA1) != fi.GetHash(HashType.SHA1)) { //updated file updatedlocalMaps.Add(mName); } } File.Copy(newMap, dest, CopyOptions.None); } if (newlocalMaps.Count > 0 || updatedlocalMaps.Count > 0) { _logger.Fatal("Updates found!"); Console.WriteLine(); if (newlocalMaps.Count > 0) { _logger.Error("New maps"); foreach (var newLocalMap in newlocalMaps) { _logger.Info(Path.GetFileNameWithoutExtension(newLocalMap)); } Console.WriteLine(); } if (updatedlocalMaps.Count > 0) { _logger.Error("Updated maps"); foreach (var um in updatedlocalMaps) { _logger.Info(Path.GetFileNameWithoutExtension(um)); } Console.WriteLine(); } Console.WriteLine(); } else { Console.WriteLine(); _logger.Info("No new maps available"); Console.WriteLine(); } Directory.Delete(Path.Combine(BaseDirectory, "evtx-master"), true); }