diff --git a/BinaryDetail.cs b/BinaryDetail.cs index 66b3d0d..f8a0b0e 100644 --- a/BinaryDetail.cs +++ b/BinaryDetail.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; @@ -9,12 +8,12 @@ namespace BinaryDetailer [Serializable] public class BinaryDetail { - public BinaryDetail(FileInfo fileInfo) { FileInfo = fileInfo; } + public string GroupId { get; internal set; } public string Error { get; internal set; } public FileInfo FileInfo { get; internal set; } public ImageFileMachine ImageFileMachine { get; internal set; } @@ -23,30 +22,26 @@ public BinaryDetail(FileInfo fileInfo) public ProcessorArchitecture ProcessorArchitecture { get; internal set; } public string TargetFrameworkAttribute { get; internal set; } public string AssemblyVersion { get; internal set; } - public string FileVersion => FileVersionInfo.GetVersionInfo(FileInfo.FullName).FileVersion; - public string ProductVersion => FileVersionInfo.GetVersionInfo(FileInfo.FullName).ProductVersion; - public string AssemblyCompanyAttribute => FileVersionInfo.GetVersionInfo(FileInfo.FullName).CompanyName; public string AssemblyCopyrightAttribute => FileVersionInfo.GetVersionInfo(FileInfo.FullName).LegalCopyright; - public static string[] CSVHeader { get { return new[] { - "Full Path,FileName,AssemblyCompanyAttribute,AssemblyCopyrightAttribute,AssemblyVersion,FileVersion,ProductVersion,ImageRuntimeVersion,TargetFrameworkAttribute,PortableExecutableKinds,ImageFileMachine,ProcessorArchitecture,Error" + "Group Id, Full Path,FileName,AssemblyCompanyAttribute,AssemblyCopyrightAttribute,AssemblyVersion,FileVersion,ProductVersion,ImageRuntimeVersion,TargetFrameworkAttribute,PortableExecutableKinds,ImageFileMachine,ProcessorArchitecture,Error" }; } } - public string ToCsv() { return + "\"" + GroupId + "\"," + "\"" + FileInfo.FullName + "\"," + "\"" + FileInfo.Name + "\"," + "\"" + AssemblyCompanyAttribute + "\"," + diff --git a/BinaryDetailFactory.cs b/BinaryDetailFactory.cs index a47321a..58feb1a 100644 --- a/BinaryDetailFactory.cs +++ b/BinaryDetailFactory.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; @@ -77,7 +76,6 @@ private AppDomain BuildChildDomain(AppDomain parentDomain) evidence, setup); } - private class BinaryDetailPopulator : MarshalByRefObject { [SuppressMessage("Microsoft.Performance", diff --git a/BinaryDetailer.csproj b/BinaryDetailer.csproj index dcb669e..62c3dc4 100644 --- a/BinaryDetailer.csproj +++ b/BinaryDetailer.csproj @@ -33,12 +33,16 @@ 4 + + + + @@ -50,6 +54,12 @@ 1.5.1 + + 15.0.4797.1004 + + + + diff --git a/Export.cs b/Export.cs new file mode 100644 index 0000000..c9f40ed --- /dev/null +++ b/Export.cs @@ -0,0 +1,275 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Xml; +using System.Xml.Linq; + +// Use of this library requires an install of Microsoft office +using Microsoft.Office.Interop.Word; + +namespace BinaryDetailer +{ + public class Export + { + readonly List ExcludeNames = new List(); + + public Export(List excludeNames) + { + ExcludeNames = excludeNames; + } + + public void GroupBinary(List binaryDetails, string xmlFilePath) + { + try + { + // Load xml config file + XDocument xmlDoc = XDocument.Load(xmlFilePath); + + // Loop through the binaries + foreach (var binaryDetail in binaryDetails) + { + // Set an escape from the loop once match is found + bool groupIdSet = false; + + // Loop through each "group" element. I.E Company name + foreach (XElement group in xmlDoc.Root.Elements("group")) + { + if (groupIdSet == true) break; + + string groupName = group.Attribute("name").Value; + + // Check if the binary has a match in the config xml + if (binaryDetail.AssemblyCompanyAttribute == groupName) + { + // Loop through each "dll" element in the matching group + // It is neccessarry to find the group first. It is possible a dll could be used in + // another library in which case a license check needs to be done. + foreach (XElement dll in group.Elements("dll")) + { + // Check if the "dllname" attribute matches a "FileInfo.Name" + string dllName = dll.Attribute("dllname")?.Value ?? dll.Value; + + // If the dll in the config matches, set groupid + if (binaryDetail.FileInfo.Name == dllName) + { + binaryDetail.GroupId = groupName; + groupIdSet = true; + break; + } + } + } + else + { + // If nothing matches + binaryDetail.GroupId = "Unknown"; + } + } + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + public void CreateReport(List binaryDetails) + { + string csvFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + Guid.NewGuid() + ".csv"); + + File.Create(csvFileName).Close(); + File.AppendAllLines(csvFileName, BinaryDetail.CSVHeader); + + foreach (var binaryDetail in binaryDetails) + { + bool include = true; + foreach (string excludeName in ExcludeNames) + { + if ((binaryDetail.AssemblyCompanyAttribute != null && binaryDetail.AssemblyCompanyAttribute.ToLower().Contains(excludeName)) || + (binaryDetail.AssemblyCopyrightAttribute != null && binaryDetail.AssemblyCopyrightAttribute.ToLower().Contains(excludeName))) + { + include = false; + } + } + + if (include == false) continue; + + File.AppendAllLines(csvFileName, new[] { binaryDetail.ToCsv() }); + } + + Console.WriteLine("File created at " + csvFileName); + } + + public void CreateWordDoc(List binaryDetails) + { + try + { + string wordFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + Guid.NewGuid() + ".docx"); + + // Create an instance for word app + Application winword = new Application + { + ShowAnimation = false, + Visible = false + }; + + // Create a missing variable for missing value + object missing = Missing.Value; + + // Create a new document + Document document = winword.Documents.Add(ref missing, ref missing, ref missing, ref missing); + document.PageSetup.Orientation = WdOrientation.wdOrientLandscape; + + // Add header into the document + foreach (Section section in document.Sections) + { + //Get the header range and add the header details. + Range headerRange = section.Headers[WdHeaderFooterIndex.wdHeaderFooterPrimary].Range; + headerRange.Fields.Add(headerRange, WdFieldType.wdFieldPage); + headerRange.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphCenter; + headerRange.Font.ColorIndex = WdColorIndex.wdBlue; + headerRange.Font.Size = 10; + headerRange.Text = "Binary Detailer"; + } + + // Add the footers into the document + foreach (Section wordSection in document.Sections) + { + //Get the footer range and add the footer details. + Range footerRange = wordSection.Footers[WdHeaderFooterIndex.wdHeaderFooterPrimary].Range; + footerRange.Font.ColorIndex = WdColorIndex.wdDarkRed; + footerRange.Font.Size = 10; + footerRange.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphCenter; + footerRange.Text = "Github repository: https://github.com/stuartjsmith/binarydetailer"; + } + + // Adding text to document + document.Content.SetRange(0, 0); + string firstLine = "Binary Detailer is a method of outputting binary details such as net framework, " + + "64-bit compatibility, version etc. Given a directory name, it will iterate dll and exe files " + + "and output the results to a csv file."; + + document.Content.Text = firstLine + Environment.NewLine; + + // Add paragraph with Heading 1 style + Paragraph para1 = document.Content.Paragraphs.Add(ref missing); + object styleHeading1 = "Heading 1"; + para1.Range.set_Style(ref styleHeading1); + para1.Range.Text = "Binary Details"; + para1.Range.InsertParagraphAfter(); + + // Create a table + Table table = document.Tables.Add(para1.Range, binaryDetails.Count + 1, 5, ref missing, ref missing); + + // Define column headings + WordColumnHeadings(table); + + // Add table borders + table.Borders.Enable = 1; + + // Loop through each binary and add to the table. + foreach (var binaryDetail in binaryDetails.Select((value, i) => new { i, value })) + { + bool include = true; + + foreach (string excludeName in ExcludeNames) + { + if ((binaryDetail.value.AssemblyCompanyAttribute != null && binaryDetail.value.AssemblyCompanyAttribute.ToLower().Contains(excludeName)) || + (binaryDetail.value.AssemblyCopyrightAttribute != null && binaryDetail.value.AssemblyCopyrightAttribute.ToLower().Contains(excludeName))) + { + include = false; + } + } + + if (include == false) continue; + + // Passing the index + 2 as there is a heading column to overcome. + WordRowData(binaryDetail.i + 2, table, binaryDetail.value); + } + + //Save the document + object filename = wordFileName; + document.SaveAs2(ref filename); + document.Close(ref missing, ref missing, ref missing); + document = null; + winword.Quit(ref missing, ref missing, ref missing); + winword = null; + + Console.WriteLine("Word Document created at " + filename); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + public void WordColumnHeadings(Table firstTable) + { + // Loop through each cell in the row + foreach (Cell cell in firstTable.Rows[1].Cells) + { + // Switch between the columns + switch (cell.ColumnIndex) + { + case 1: + cell.Range.Text = "Group ID"; + break; + case 2: + cell.Range.Text = "Company Name"; + break; + case 3: + cell.Range.Text = "File Name"; + break; + case 4: + cell.Range.Text = "Assembly Version"; + break; + case 5: + cell.Range.Text = "File Version"; + break; + } + + // Format properties goes here + cell.Range.Font.Bold = 1; + cell.Range.Font.Name = "verdana"; + cell.Range.Font.Size = 10; + + // Cell shading + cell.Shading.BackgroundPatternColor = WdColor.wdColorGray25; + + // Center alignment for the Header cells + cell.VerticalAlignment = WdCellVerticalAlignment.wdCellAlignVerticalCenter; + cell.Range.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphCenter; + } + } + + public void WordRowData(int index, Table firstTable, BinaryDetail binaryDetail) + { + // Loop through each cell in the row + foreach (Cell cell in firstTable.Rows[index].Cells) + { + // Switch between the columns + switch (cell.ColumnIndex) + { + case 1: + cell.Range.Text = binaryDetail.GroupId; + break; + case 2: + cell.Range.Text = binaryDetail.AssemblyCompanyAttribute; + break; + case 3: + cell.Range.Text = binaryDetail.FileInfo.Name; + break; + case 4: + cell.Range.Text = binaryDetail.AssemblyVersion; + break; + case 5: + cell.Range.Text = binaryDetail.FileVersion; + break; + } + } + } + } +} diff --git a/GroupingConfigExample.xml b/GroupingConfigExample.xml new file mode 100644 index 0000000..0b7bb32 --- /dev/null +++ b/GroupingConfigExample.xml @@ -0,0 +1,17 @@ + + + + Infragistics.Documents.Core.dll + + + Microsoft.Build.Tasks.Core.resources.dll + + + + + + + + + + diff --git a/Program.cs b/Program.cs index cae61da..eac8dde 100644 --- a/Program.cs +++ b/Program.cs @@ -1,20 +1,18 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; -using System.Text.RegularExpressions; namespace BinaryDetailer { internal class Program { - private static string currentBinary = string.Empty; private static List ExcludeNames = new List(); - + private static void Main(string[] args) { + List groupedStrings = new List(); + string path = args[0]; if (args.Length > 0) { @@ -24,6 +22,8 @@ private static void Main(string[] args) } } + Export ex = new Export(ExcludeNames); + List binaryDetails = new List(); IEnumerable allFiles = GetFiles(path, new[] { "*.dll", "*.exe" }, SearchOption.AllDirectories); @@ -33,34 +33,36 @@ private static void Main(string[] args) binaryDetails.Add(bd); } - CreateReport(binaryDetails); - Console.In.ReadLine(); - } - - private static void CreateReport(List binaryDetails) - { - string fileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), - Guid.NewGuid() + ".csv"); - File.Create(fileName).Close(); - File.AppendAllLines(fileName, BinaryDetail.CSVHeader); - foreach (var binaryDetail in binaryDetails) + if (args.Length > 1) { - bool include = true; - foreach (string excludeName in ExcludeNames) + foreach (var arg in args.Select((value, i) => new { i, value })) { - if ((binaryDetail.AssemblyCompanyAttribute != null && binaryDetail.AssemblyCompanyAttribute.ToLower().Contains(excludeName)) || - (binaryDetail.AssemblyCopyrightAttribute != null && binaryDetail.AssemblyCopyrightAttribute.ToLower().Contains(excludeName))) + var index = arg.i; + + // Skip the first arg as this is the path to report on + if (index.Equals(0)) continue; + + if (arg.value.ToLower().Equals("doc")) + { + // Create word document + ex.CreateWordDoc(binaryDetails); + } + else if (arg.value.ToLower().Equals("config")) { - include = false; + // Create a binary grouping based on a config. + ex.GroupBinary(binaryDetails, args[index+1]); + ex.CreateReport(binaryDetails); } } - - if (include == false) continue; - - File.AppendAllLines(fileName, new[] { binaryDetail.ToCsv() }); + } + else + { + // Raw report + ex.CreateReport(binaryDetails); } - Console.WriteLine("File created at " + fileName); + Console.WriteLine("Export complete"); + Console.In.ReadLine(); } private static IEnumerable GetFiles(string path, @@ -72,4 +74,4 @@ private static IEnumerable GetFiles(string path, Directory.EnumerateFiles(path, searchPattern, searchOption)); } } -} +} \ No newline at end of file diff --git a/README.md b/README.md index d7ca456..7b5ba2d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Binary Detailer -Binary Detailer is a method of outputing binary details such as net framework, 64 bit compatibility, version etc. Given a directory name, it will iterate dll and exe files and output the results to a csv file. +Binary Detailer is a method of outputting binary details such as net framework, 64-bit compatibility, version etc. Given a directory name, it will iterate dll and exe files and output the results to a csv file. ___ ### Usage @@ -18,6 +18,13 @@ ___ ![Screenshot 3](data/screenshots/Completed-csv.jpg "Completed CSV File") ___ +### Arguments + +'config' - This requires an XML passed after the config argument. This will compare the binaries against the XML and group common binaries together. See "GroupingConfigExample.xml" +'doc' - This will create a word document table of the data. This requires a Microsoft Office install on the machine executing. + +Example argument: BinaryDetailer.exe "C:\Program Files\dotnet\sdk\6.0.400" config "C:\BinaryDetailer\GroupingConfigExample.xml" doc + ## Contribute Congratulations! You’re up and running. Now you can begin using and contributing your fixes and new features to the project.