in Tools/InstallerVerifier/Program.cs [44:188]
static int Main (string [] args)
{
var loggingLevelSwitch = new LoggingLevelSwitch {
MinimumLevel = LogEventLevel.Information
};
Log.Logger = new LoggerConfiguration ()
.WriteTo.Console ()
.MinimumLevel.ControlledBy (loggingLevelSwitch)
.CreateLogger ();
Console.OutputEncoding = Encoding.UTF8;
string workingPath = null;
bool cleanWorkingPath = false;
string exclusionsFile = null;
bool updateExclusionsFile = false;
string exclusionsBootstrapReason = null;
bool showHelp = false;
string msiFile = null;
Exception optionsError = null;
var optionSet = new OptionSet
{
{ "o|output=", "Output path for intermediate work",
v => workingPath = v },
{ "x|exclude=", "Path to an exclusions JSON file (see below for format)",
v => exclusionsFile = v },
{ "exclude-update", "Update the exclusions file in place by removing " +
"entries in the exclusion file no longer present in the installer.",
v => updateExclusionsFile = true },
{ "exclude-bootstrap=", "Generate an initial exclusions file based on all unsigned files.",
v => exclusionsBootstrapReason = v },
{ "v|verbose", "Verbose", v => {
switch (loggingLevelSwitch.MinimumLevel) {
case LogEventLevel.Debug:
loggingLevelSwitch.MinimumLevel = LogEventLevel.Verbose;
break;
case LogEventLevel.Verbose:
break;
default:
loggingLevelSwitch.MinimumLevel = LogEventLevel.Debug;
break;
} } },
{ "h|?|help", "Show this help",
v => showHelp = true }
};
try {
var remaining = optionSet.Parse (args);
switch (remaining.Count) {
case 0:
throw new Exception ("must specify an MSI file to process");
case 1:
msiFile = remaining [0];
break;
default:
throw new Exception ("only one MSI file may be specified");
}
} catch (Exception e) {
showHelp = true;
optionsError = e;
}
if (showHelp) {
if (optionsError != null) {
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine ("Error: {0}", optionsError.Message);
Console.Error.WriteLine ();
Console.ResetColor ();
}
Console.Error.WriteLine (
"Usage: {0} [OPTIONS] MSI_FILE",
Path.GetFileName (typeof (Program).Assembly.Location));
Console.Error.WriteLine ();
Console.Error.WriteLine ("Options:");
optionSet.WriteOptionDescriptions (Console.Error);
return 1;
}
if (workingPath == null) {
workingPath = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ());
cleanWorkingPath = true;
}
ExclusionSet exclusions;
try {
exclusions = new ExclusionSet (exclusionsFile);
} catch (Exception e) {
Log.Fatal (e, "Error loading exclusions file {ExclusionsFile}", exclusionsFile);
return 1;
}
int totalUnsigned = 0;
try {
var wxsOutputPath = Path.Combine (
workingPath,
Path.GetFileNameWithoutExtension (msiFile) + ".wxs");
var extractPath = Path.Combine (workingPath, "contents");
if (!Directory.Exists (extractPath))
Exec (
"wix/dark",
Path.Combine (FindWixTools (), "dark.exe"),
"-v",
"-sui",
"-o", wxsOutputPath,
"-x", extractPath,
msiFile);
var fileMap = GenerateFileMap (wxsOutputPath);
foreach (var entry in fileMap)
exclusions.MarkHandled (entry.Value.InstallPath);
var stopwatch = new Stopwatch ();
stopwatch.Start ();
totalUnsigned = VerifySignatures (
fileMap,
exclusions,
exclusionsBootstrapReason);
stopwatch.Stop ();
Log.Debug ("Signature verification completed: {Duration}", stopwatch.Elapsed);
if (exclusionsBootstrapReason != null || updateExclusionsFile)
exclusions.Save ();
} finally {
if (cleanWorkingPath) {
Log.Debug ("Removing working directory {WorkingPath}…", workingPath);
Directory.Delete (workingPath, recursive: true);
}
}
if (totalUnsigned > 0) {
Log.Error ("{TotalUnsigned} unsigned files", totalUnsigned);
return 2;
}
return 0;
}