diff --git a/AppControl Manager/Pages/Update.xaml b/AppControl Manager/Pages/Update.xaml
index be6f43629..0166ed0fb 100644
--- a/AppControl Manager/Pages/Update.xaml
+++ b/AppControl Manager/Pages/Update.xaml
@@ -63,16 +63,12 @@
+
+
-
-
+ Click="CheckForUpdateButton_Click"
+ ToolTipService.ToolTip="Will download and install the latest version from the GitHub repository. The time it takes depends on your network connection. Approxmitate download size is 140 MB."/>
diff --git a/AppControl Manager/Pages/Update.xaml.cs b/AppControl Manager/Pages/Update.xaml.cs
index 395e4a413..0274df8da 100644
--- a/AppControl Manager/Pages/Update.xaml.cs
+++ b/AppControl Manager/Pages/Update.xaml.cs
@@ -1,9 +1,12 @@
using Microsoft.UI.Xaml.Controls;
-using Microsoft.UI.Xaml.Input;
using System;
+using System.IO;
+using System.Net.Http;
using System.Threading.Tasks;
using Windows.ApplicationModel;
+#pragma warning disable IDE0063 // Do not simplify using statements, keep them scoped for proper disposal otherwise files will be in use until the method is exited
+
namespace WDACConfig.Pages
{
@@ -16,59 +19,350 @@ public Update()
this.NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
}
+ // The link to the file that contains the download link for the latest version of the AppControl Manager
+ private const string downloadLinkURL = "https://raw.githubusercontent.com/HotCakeX/Harden-Windows-Security/refs/heads/main/AppControl%20Manager/DownloadURL.txt";
+
+ // The link to the file that contains the version number of the latest available version of the AppControl Manager
+ private const string versionLinkURL = "https://raw.githubusercontent.com/HotCakeX/Harden-Windows-Security/refs/heads/main/AppControl%20Manager/version.txt";
+
+
private async void CheckForUpdateButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
try
{
+ UpdateStatusInfoBar.IsClosable = false;
CheckForUpdateButton.IsEnabled = false;
UpdateStatusInfoBar.IsOpen = true;
- UpdateStatusInfoBar.Message = "Checking for update and installing the new version if available. Please keep the app open.";
+ UpdateStatusInfoBar.Message = "Checking for update";
UpdateStatusInfoBar.Severity = InfoBarSeverity.Informational;
- // To save the output of the PowerShell
- string? psOutput = null;
+ // Get the current app's version
+ PackageVersion packageVersion = Package.Current.Id.Version;
- // Run the update check in a separate thread and asynchronously wait for its completion
- await Task.Run(() =>
- {
- // Get the current app's version
- PackageVersion packageVersion = Package.Current.Id.Version;
+ // Convert it to a normal Version object
+ Version currentAppVersion = new(packageVersion.Major, packageVersion.Minor, packageVersion.Build, packageVersion.Revision);
- // Convert it to a normal Version object
- Version currentAppVersion = new(packageVersion.Major, packageVersion.Minor, packageVersion.Build, packageVersion.Revision);
+ string versionsResponse;
- // Run the PowerShell script to check for updates and save the output code
- psOutput = PowerShellExecutor.ExecuteScript($"""
-$VerbosePreference = 'Continue';
-(irm 'https://raw.githubusercontent.com/HotCakeX/Harden-Windows-Security/main/Harden-Windows-Security.ps1')+'AppControl -CheckForUpdate {currentAppVersion}'|iex
-""", true);
- });
-
-
- if (psOutput is not null && string.Equals(psOutput, "420", StringComparison.OrdinalIgnoreCase))
+ using (HttpClient client = new())
{
- UpdateStatusInfoBar.Message = "The current version is already up to date.";
- UpdateStatusInfoBar.Severity = InfoBarSeverity.Success;
+ versionsResponse = await client.GetStringAsync(versionLinkURL);
}
- else if (psOutput is not null && string.Equals(psOutput, "8200", StringComparison.OrdinalIgnoreCase))
+
+ // To store the online version
+ Version onlineAvailableVersion = new(versionsResponse);
+
+ if (onlineAvailableVersion > currentAppVersion)
{
- UpdateStatusInfoBar.Message = "Successfully installed the latest version. Please close and reopen the AppControl Manager to use the new version.";
+
+ string msg1 = $"The current version is {currentAppVersion} while the online version is {onlineAvailableVersion}, updating the application...";
+ Logger.Write(msg1);
+ UpdateStatusInfoBar.Message = msg1;
+
+ string onlineDownloadURL;
+
+ using (HttpClient client = new())
+ {
+ // Store the download link to the latest available version
+ onlineDownloadURL = await client.GetStringAsync(downloadLinkURL);
+ }
+
+ string stagingArea = StagingArea.NewStagingArea("AppUpdate").ToString();
+
+ string AppControlManagerSavePath = Path.Combine(stagingArea, "AppControlManager.msix");
+
+ UpdateStatusInfoBar.Message = "Downloading the AppControl Manager MSIX package...";
+
+ DownloadProgressRingForMSIXFile.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
+
+ using (HttpClient client = new())
+ {
+ // Send an Async get request to the url and specify to stop reading after headers are received for better efficiently
+ using (HttpResponseMessage response = await client.GetAsync(onlineDownloadURL, HttpCompletionOption.ResponseHeadersRead))
+ {
+ // Ensure that the response is successful (status code 2xx); otherwise, throw an exception
+ _ = response.EnsureSuccessStatusCode();
+
+ // Retrieve the total file size from the Content-Length header (if available)
+ long? totalBytes = response.Content.Headers.ContentLength;
+
+ // Open a stream to read the response content asynchronously
+ await using (Stream contentStream = await response.Content.ReadAsStreamAsync())
+ {
+ // Open a file stream to save the downloaded data locally
+ await using (FileStream fileStream = new(
+ AppControlManagerSavePath, // Path to save the file
+ FileMode.Create, // Create a new file or overwrite if it exists
+ FileAccess.Write, // Write-only access
+ FileShare.None, // Do not allow other processes to access the file
+ bufferSize: 8192, // Set buffer size to 8 KB
+ useAsync: true)) // Enable asynchronous operations for the file stream
+ {
+ // Define a buffer to hold data chunks as they are read
+ byte[] buffer = new byte[8192];
+ long totalReadBytes = 0; // Track the total number of bytes read
+ int readBytes; // Holds the count of bytes read in each iteration
+ double lastReportedProgress = 0; // Tracks the last reported download progress
+
+ // Loop to read from the content stream in chunks until no more data is available
+ while ((readBytes = await contentStream.ReadAsync(buffer)) > 0)
+ {
+ // Write the buffer to the file stream
+ await fileStream.WriteAsync(buffer.AsMemory(0, readBytes));
+ totalReadBytes += readBytes; // Update the total bytes read so far
+
+ // If the total file size is known, calculate and report progress
+ if (totalBytes.HasValue)
+ {
+ // Calculate the current download progress as a percentage
+ double progressPercentage = (double)totalReadBytes / totalBytes.Value * 100;
+
+ // Only update the ProgressBar if progress has increased by at least 1% to avoid constantly interacting with the UI thread
+ if (progressPercentage - lastReportedProgress >= 1)
+ {
+ // Update the last reported progress
+ lastReportedProgress = progressPercentage;
+
+ // Update the UI ProgressBar value on the dispatcher thread
+ _ = DownloadProgressRingForMSIXFile.DispatcherQueue.TryEnqueue(() =>
+ {
+ DownloadProgressRingForMSIXFile.Value = progressPercentage;
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ Logger.Write($"The AppControl Manager MSIX package has been successfully downloaded to {AppControlManagerSavePath}");
+
+ DownloadProgressRingForMSIXFile.IsIndeterminate = true;
+
+ UpdateStatusInfoBar.Message = "Detecting and downloading the SignTool.exe from the Microsoft servers";
+
+ string signToolPath = string.Empty;
+
+ await Task.Run(() =>
+ {
+ signToolPath = SignToolHelper.GetSignToolPath();
+ });
+
+ UpdateStatusInfoBar.Message = "All Downloads finished, installing the new AppControl Manager version";
+
+ // Run the update check in a separate thread and asynchronously wait for its completion
+ await Task.Run(() =>
+ {
+
+ string script = """
+[System.String]$MSIXPath = '{MSIXPath}'
+[System.String]$SignTool = '{SignTool}'
+[System.String]$MSIXDownloadURL = '{MSIXDownloadURL}'
+$ErrorActionPreference = 'Stop'
+$VerbosePreference = 'Continue'
+Write-Verbose -Message 'Detecting the CPU Arch'
+switch ($Env:PROCESSOR_ARCHITECTURE) {
+ 'AMD64' { [System.String]$CPUArch = 'x64'; break }
+ 'ARM64' { [System.String]$CPUArch = 'arm64'; break }
+ default { Throw [System.PlatformNotSupportedException] 'Only AMD64 and ARM64 architectures are supported.' }
+}
+
+Add-Type -TypeDefinition @'
+using System;
+using System.Security;
+using System.Security.Cryptography;
+
+public static class SecureStringGenerator
+{
+ private static readonly char[] allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
+ public static SecureString GenerateSecureString(int length)
+ {
+ SecureString secureString = new();
+ using RandomNumberGenerator rng = RandomNumberGenerator.Create();
+ byte[] randomNumber = new byte[4]; // Buffer for generating secure random numbers
+ for (int i = 0; i < length; i++)
+ {
+ rng.GetBytes(randomNumber);
+ int randomIndex = BitConverter.ToInt32(randomNumber, 0) & int.MaxValue; // Ensure non-negative index
+ randomIndex %= allowedChars.Length; // Fit within allowedChars length
+
+ char randomChar = allowedChars[randomIndex];
+ secureString.AppendChar(randomChar);
+ }
+ secureString.MakeReadOnly();
+ return secureString;
+ }
+}
+'@ -Language CSharp
+
+Write-Verbose -Message 'Creating the working directory in the TEMP directory'
+[System.String]$CommonName = 'SelfSignedCertForAppControlManager'
+[System.String]$WorkingDir = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), $CommonName)
+[System.String]$CertificateOutputPath = [System.IO.Path]::Combine($WorkingDir, "$CommonName.cer")
+[System.String]$PFXCertificateOutputPath = [System.IO.Path]::Combine($WorkingDir, "$CommonName.pfx")
+[System.Security.SecureString]$PassWord = [SecureStringGenerator]::GenerateSecureString(100)
+[System.String]$HashingAlgorithm = 'Sha512'
+
+if ([System.IO.Directory]::Exists($WorkingDir)) {
+ [System.IO.Directory]::Delete($WorkingDir, $true)
+}
+$null = [System.IO.Directory]::CreateDirectory($WorkingDir)
+
+try {
+ Write-Verbose -Message "Checking if a certificate with the common name '$CommonName' already exists."
+ [System.String[]]$CertStoresToCheck = @('Cert:\LocalMachine\My', 'Cert:\LocalMachine\Root', 'Cert:\LocalMachine\CA', 'Cert:\LocalMachine\TrustedPublisher', 'Cert:\CurrentUser\My', 'Cert:\CurrentUser\Root', 'Cert:\CurrentUser\CA', 'Cert:\CurrentUser\TrustedPublisher')
+ foreach ($Store in $CertStoresToCheck) {
+ foreach ($Item in (Get-ChildItem -Path $Store)) {
+ if ($Item.Subject -ieq "CN=$CommonName") {
+ Write-Verbose -Message "A certificate with the common name '$CommonName' in the store '$Store' already exists. Removing it."
+ $Item | Remove-Item -Force
+ }
+ }
+ }
+
+ Write-Verbose -Message 'Building the certificate'
+ [System.Collections.Hashtable]$Params = @{
+ Subject = "CN=$CommonName"
+ FriendlyName = $CommonName
+ CertStoreLocation = 'Cert:\CurrentUser\My'
+ KeyExportPolicy = 'ExportableEncrypted'
+ KeyLength = '4096'
+ KeyAlgorithm = 'RSA'
+ HashAlgorithm = $HashingAlgorithm
+ KeySpec = 'Signature'
+ KeyUsage = 'DigitalSignature'
+ KeyUsageProperty = 'Sign'
+ Type = 'CodeSigningCert'
+ NotAfter = [System.DateTime](Get-Date).AddYears(100)
+ TextExtension = @('2.5.29.19={text}CA:FALSE', '2.5.29.37={text}1.3.6.1.5.5.7.3.3', '1.3.6.1.4.1.311.21.10={text}oid=1.3.6.1.5.5.7.3.3')
+ }
+ [System.Security.Cryptography.X509Certificates.X509Certificate2]$NewCertificate = New-SelfSignedCertificate @params
+
+ # Save the thumbprint of the certificate to a variable
+ [System.String]$NewCertificateThumbprint = $NewCertificate.Thumbprint
+
+ Write-Verbose -Message 'Finding the certificate that was just created by its thumbprint'
+ [System.Security.Cryptography.X509Certificates.X509Certificate2]$TheCert = foreach ($Cert in (Get-ChildItem -Path 'Cert:\CurrentUser\My' -CodeSigningCert)) {
+ if ($Cert.Thumbprint -eq $NewCertificateThumbprint) {
+ $Cert
+ }
+ }
+
+ Write-Verbose -Message 'Exporting the certificate (public key only)'
+ $null = Export-Certificate -Cert $TheCert -FilePath $CertificateOutputPath -Type 'CERT' -Force
+
+ Write-Verbose -Message 'Exporting the certificate (public and private keys)'
+ $null = Export-PfxCertificate -Cert $TheCert -CryptoAlgorithmOption 'AES256_SHA256' -Password $PassWord -ChainOption 'BuildChain' -FilePath $PFXCertificateOutputPath -Force
+
+ Write-Verbose -Message "Removing the certificate from the 'Current User/Personal' store"
+ $TheCert | Remove-Item -Force
+
+ try {
+ Write-Verbose -Message "Importing the certificate to the 'Local Machine/Trusted Root Certification Authorities' store with the private key protected by VSM (Virtual Secure Mode - Virtualization Based Security)"
+ $null = Import-PfxCertificate -ProtectPrivateKey 'VSM' -FilePath $PFXCertificateOutputPath -CertStoreLocation 'Cert:\LocalMachine\Root' -Password $PassWord
+ }
+ catch {
+ Write-Verbose -Message "Importing the certificate to the 'Local Machine/Trusted Root Certification Authorities' store with the private key without VSM protection since it's most likely not available on the system. Happens usually in VMs with not nested-virtualization feature enabled."
+ $null = Import-PfxCertificate -FilePath $PFXCertificateOutputPath -CertStoreLocation 'Cert:\LocalMachine\Root' -Password $PassWord
+ }
+
+ # Pattern for AppControl Manager version and architecture extraction from file path and download link URL
+ [regex]$RegexPattern = '_(?\d+\.\d+\.\d+\.\d+)_(?x64|arm64)\.msix$'
+
+ # Get the version and architecture of the installing MSIX package app from the provided file path
+ $RegexMatch = $RegexPattern.Match($MSIXDownloadURL)
+
+ if ($RegexMatch.Success) {
+ $InstallingAppVersion = $RegexMatch.Groups['Version'].Value
+ $InstallingAppArchitecture = $RegexMatch.Groups['Architecture'].Value
+ }
+ else {
+ throw 'Could not get the version of the installing app'
+ }
+
+ Write-Verbose -Message 'Signing the App Control Manager MSIX package'
+
+ # In this step the SignTool detects the cert to use based on Common name + ThumbPrint + Hash Algo + Store Type + Store Name
+ . $SignTool sign /debug /n $CommonName /fd $HashingAlgorithm /sm /s 'Root' /sha1 $NewCertificateThumbprint $MSIXPath
+
+ if ($LASTEXITCODE -ne 0) {
+ throw "SignTool Failed. Exit Code: $LASTEXITCODE"
+ }
+
+ $PossibleExistingApp = Get-AppxPackage -Name 'AppControlManager'
+ if ($null -ne $PossibleExistingApp) {
+ # Get the details of the currently installed app before attempting to install the new one
+ [System.String]$InstalledAppVersionBefore = $PossibleExistingApp.Version
+ [System.String]$InstalledAppArchitectureBefore = $PossibleExistingApp.Architecture
+ }
+
+ Write-Verbose -Message "Installing AppControl Manager MSIX package version '$InstallingAppVersion' with architecture '$InstallingAppArchitecture'"
+ Add-AppPackage -Path $MSIXPath -ForceUpdateFromAnyVersion -DeferRegistrationWhenPackagesAreInUse # -ForceTargetApplicationShutdown will shutdown the application if its open.
+
+ Write-Verbose -Message "Finding the certificate that was just created by its thumbprint again from the 'Local Machine/Trusted Root Certification Authorities' store"
+ [System.Security.Cryptography.X509Certificates.X509Certificate2]$TheCert2 = foreach ($Cert2 in (Get-ChildItem -Path 'Cert:\LocalMachine\Root' -CodeSigningCert)) {
+ if ($Cert.Thumbprint -eq $NewCertificateThumbprint) {
+ $Cert2
+ }
+ }
+
+ Write-Verbose -Message 'Removing the certificate that has private + public keys'
+ $TheCert2 | Remove-Item -Force
+
+ Write-Verbose -Message "Adding the certificate to the 'Local Machine/Trusted Root Certification Authorities' store with public key only. This safely stores the certificate on your device, ensuring its private key does not exist so cannot be used to sign anything else."
+ $null = Import-Certificate -FilePath $CertificateOutputPath -CertStoreLocation 'Cert:\LocalMachine\Root'
+
+ [System.String]$InstallingAppLocationToAdd = 'C:\Program Files\WindowsApps\AppControlManager_' + $InstallingAppVersion + '_' + $InstallingAppArchitecture + '__sadt7br7jpt02\'
+ Write-Verbose -Message "Adding the new app install's files To the ASR Rules exclusions."
+ Add-MpPreference -AttackSurfaceReductionOnlyExclusions (($InstallingAppLocationToAdd + 'AppControlManager.exe'), ($InstallingAppLocationToAdd + 'AppControlManager.dll'))
+
+ # Remove ASR rule exclusions that belong to the previous app version if it existed
+ if (![string]::IsNullOrWhiteSpace($InstalledAppVersionBefore) -and ![string]::IsNullOrWhiteSpace($InstalledAppArchitectureBefore)) {
+ Write-Verbose -Message 'Removing ASR Rules exclusions that belong to the previous app version.'
+ [System.String]$InstalledAppLocationToRemove = 'C:\Program Files\WindowsApps\AppControlManager_' + $InstalledAppVersionBefore + '_' + $InstalledAppArchitectureBefore + '__sadt7br7jpt02\'
+ Remove-MpPreference -AttackSurfaceReductionOnlyExclusions (($InstalledAppLocationToRemove + 'AppControlManager.exe'), ($InstalledAppLocationToRemove + 'AppControlManager.dll'))
+ }
+}
+finally {
+ Write-Verbose -Message 'Cleaning up the working directory in the TEMP directory'
+ [System.IO.Directory]::Delete($WorkingDir, $true)
+}
+
+""";
+
+ // Replace placeholders in the script with actual values
+ script = script.Replace("{MSIXPath}", AppControlManagerSavePath, StringComparison.OrdinalIgnoreCase)
+ .Replace("{SignTool}", signToolPath, StringComparison.OrdinalIgnoreCase)
+ .Replace("{MSIXDownloadURL}", onlineDownloadURL, StringComparison.OrdinalIgnoreCase);
+
+
+ // Run the PowerShell script to check for updates and save the output code
+ _ = PowerShellExecutor.ExecuteScript(script);
+
+ });
+
+ UpdateStatusInfoBar.Message = "Update has been successful. When you close and reopen the AppControl Manager, you will be automatically using the new version.";
UpdateStatusInfoBar.Severity = InfoBarSeverity.Success;
}
+
else
{
- UpdateStatusInfoBar.Message = psOutput;
- UpdateStatusInfoBar.Severity = InfoBarSeverity.Warning;
+ UpdateStatusInfoBar.Message = "The current version is already up to date.";
+ UpdateStatusInfoBar.Severity = InfoBarSeverity.Success;
}
-
}
catch
{
UpdateStatusInfoBar.Severity = InfoBarSeverity.Error;
UpdateStatusInfoBar.Message = "An error occurred while checking for update.";
+
+ DownloadProgressRingForMSIXFile.Value = 0;
+
throw;
}
@@ -77,26 +371,9 @@ await Task.Run(() =>
UpdateStatusInfoBar.IsClosable = true;
CheckForUpdateButton.IsEnabled = true;
- }
-
- }
-
- #region
- private void CheckForUpdateButton_PointerEntered(object sender, PointerRoutedEventArgs e)
- {
- CheckForUpdateButtonTeachingTip.IsOpen = true;
- }
-
- private void CheckForUpdateButton_PointerExited(object sender, PointerRoutedEventArgs e)
- {
- CheckForUpdateButtonTeachingTip.IsOpen = false;
- }
-
- private void CheckForUpdateButton_PointerPressed(object sender, PointerRoutedEventArgs e)
- {
- CheckForUpdateButtonTeachingTip.IsOpen = false;
+ DownloadProgressRingForMSIXFile.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed;
+ }
}
- #endregion
}
}
diff --git a/AppControl Manager/Shared Logics/ConfigureISGServices.cs b/AppControl Manager/Shared Logics/ConfigureISGServices.cs
index 78eaddd13..8a82adfd1 100644
--- a/AppControl Manager/Shared Logics/ConfigureISGServices.cs
+++ b/AppControl Manager/Shared Logics/ConfigureISGServices.cs
@@ -1,6 +1,6 @@
namespace WDACConfig
{
- internal static class ConfigureISGServices
+ public static class ConfigureISGServices
{
///
/// Starts the AppIdTel and sets the appidsvc service to auto start
diff --git a/AppControl Manager/Shared Logics/SignToolHelper.cs b/AppControl Manager/Shared Logics/SignToolHelper.cs
index cc4af4054..3fc085aa8 100644
--- a/AppControl Manager/Shared Logics/SignToolHelper.cs
+++ b/AppControl Manager/Shared Logics/SignToolHelper.cs
@@ -1,6 +1,11 @@
using System;
using System.Diagnostics;
using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Net.Http;
+using System.Runtime.InteropServices;
+using System.Text.Json;
#nullable enable
@@ -64,5 +69,204 @@ public static void Sign(FileInfo ciPath, FileInfo signToolPathFinal, string cert
throw new InvalidOperationException($"SignTool failed with exit code {process.ExitCode}. Error: {error}");
}
}
+
+
+ ///
+ /// Downloads the latest version of the Microsoft.Windows.SDK.BuildTools NuGet package.
+ /// Extracts the SignTool.exe from it and returns the path to it.
+ /// Copies it to the User Configurations directory.
+ ///
+ private static string Download()
+ {
+ DirectoryInfo stagingArea = StagingArea.NewStagingArea("GetSignTool");
+
+ using HttpClient client = new();
+
+ string packageName = "Microsoft.Windows.SDK.BuildTools";
+
+ Logger.Write("Finding the latest version of the Microsoft.Windows.SDK.BuildTools package from NuGet");
+
+ // Get the list of versions
+ string versionsUrl = $"https://api.nuget.org/v3-flatcontainer/{packageName}/index.json";
+ string versionsResponse = client.GetStringAsync(versionsUrl).GetAwaiter().GetResult();
+
+ // Parse the JSON to get the latest version
+ JsonDocument versionsJson = JsonDocument.Parse(versionsResponse);
+ JsonElement versions = versionsJson.RootElement.GetProperty("versions");
+ string? latestVersion = versions[versions.GetArrayLength() - 1].GetString() ?? throw new InvalidOperationException("Failed to get the latest version of the package.");
+
+ // Construct the download link for the latest version's .nupkg
+ string downloadUrl = $"https://api.nuget.org/v3-flatcontainer/{packageName}/{latestVersion}/{packageName}.{latestVersion}.nupkg";
+
+ Logger.Write($"Downloading the latest .nupkg package file version '{latestVersion}' from the following URL: {downloadUrl}");
+
+ // Download the .nupkg file
+ string filePath = Path.Combine(stagingArea.FullName, $"{packageName}.{latestVersion}.nupkg");
+ using (Stream downloadStream = client.GetStreamAsync(downloadUrl).GetAwaiter().GetResult())
+ using (FileStream fileStream = new(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
+ {
+ downloadStream.CopyTo(fileStream);
+ }
+
+ Logger.Write($"Downloaded package to {filePath}");
+
+ // Extract the .nupkg file
+ string extractPath = Path.Combine(stagingArea.FullName, "extracted");
+ ZipFile.ExtractToDirectory(filePath, extractPath);
+
+ Logger.Write($"Extracted package to {extractPath}");
+
+
+ string binDirectoryPath = Path.Combine(extractPath, "bin");
+ // Get the directory that has the version, since it varies we need to get it implicitly
+ string[] versionDirectories = Directory.GetDirectories(binDirectoryPath);
+
+ if (versionDirectories.Length == 0)
+ {
+ throw new DirectoryNotFoundException("No version directories found in 'bin'.");
+ }
+
+ // There should be only one
+ string versionDirectory = versionDirectories.First();
+ string signtoolPath = Path.Combine(versionDirectory, "x64", "signtool.exe");
+
+ if (!File.Exists(signtoolPath))
+ {
+ throw new FileNotFoundException("signtool.exe not found in the expected path.");
+ }
+
+ // The final path that is in the User configurations directory and will be returned and saved in User configs
+ string finalSignToolPath = Path.Combine(GlobalVars.UserConfigDir, "SignTool.exe");
+
+ File.Copy(signtoolPath, finalSignToolPath, true);
+
+ Directory.Delete(stagingArea.ToString(), true);
+
+ Logger.Write($"Path to signtool.exe: {finalSignToolPath}");
+
+ return finalSignToolPath;
+
+ }
+
+
+ ///
+ /// Verifies if the SignTool.exe is of a version greater than one specified in the method
+ ///
+ ///
+ ///
+ private static bool Verify(string filePath)
+ {
+ try
+ {
+ FileVersionInfo fileInfo = FileVersionInfo.GetVersionInfo(filePath);
+ return (new Version(fileInfo.ProductVersion!) > new Version("10.0.22621.2428"));
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+
+
+ ///
+ /// Returns the architecture of the current OS
+ ///
+ ///
+ ///
+ private static string GetArchitecture()
+ {
+ if (RuntimeInformation.OSArchitecture is Architecture.X64)
+ {
+ return "x64";
+ }
+ else if (RuntimeInformation.OSArchitecture is Architecture.Arm64)
+ {
+ return "arm64";
+ }
+ else
+ {
+ throw new InvalidOperationException("Only X64 and ARM64 platforms are supported.");
+ }
+ }
+
+
+
+ ///
+ /// Gets the path to SignTool.exe and verifies it to make sure it's valid
+ /// If the SignTool.exe path is not provided by parameter, it will try to detect it automatically by checking if Windows SDK is installed
+ /// If the SignTool.exe path is not provided by parameter and it could not be detected automatically, it will try to download it from NuGet
+ ///
+ ///
+ ///
+ public static string GetSignToolPath(string? filePath = null)
+ {
+ // The path to return at the end
+ string? signToolPath = null;
+
+ // If Sign tool path wasn't provided by parameter or it doesn't exist on the file system, try to detect it automatically
+ if (string.IsNullOrWhiteSpace(filePath) && !Path.Exists(filePath))
+ {
+
+ try
+ {
+
+ Logger.Write("SignTool.exe path was not provided by parameter, trying to detect it automatically");
+
+ string baseDir = @"C:\Program Files (x86)\Windows Kits\10\bin";
+ string targetArchitecture = GetArchitecture();
+
+ // Get the directory with the highest version in its name
+ string? latestSigntoolPath = Directory.GetDirectories(baseDir)
+ .Select(dir => new DirectoryInfo(dir))
+ .Where(dir => Version.TryParse(Path.GetFileName(dir.Name), out _)) // Ensure directory is a version
+ .OrderByDescending(dir => new Version(dir.Name)) // Order by version
+ .First().ToString(); // Get the highest version
+
+ if (latestSigntoolPath is not null)
+ {
+ // Construct the full SignTool.exe path
+ string constructedFinalPath = Path.Combine(latestSigntoolPath, targetArchitecture, "signtool.exe");
+
+ // If it checks out, assign it to the output variable
+ if (Verify(constructedFinalPath))
+ {
+ signToolPath = constructedFinalPath;
+ Logger.Write($"Successfully detected the SignTool.exe on the system: {constructedFinalPath}");
+ }
+ }
+
+ }
+ catch (Exception ex)
+ {
+ Logger.Write($"Failed to detect SignTool.exe path automatically: {ex.Message}");
+ }
+
+ }
+
+ // If Sign tool path was provided by parameter, use it
+ else
+ {
+ Logger.Write("SignTool.exe path was provided by parameter");
+
+ if (Verify(filePath))
+ {
+ Logger.Write("The provided SignTool.exe is valid");
+ signToolPath = filePath;
+ }
+ else
+ {
+ Logger.Write("The provided SignTool.exe is not valid");
+ }
+ }
+
+ // Download the SignTool.exe if it's still null
+ signToolPath ??= Download();
+
+ Logger.Write($"Setting the SignTool path in the common user configurations to: {signToolPath}");
+ _ = UserConfiguration.Set(SignToolCustomPath: signToolPath);
+
+ return signToolPath;
+ }
}
}
diff --git a/AppControl Manager/Shared Logics/StagingArea.cs b/AppControl Manager/Shared Logics/StagingArea.cs
index 51839f7a5..9bd8da5e6 100644
--- a/AppControl Manager/Shared Logics/StagingArea.cs
+++ b/AppControl Manager/Shared Logics/StagingArea.cs
@@ -7,6 +7,12 @@ namespace WDACConfig
{
public static class StagingArea
{
+ ///
+ /// Creating a directory as a staging area for a job and returns the path to that directory
+ ///
+ ///
+ ///
+ ///
public static DirectoryInfo NewStagingArea(string cmdletName)
{
if (string.IsNullOrWhiteSpace(cmdletName))
diff --git a/Harden-Windows-Security.ps1 b/Harden-Windows-Security.ps1
index c050d8b37..9b9eac125 100644
--- a/Harden-Windows-Security.ps1
+++ b/Harden-Windows-Security.ps1
@@ -168,36 +168,19 @@ Function AppControl {
.PARAMETER SignTool
Optional. The path to the Microsoft's Signtool.exe
If not provided, the function automatically downloads the latest SignTool.exe from the Microsoft website in Nuget and will use it for the signing operations.
- .PARAMETER CheckForUpdate
- Used internally by the AppControl Manager app when you use the 'Check for update' button.
.LINK
https://github.com/HotCakeX/Harden-Windows-Security/wiki/AppControl-Manager
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)][System.String]$MSIXPath,
- [Parameter(Mandatory = $False)][System.String]$SignTool,
- [Parameter(Mandatory = $False)][System.Version]$CheckForUpdate
+ [Parameter(Mandatory = $False)][System.String]$SignTool
)
$ErrorActionPreference = 'Stop'
- # If calling this function internally to check for update
- if ($null -ne $CheckForUpdate) {
- Write-Verbose -Message 'Checking for AppControl Manager update'
- [System.Version]$OnlineVersion = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/HotCakeX/Harden-Windows-Security/refs/heads/main/AppControl%20Manager/version.txt'
- if ($CheckForUpdate -lt $OnlineVersion) {
- Write-Verbose -Message "Updating the AppControl Manger because the current version '$CheckForUpdate' is less than the online version '$OnlineVersion'"
- }
- else {
- Write-Verbose -Message 'The AppControl Manager is up to date. Returning.'
- return '420' # Consumed by the AppControl Manager internally
- }
- }
-
if (!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Warning -Message 'Please run this function as an Administrator'
return
}
-
Write-Verbose -Message 'Detecting the CPU Arch'
switch ($Env:PROCESSOR_ARCHITECTURE) {
'AMD64' { [System.String]$CPUArch = 'x64'; break }
@@ -228,8 +211,6 @@ public static class SecureStringGenerator
}
'@ -Language CSharp
}
-
- Write-Verbose -Message 'Creating the working directory in the TEMP directory'
[System.String]$CommonName = 'SelfSignedCertForAppControlManager'
[System.String]$WorkingDir = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), $CommonName)
[System.String]$CertificateOutputPath = [System.IO.Path]::Combine($WorkingDir, "$CommonName.cer")
@@ -240,10 +221,10 @@ public static class SecureStringGenerator
# Pattern for AppControl Manager version and architecture extraction from file path and download link URL
[regex]$RegexPattern = '_(?\d+\.\d+\.\d+\.\d+)_(?x64|arm64)\.msix$'
- #StartMSIXPackageDownloadURLVariable
- $MSIXPackageDownloadURL = 'https://github.com/HotCakeX/Harden-Windows-Security/releases/download/WDACConfigv0.4.6/AppControl.Manager_1.0.0.0_x64.msix'
- #EndMSIXPackageDownloadURLVariable
+ # Download link for the latest version of AppControl manger is retrieved from this text file
+ [System.String]$MSIXPackageDownloadURL = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/HotCakeX/Harden-Windows-Security/refs/heads/main/AppControl%20Manager/DownloadURL.txt'
+ Write-Verbose -Message 'Creating the working directory in the TEMP directory'
if ([System.IO.Directory]::Exists($WorkingDir)) {
[System.IO.Directory]::Delete($WorkingDir, $true)
}
@@ -284,9 +265,7 @@ public static class SecureStringGenerator
Write-Verbose -Message 'Finding the certificate that was just created by its thumbprint'
[System.Security.Cryptography.X509Certificates.X509Certificate2]$TheCert = foreach ($Cert in (Get-ChildItem -Path 'Cert:\CurrentUser\My' -CodeSigningCert)) {
- if ($Cert.Thumbprint -eq $NewCertificateThumbprint) {
- $Cert
- }
+ if ($Cert.Thumbprint -eq $NewCertificateThumbprint) { $Cert }
}
Write-Verbose -Message 'Exporting the certificate (public key only)'
@@ -328,12 +307,12 @@ public static class SecureStringGenerator
Expand-Archive -Path "$WorkingDir\*.nupkg" -DestinationPath $WorkingDir -Force
Write-Verbose -Message 'Finding the Signtool.exe path in the extracted directory'
- $SignTool = (Get-Item -Path "$WorkingDir\bin\*\$CPUArch\signtool.exe").FullName
+ [System.String]$SignTool = (Get-Item -Path "$WorkingDir\bin\*\$CPUArch\signtool.exe").FullName
}
# Download the MSIX package if user did not provide the path to it
if ([System.String]::IsNullOrWhiteSpace($MSIXPath)) {
- $MSIXPath = [System.IO.Path]::Combine($WorkingDir, 'AppControl.Manager.msix')
+ [System.String]$MSIXPath = [System.IO.Path]::Combine($WorkingDir, 'AppControl.Manager.msix')
Write-Verbose -Message 'Downloading the MSIX package from the GitHub releases' -Verbose
$null = Invoke-WebRequest -Uri $MSIXPackageDownloadURL -OutFile $MSIXPath
@@ -352,7 +331,6 @@ public static class SecureStringGenerator
else {
# Get the version and architecture of the installing MSIX package app from the User provided file path
$RegexMatch = $RegexPattern.Match($MSIXPath)
-
if ($RegexMatch.Success) {
$InstallingAppVersion = $RegexMatch.Groups['Version'].Value
$InstallingAppArchitecture = $RegexMatch.Groups['Architecture'].Value
@@ -361,10 +339,6 @@ public static class SecureStringGenerator
throw 'Could not get the version of the installing app from the -MSIX parameter value that you provided.'
}
}
-
- Write-Verbose -Message "Installing AppControl Manager version '$InstallingAppVersion' with architecture '$InstallingAppArchitecture'"
-
- # https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe
Write-Verbose -Message 'Signing the App Control Manager MSIX package'
# In this step the SignTool detects the cert to use based on Common name + ThumbPrint + Hash Algo + Store Type + Store Name
@@ -376,7 +350,6 @@ public static class SecureStringGenerator
# Displays no output if the command runs successfully, and displays minimal output if the command fails.
$null = . $SignTool sign /q /n $CommonName /fd $HashingAlgorithm /sm /s 'Root' /sha1 $NewCertificateThumbprint $MSIXPath
}
-
if ($LASTEXITCODE -ne 0) {
throw "SignTool Failed. Exit Code: $LASTEXITCODE"
}
@@ -395,16 +368,15 @@ public static class SecureStringGenerator
# Get the details of the currently installed app before attempting to install the new one
[System.String]$InstalledAppVersionBefore = $PossibleExistingApp.Version
[System.String]$InstalledAppArchitectureBefore = $PossibleExistingApp.Architecture
+ Write-Verbose -Message "The AppControl Manager app is already installed with version '$InstalledAppVersionBefore' and architecture '$InstalledAppArchitectureBefore'"
}
- Write-Verbose -Message 'Installing the MSIX Package'
+ Write-Verbose -Message "Installing AppControl Manager MSIX Package version '$InstallingAppVersion' with architecture '$InstallingAppArchitecture'"
Add-AppPackage -Path $MSIXPath -ForceUpdateFromAnyVersion -DeferRegistrationWhenPackagesAreInUse # -ForceTargetApplicationShutdown will shutdown the application if its open.
Write-Verbose -Message "Finding the certificate that was just created by its thumbprint again from the 'Local Machine/Trusted Root Certification Authorities' store"
[System.Security.Cryptography.X509Certificates.X509Certificate2]$TheCert2 = foreach ($Cert2 in (Get-ChildItem -Path 'Cert:\LocalMachine\Root' -CodeSigningCert)) {
- if ($Cert.Thumbprint -eq $NewCertificateThumbprint) {
- $Cert2
- }
+ if ($Cert.Thumbprint -eq $NewCertificateThumbprint) { $Cert2 }
}
Write-Verbose -Message 'Removing the certificate that has private + public keys'
@@ -413,64 +385,34 @@ public static class SecureStringGenerator
Write-Verbose -Message "Adding the certificate to the 'Local Machine/Trusted Root Certification Authorities' store with public key only. This safely stores the certificate on your device, ensuring its private key does not exist so cannot be used to sign anything else."
$null = Import-Certificate -FilePath $CertificateOutputPath -CertStoreLocation 'Cert:\LocalMachine\Root'
- #region ASR rules handling
- Write-Verbose -Message 'Getting the list of Attack Surface Reduction Rules exclusions'
- [System.Collections.Generic.List[System.String]]$CurrentASRExclusions = (Get-MpPreference).AttackSurfaceReductionOnlyExclusions
-
[System.String]$InstallingAppLocationToAdd = 'C:\Program Files\WindowsApps\AppControlManager_' + $InstallingAppVersion + '_' + $InstallingAppArchitecture + '__sadt7br7jpt02\'
- [System.Collections.Generic.List[System.String]]$ExesAndDllsToAddToASR = @()
-
- $ExesAndDllsToAddToASR.Add($InstallingAppLocationToAdd + 'AppControlManager.exe')
- $ExesAndDllsToAddToASR.Add($InstallingAppLocationToAdd + 'AppControlManager.dll')
-
- foreach ($ItemToAddToASR in $ExesAndDllsToAddToASR) {
- # If the ASR Rules exclusions list is either empty or it doesn't contain the AppControl Manager files, then add them
- if ($null -eq $CurrentASRExclusions -or !$CurrentASRExclusions.Contains($ItemToAddToASR)) {
- Write-Verbose -Message "Adding $ItemToAddToASR To the ASR Rules exclusions because it didn't exist there."
- Add-MpPreference -AttackSurfaceReductionOnlyExclusions $ItemToAddToASR
- }
- }
+ Write-Verbose -Message "Adding the new app install's files To the ASR Rules exclusions."
+ # The cmdlet won't add duplicates
+ Add-MpPreference -AttackSurfaceReductionOnlyExclusions (($InstallingAppLocationToAdd + 'AppControlManager.exe'), ($InstallingAppLocationToAdd + 'AppControlManager.dll'))
# If the app version being installed is not the same as the app version currently installed
if ($InstallingAppVersion -ne $InstalledAppVersionBefore) {
-
- # Remove ASR rule exclusions that belong to the previous app version if it existed
if (![string]::IsNullOrWhiteSpace($InstalledAppVersionBefore) -and ![string]::IsNullOrWhiteSpace($InstalledAppArchitectureBefore)) {
-
+ Write-Verbose -Message 'Removing ASR Rules exclusions that belong to the previous app version.'
+ # No check is needed since the Remove-MpPreference accepts any string and only removes them if they exist
[System.String]$InstalledAppLocationToRemove = 'C:\Program Files\WindowsApps\AppControlManager_' + $InstalledAppVersionBefore + '_' + $InstalledAppArchitectureBefore + '__sadt7br7jpt02\'
- [System.Collections.Generic.List[System.String]]$ExesAndDllsToRemoveFromASR = @()
-
- $ExesAndDllsToRemoveFromASR.Add($InstalledAppLocationToRemove + 'AppControlManager.exe')
- $ExesAndDllsToRemoveFromASR.Add($InstalledAppLocationToRemove + 'AppControlManager.dll')
-
- foreach ($ItemToRemoveFromASR in $ExesAndDllsToRemoveFromASR) {
-
- if ($null -eq $CurrentASRExclusions -or !$CurrentASRExclusions.Contains($ItemToRemoveFromASR)) {
- Write-Verbose -Message "Removing $ItemToRemoveFromASR from the ASR Rules exclusions because it belongs to the previous app version."
- Remove-MpPreference -AttackSurfaceReductionOnlyExclusions $ItemToRemoveFromASR
- }
- }
+ Remove-MpPreference -AttackSurfaceReductionOnlyExclusions (($InstalledAppLocationToRemove + 'AppControlManager.exe'), ($InstalledAppLocationToRemove + 'AppControlManager.dll'))
}
}
- #endregion
+ else {
+ Write-Verbose -Message 'Current and new AppControl Manager versions are the same, skipping removing previous ASR rules exclusions.'
+ }
try {
$ValidateAdminCodeSignaturesRegPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
$ValidateAdminCodeSignaturesRegName = 'ValidateAdminCodeSignatures'
-
$ValidateAdminCodeSignaturesRegValue = Get-ItemProperty -Path $ValidateAdminCodeSignaturesRegPath -Name $ValidateAdminCodeSignaturesRegName -ErrorAction SilentlyContinue
-
# This will cause the "A referral was returned from the server." error to show up when AppControl Manager tries to start.
if ($ValidateAdminCodeSignaturesRegValue.$ValidateAdminCodeSignaturesRegName -eq 1) {
Write-Warning -Message "A policy named 'Only elevate executables that are signed and validated' is conflicting with the AppControl Manager app and won't let it start because it's self-signed with your on-device keys. Please disable the policy. It can be found in Group Policy Editor -> Computer Configuration -> Windows Settings -> Security Settings -> Local Policies -> Security Options -> 'User Account Control: Only elevate executable files that are signed and validated'"
}
}
catch {}
-
- # The code is consumed by the AppControl Manager internally
- if ($null -ne $CheckForUpdate) {
- return '8200'
- }
}
finally {
Write-Verbose -Message 'Cleaning up the working directory in the TEMP directory'
diff --git a/WDACConfig/Utilities/Hashes.csv b/WDACConfig/Utilities/Hashes.csv
index 5f282702b..0be856c21 100644
--- a/WDACConfig/Utilities/Hashes.csv
+++ b/WDACConfig/Utilities/Hashes.csv
@@ -1 +1,132 @@
-
\ No newline at end of file
+"RelativePath","FileName","FileHash"
+".NETAssembliesToLoad.txt",".NETAssembliesToLoad.txt","804D546AE56387503C051F12B57C3A1188862AAE9E80691504BB27E6191F7E1823C90B5D2B3884606B4913B78C092592FA6F2337B6920D8EC64540234FA2B2BD"
+"WDACConfig.psd1","WDACConfig.psd1","53A559C88959E65D466A117235AD24E41D697F72BD34B29D2AB9FF2AEA9D0C4A28C63A9A3AC435264E82A63EC635538E40CDF699D64A1156C3E10E5BF8E12C4E"
+"WDACConfig.psm1","WDACConfig.psm1","1D23D80AABFAD0EE526596D2C9C7CAC21C076C47F6678E539F551430453EE0643550BF3AA9BDF966BBDAB0DF0A6DBB5CC179915C59F63822110993EBE2A2949A"
+"Core\Assert-WDACConfigIntegrity.psm1","Assert-WDACConfigIntegrity.psm1","038E3B2F7377BD2EF75594628F3C6491380BACDD5ED5A3EFFC85068B2E99F6617B905F94CA7B6F7AB3D47F7804923ED886EEED958C06B2A9A67332DEBB342E5D"
+"Core\Build-WDACCertificate.psm1","Build-WDACCertificate.psm1","923416158B7AE1F489271E94B2584ABCD22F466D085BFAC72AA9EF480BEBE6D3E32EA986E8B956AAA61E9B2F12F585E747BB10C6C2903B3387D53F59A8EB5065"
+"Core\Confirm-WDACConfig.psm1","Confirm-WDACConfig.psm1","505D77722CA9F1DE037453DA4BE94ADE78B7B15EB20F5D61A458C8DFF1AD79F30494128A420C2AA70E3AC9B3F0FC4530EEA5FA3E66D173B061B328CB7E9FF708"
+"Core\ConvertTo-WDACPolicy.psm1","ConvertTo-WDACPolicy.psm1","C0521057BAB6228E78F692B8D81C1D366E2DD5FD1B4DCA4C1ECB17B52C8BCC7102267F6D147F25C44BB903DF2933069B8D30DF8AA293DCBE9B52B1A814EBBA7B"
+"Core\Deploy-SignedWDACConfig.psm1","Deploy-SignedWDACConfig.psm1","E7FAAA0FEF7C2C538BA38C3DD245B7C3C8F88F5058BF40CE90F875E24A5C6EB2D62232AAF7CBA0163C4DA6FA7238DCD6DC84D467C5C02071E28983F1FE98B284"
+"Core\Edit-SignedWDACConfig.psm1","Edit-SignedWDACConfig.psm1","D3006891F7A8B16096F83ADC02BF77D8C1B299F577A6CDB2A6AD3EC7B21A10419E71A0529DA2350F4BA40D94D9CC5DD12BB317C95C0761F2D32D4E89ED96A58B"
+"Core\Edit-WDACConfig.psm1","Edit-WDACConfig.psm1","1454899AEC7452E5C490C09C6A33F285C80959DBD0CFF2614ABA6B7CA8248C2FDA459D21E408310B56BC58044115A90DB8F058545CD4906A8C2C088A33990D1D"
+"Core\Get-CiFileHashes.psm1","Get-CiFileHashes.psm1","A53755F8040842925AE48C44FA642226DDD2D68A6F2F08D5DE386FF486450E1BEDDB6C7DC136CBA425F849EDC96A55595B75060E4AA9AC2D3FF5BBE879967C66"
+"Core\Get-CIPolicySetting.psm1","Get-CIPolicySetting.psm1","C2F36D55458C820257D8E62F493057BD467B9E8E197115989B19111BE01EE5BAE79EECEC66A09CF2F23609C8817334A5A09D0ABB4502F3E58C49E7287E1E53F1"
+"Core\Get-CommonWDACConfig.psm1","Get-CommonWDACConfig.psm1","94C92A903C06D218500173155E2F96726A6F2D4F0C2E0FD89D8D4090728D84FF8D1002D9A85CE5A15326B2993E4155B989BBCB7272BA222F34874FE0AEED9B44"
+"Core\Invoke-WDACSimulation.psm1","Invoke-WDACSimulation.psm1","35908E0BBADA2AA7CB6EB14C931B5D192C860B33C144241FD38460914EB9DCA1A4304EC44A73DF6F9296864B29497FB844D8673B10F8E5591F1F7681FA0CAF9C"
+"Core\New-DenyWDACConfig.psm1","New-DenyWDACConfig.psm1","DE59549E378AF7D7037E6D6811514E6A6CCB693C2EC2867611EA0C0192F0A8174C51B6C47F9BCBACE1ADA84A5E947BDCE73310FA41A7C6ECB27ABB2A81E0EEDA"
+"Core\New-KernelModeWDACConfig.psm1","New-KernelModeWDACConfig.psm1","F1619DFE4635E507BF2C17ECF6E4ADFF05839FD236C30ECABCA11AEC8EAAB71F1C1EF7859E1AB4D80781AB0B01A63FD0937DAE010EE1781C417EB0E1C105D434"
+"Core\New-SupplementalWDACConfig.psm1","New-SupplementalWDACConfig.psm1","CE345438DB51B13F2AD074079F96911FB70CEC55FF53EAB17C8F82999261692497FD9B1319053D52D19D2B02ECF6C4578DA458AE2ED4CC6151AE4EF5B19BF6C4"
+"Core\New-WDACConfig.psm1","New-WDACConfig.psm1","3805DADCD0233F19FCFDDD9F69A5EC609D22C4AB9952B7724A20F2D82C4E47AF4E7ABC1A9FBE5410E3F4845E7F02E3B37D88E2B33FF5B4752E71BE4C12B1F3C0"
+"Core\Remove-CommonWDACConfig.psm1","Remove-CommonWDACConfig.psm1","874FD5D71EB136239CE06192B1A5E388B6A9D6A4FB016534E40FB35FD327334B1764B761FE5B5DA4BF10450C83283A06117E93F8F15F5EE62F85611100770445"
+"Core\Remove-WDACConfig.psm1","Remove-WDACConfig.psm1","0BA48E8E1F4EBCDA0CFFC8EB030A35308CC7753072D7405B89ABAF4F801FE79AE1D3A4B147DE7DC989F6467C6AE04C05CA94661DDED8326E03F360FB1808156B"
+"Core\Set-CommonWDACConfig.psm1","Set-CommonWDACConfig.psm1","0D855EBB7503564F44A25BD752572FCEC39112089CEC6ABEA00632FF39C31C46D5DD27389515C97BCD1D3F43405C81E58CA196876F3C055986413205FBA00CF4"
+"Core\Test-CiPolicy.psm1","Test-CiPolicy.psm1","2759500B4680B9A40CA09C5018F6DB5C42C2438DEEAFF6BED415F700AF06E6DF6249E03E5A5DC1492519B886293165B69D658F198919B4DAA1CB46C4D2D4D9B5"
+"Help\ConvertTo-WDACPolicy.md","ConvertTo-WDACPolicy.md","5DF0995E33298FCC53926C79CC7C6122A980D2BDD899A9DC7DC37C465713D783E294B91360AE0B3EE2E10AA034168276A91CF04E9AA51DE6F4BD9136F4A1C544"
+"Help\ConvertTo-WDACPolicy.xml","ConvertTo-WDACPolicy.xml","3DF2CFE215E81AC3B5B3A98BE9EC24663223E09AE676AC63636C0B773E90424980A6231AEB0F05444CDA4206192E8D560A38AD7D41449F44A5C56A5F8B1F3DE8"
+"Public\MockConfigCIBootstrap.psm1","MockConfigCIBootstrap.psm1","CC97429BAB23AE5EA068D2D68BD3002EC3CE08FD04DFFC0010DB9884E7BEADFB443F027EE73D09F6A56174A97CEECA440A4B37D2B4E1599B068C68D46CDC579E"
+"Public\PSCustomObjectArrayToHashtableArray.psm1","PSCustomObjectArrayToHashtableArray.psm1","E7DA5F31B198CF5545D30BF47DA2283E5CB61F0C6B6AFCA3DE59B6331142ADA28DFE1C7B24390FDFC86501DCABD1FFEB98ED3F083308C986DCE11350B66B5920"
+"Public\Write-ColorfulText.psm1","Write-ColorfulText.psm1","E9ED3290B5F39E28BC0ADCD76BE28E5C63D94F7C88E037AAD2D9AC52F08D245B3384B7C652AD952E4F89E8B329A36339AB1ACE1462333AC8D06A3168ED93DE78"
+"Public\Write-FinalOutput.psm1","Write-FinalOutput.psm1","64433D0C34588B1240B27270C24D446BCD91B5742B739560764BDE33EBE18B5CDC659D57BCCD8061FBDB5AC780D7E8DB7600A23A670B7A31182CEA191383CE29"
+"Resources\PolicyRuleOptions.Json","PolicyRuleOptions.Json","A97AAF4AFC1194B65CF92E7D97EBD99652F2809037AB823F238362C16CF0E8CB3BDDFA72D17B81FA534FEA9BD0EEBD19681DB954254A9B9E7C376C43C9508FA6"
+"Shared\Get-KernelModeDrivers.psm1","Get-KernelModeDrivers.psm1","6B8027C667974C0DF491D7CD34296E4E5AFC5F3AB23F19C8792B839D55CDEC4830F027AA1731F065D4DA017AA8D0C30AC57D52875970C34FC5D451C794E4D90C"
+"Shared\Get-KernelModeDriversAudit.psm1","Get-KernelModeDriversAudit.psm1","3E86F390BFE6C9EBE0DC8BA363BB88B3FBE7EA246F033DA6CC363E17CE0F6DCD3C0731736029B343AD58661E6D7324EBC30627AB5E846A364A056D816E69E80E"
+"Shared\Receive-CodeIntegrityLogs.psm1","Receive-CodeIntegrityLogs.psm1","8143DEBE233360D9D621047A911DE05705BD90F271A9BACE0595BB0CC5EFB6B5558489532FA96B739AD4A3156B932C68B1BE32FC9D672840F54B7E5B1136C9D5"
+"Shared\Select-LogProperties.psm1","Select-LogProperties.psm1","8A326BF412DE2C12876D9CD064D6F1201C1F337B248AEBC9FFAB6ED9CFA7B432FD2F9B420CA6855828AF6A3BBB2807411A2C9409B1D777C284EEFDF0F772AA8B"
+"Shared\Set-LogPropertiesVisibility.psm1","Set-LogPropertiesVisibility.psm1","154CAEE6ACD79733D4AAE66A12F04E651E090F46F427CF8FD4FBC4E5C765AD56DE2C5D8943497BD7355C33EEB62F0865731CAEDE0860889C38035D8B416278A1"
+"Shared\Test-ECCSignedFiles.psm1","Test-ECCSignedFiles.psm1","6D90429A30E5CD7C0781C45901CE38F5555B57E59A412FE9F991D6C5CD9E01A3619E18CDB5D06BFEF27D36D69F2CA839F93AFD6811E926E4CFDD5C98903F0262"
+"Shared\Test-KernelProtectedFiles.psm1","Test-KernelProtectedFiles.psm1","D794CF381482B2FB7723C91086AFB406837008AECA2FE9F8BC1AF6580D2A715F2AA88174BAF0725671B59150A52A6534CBBA4AF407293071138FA6C02DB61E61"
+"XMLOps\Compare-CorrelatedData.psm1","Compare-CorrelatedData.psm1","AB1075E899B78A9572242A3E56E371B436596A3322C9A5A3FEEE78D3CCBCB9C310C36C566C8AF9532B7D4651B3D88E1124959A607B5ECB5280CADF93410DE0AC"
+"XMLOps\Merge-Signers_Semantic.psm1","Merge-Signers_Semantic.psm1","44D64796129353B92ADEFE6F0F03679F0A487DDD020451775547BE2943D527DB50C88B7A5B22B60B928378D512A8A2AE05A55F556D03D3DE7F56384F5017FE83"
+"XMLOps\New-Macros.psm1","New-Macros.psm1","9C7638FF54E2CB7480A3927B9DC8BFB67483F7C732D8CE38473C52D9090DC50D28BE9CAA7BDB03C90ABA03DCB0E190753606665CC2FEB703ED911AE049E3CA0D"
+"XMLOps\Optimize-MDECSVData.psm1","Optimize-MDECSVData.psm1","F52E651920E4CB0A695D57A89BDB409BCAF72DBAA2A673EF09EDDD2B055869B6637776ADE4C7E803A49AD9CCE5F525E3014F569EF97D18C62A6CD3D92ECDB420"
+"XMLOps\Remove-DuplicateFileAttrib_Semantic.psm1","Remove-DuplicateFileAttrib_Semantic.psm1","BDA0D4BB52A8AC96402FA1747D3E24E55956F9F8BA0DD5668CED4F90CCE61D6E68B0139DA1E1C0CFE80B93CF8A80CC083A5117050F44B34667591DC0C5B54E0E"
+"C#\ArgumentCompleters\ArgumentCompleterAttribute.cs","ArgumentCompleterAttribute.cs","C783CC25FE46A9251DAF8AB85EA034A0E3E9AF7CB61E15788402425E628744C9A4FA22B6DF5BE008234F04634DA31CC2D67EB8F39B88E58C90ECE4475F8D4F06"
+"C#\ArgumentCompleters\BasePolicyNamez.cs","BasePolicyNamez.cs","7B8E14C9EEE91F0660D9B07D779382D2422B50F58E4CD03E6D5C4A8738334B84B3CA687BAB5BD1105C6A2D31018CADCFD78E4579EDEC19FD1B0379EDF19754B6"
+"C#\Shared Logics\AllCertificatesGrabber.cs","AllCertificatesGrabber.cs","3A2EC9CBE97DA8B4E2EAB03C6C73194BEE997A05049CCAC336F097E038FE618D48B6F52368F414905F203D4E520159B77BBB1D51B68E0152D1A70369FD6236CA"
+"C#\Shared Logics\CertCNz.cs","CertCNz.cs","786A32B78052C8F35654C6BC57A72531820147F7E23B9D59563FDE4EA29AF213F1D75DA79C9E05406C539C0F9456D1EAFCCCB7980C8D7F376A75FCA2D8606C2E"
+"C#\Shared Logics\CertificateHelper.cs","CertificateHelper.cs","1F2FA9CC224B82B2B944418D505C151C75171C7C60B2521616429FB249CF7E35173B12E537FCB3126CAD04D5D87678B4F339BCDAB9CC020E79764F280AAB5D2F"
+"C#\Shared Logics\CheckPolicyDeploymentStatus.cs","CheckPolicyDeploymentStatus.cs","BDB8A7FDA3E2D0D741656E0FB44C24DCE7F110C0B0BCEAF2395AA26F2424271CFA3DACD0432C38CBE13F640522446FF15CF808A87C8F311AEC00D0E380A3FBB4"
+"C#\Shared Logics\CiPolicyUtility.cs","CiPolicyUtility.cs","07F96A5637533B1780B22B47E66BC179E3E719E9C2A511E070AC17A4C3633097B5E98241F05499CD3CE93BFCA3D1BE83A62F2EF93AA195307B68A85F7732BEBE"
+"C#\Shared Logics\CiToolHelper.cs","CiToolHelper.cs","C7E353FD94E90F23C58D2B65235D2EFC5C539CA02B9A001D803A3A9A5457B7633AB65FFAFB7DF9D84AB89C27C5CEC4ACDD4726D27692270E34C8FC4FCE83D050"
+"C#\Shared Logics\CodeIntegrityInfo.cs","CodeIntegrityInfo.cs","7FB6FD8FA1A5723189F3150CC1EA2EC6A2272B145D86C2888ED0CAF7976D33F83AC186784E5EB639FB84AC03126FBDCFEC40E0AE8FF9E286BB718E69B58F7480"
+"C#\Shared Logics\ConfigureISGServices.cs","ConfigureISGServices.cs","3FD2AA11C44448390F3857BF0565B12BE1CCF5FFBBB2761E1228D2C9CA6C0035ED31547C951744F3F794B7D91F5FD945D010D5FE47137C10BC1864756A2F6B9F"
+"C#\Shared Logics\Crypt32CertCN.cs","Crypt32CertCN.cs","2032427F766383C8E86EBB5224E63BFF68919B2098D09F1A78F7D21989E3FA47CB5A56031921D6EA1CB5AF28CB4887D2717F013AD8ACCDDDA18F8156D398CD9D"
+"C#\Shared Logics\DeviceGuardInfo.cs","DeviceGuardInfo.cs","8500E69C09709AE960AE18D12B76062CDDE6F3DA500DED5AE4A010C0E3A7D24235CC0273155BA3DA145F8D6F367DECE2F86DE9E5418D28810361745F334E0551"
+"C#\Shared Logics\DirectorySelector.cs","DirectorySelector.cs","089AFBDEA1BE2CE2783F0FEE336279AF1A29F56242A35F8093FB96533F6ED17C0EA35C46A4153570DC21291436F67A1AA0968529835276A9BD354283756BEE56"
+"C#\Shared Logics\DriveLetterMapper.cs","DriveLetterMapper.cs","2C815AACA365D7E93AEFF74E6AFD788D1A02AD928CB55FD0E93BB0D748C588A240888C61D3A9DE72FD7ED4485E2294F362879E1821D85903D6257E88ADAA93B9"
+"C#\Shared Logics\EditGUIDs.cs","EditGUIDs.cs","62CDF835E8B7B32FBBA09897BE3ACCD0D7FAFE6A1CDB0A77694BF49F36D3CA14CC9F2B11BB667EFCD129C093F6B331C065511AE507A4BBF4649BE63931FDA5E1"
+"C#\Shared Logics\EventLogUtility.cs","EventLogUtility.cs","430C0BD786BAE0FFF3A0B498861BAE324C303E091F7DC535DBC74E54EA5FAB692C7D3851426A3A4F2BBE0BE120671B213219F6B69359E3EA73AA00C02A5A3D20"
+"C#\Shared Logics\FileDirectoryPathComparer.cs","FileDirectoryPathComparer.cs","75BE831135138B4566AAA29D5581EA913A5E8C2741F7C2910F9905D97F05CBF420DD0EEFCE294BE26FCC30471B24ABEEB54A8CBC93129C1545290EBED6A390FF"
+"C#\Shared Logics\FileSystemPicker.cs","FileSystemPicker.cs","6FFB5DD553F1C9192985438E7919AD9B572C40F51B8DEDF7164046A0436B1DB2026BA8AFAF731BC4F730D8A1A910926FB2F481DD114D2E886EE1CD45E47CAC97"
+"C#\Shared Logics\GetExtendedFileAttrib.cs","GetExtendedFileAttrib.cs","E951B706A90A68180ACC21FE2F16A6F994B42E29A936565DB932A53F95880768A15F004F36B47D8B76DF8C7A6306432FBE0BED09AD41EFE8EC8A2871E7E3DE9B"
+"C#\Shared Logics\GetFilesFast.cs","GetFilesFast.cs","4C14280499C146F6E2749B0D49CC0509AD1434951C41ED5BCEB8965A66C50449447A6ADD858DF597CBD1FCB1E74F463EA2C5BAF29536700B7B3F9CAD0C9A9055"
+"C#\Shared Logics\GetOpusData.cs","GetOpusData.cs","7ADB61AD5BA2D4176B9DC2066CB9A6A773DB218DE8D8427E5E8FD7CED33311728686871D59A4374DF4E0C3E88A4CC4618CB87C911D1186E3AC4D6525698C44E7"
+"C#\Shared Logics\Initializer.cs","Initializer.cs","C86314F4C30564EAD334BD1DCCACC174320157BB75FECA100CF83191651BD1D9F8D26721E90B75217D14D589700EB789ACB9CBFD49639A4BAFC042F4A38A058E"
+"C#\Shared Logics\MeowOpener.cs","MeowOpener.cs","C589C9A9C76362A08DD93D5088337CFB130EAA50DE783AA0AFB4C5A3548845CD28C0715304A2A47B0B0F53E075A5FEC50ECB4FB0505F9D514D9E227A050B0A31"
+"C#\Shared Logics\MoveUserModeToKernelMode.cs","MoveUserModeToKernelMode.cs","CE12C1100E697F1F7B70F155B8ACB925774FC4B4BA1880B2F0CC8D67BEC4C29EE0480743FE1F8619690247862F39313FB61370B8A65FFD9F982D6F2C08DA99EE"
+"C#\Shared Logics\PageHashCalc.cs","PageHashCalc.cs","3CA4F77595FF9F98870FBD50DCDCAE0CE99671B93A87EF52A98DABC9E3918B6800E94F03BDE72E0F769F73D67523247F9EF804E7A9FDE73BD27BFC15E4D4D01F"
+"C#\Shared Logics\PolicyFileSigningStatusDetection.cs","PolicyFileSigningStatusDetection.cs","539B53D3CD39E61ADDEA3922E0FCC8189FCA0EA52FC3B32A73B22E9E63E661A44005845826089FAFCBA5CEC2360A162609E81EBD7A6A7D8F3B7579680B5F9823"
+"C#\Shared Logics\PolicyMerger.cs","PolicyMerger.cs","29DCC68F78B87FD5F8B69EA9FF757FC019A05BEA09155D2D6B20A325486925BB5749BFAFC1C02D61B4DB7A354CFA4BA838A6F0D1D36D864C9A133795386878D7"
+"C#\Shared Logics\PolicyToCIPConverter.cs","PolicyToCIPConverter.cs","7D98ED90EAB43225C591579CDE9E143FA1DA75A2BF0EF06A87BE18A6A02D6019D17F15B04344DADD84ADB862392786FD5D1A226CB0CE72D9FA6B64E0CDDC0CBC"
+"C#\Shared Logics\PowerShellExecutor.cs","PowerShellExecutor.cs","59FE223B5404D78638107B892BB6623A7AEEE48160C68C6ABF5C0AB0978659595BF01C5356366297BA9832720658B85816E0A9FD388196AF2DCA5F8BB2CC635F"
+"C#\Shared Logics\RemoveSupplementalSigners.cs","RemoveSupplementalSigners.cs","A5C8E6AC4012EB34D7A289975749769ED3390D84C149239E149E9DED4200922E5EFF9A4F04A642D08149FD36178657F78D24B4935B903A97891FD18D9238752A"
+"C#\Shared Logics\ScanLevelz.cs","ScanLevelz.cs","4459B1FA44FEE190DDCB89F5453B4B9B1F23E464FF2E192E04BD639E06F4D014AC4A70FCC0769270379B7ADE3932D0626EC9F2A8B464195ED4C5F363E6904E2C"
+"C#\Shared Logics\SecureStringComparer.cs","SecureStringComparer.cs","54E63D84A02150CCE561CC22CA283F833282D83CDCE01FAD10D0024A0306DB8AF15928E4AB80F7553DC61640B705ED1411A8B7FDA3C2820499308439008856A1"
+"C#\Shared Logics\SignToolHelper.cs","SignToolHelper.cs","64BA5A6287F51F23BBD4871EF6028D8B934A84A6CB3B5C6A344A7F6E0E45730C590DB4573A83C6A64BDDD674B3B79093F652AAE5BE585D57EE1D1ACDE922B94E"
+"C#\Shared Logics\SnapBackGuarantee.cs","SnapBackGuarantee.cs","EB1B9D81CE33AC858F6103FC1348F5EF3AB2A186C15E34DE3E1268E3FFB3ABBECB921DC7A79A7BF5BF0D715369D8D4AC3205F3DACB9FDB50E250F2E8A48C883B"
+"C#\Shared Logics\StagingArea.cs","StagingArea.cs","A0635D40B248AA87DB13F1429D727D0A2222454B2E2E991A4C32413F356C982CB05F7366DE7B726454F1945FEA71000ACC9C66D56CE12B9B41DEE0652B4BDB51"
+"C#\Shared Logics\SupplementalForSelf.cs","SupplementalForSelf.cs","0EE8E08C13A1FE6226BFAE1DC272C9501DD73CF44F9B8627130A9EF600738615AA646644AC6423EBAAFF9A31D7B11FD32E009CC467C7A4EA4EB94503A8FE2112"
+"C#\Shared Logics\VersionIncrementer.cs","VersionIncrementer.cs","97390959BC6A800301F152F504895B20A618309EF004143A8E32247078177B054AB2FB2BDF3C2FDBE3B8E529BE413BA5A89CFE943ECACC3F04280C8210CBF3BE"
+"C#\Shared Logics\WldpQuerySecurityPolicy.cs","WldpQuerySecurityPolicy.cs","C1941F387AA49E3E853B4A277DC488A6158A210C6C29F6C5FC9E365D0D359013165BA3DDBD4B917B978A2DC68E139DD96F1900282B936EBE3655E00074B76703"
+"C#\Shared Logics\XmlFilePathExtractor.cs","XmlFilePathExtractor.cs","57389456B872C894062F995089A8DABAB2C9CBA9DA47B498B004BC4AE0CE1D0CD423C009144C43643C6F597FF64BA49C730818624FA00CF7E28D71B6BF6F9ABA"
+"Resources\User Configurations\Schema.json","Schema.json","D9D8391DAA994B8AE33433070A9438B4EAE5EFF4E00652E26A7C19870211B092991F6C4A8577D31255016369F4C5956A34A0404B78CB091AABC1043833C5CF79"
+"Resources\WDAC Policies\DefaultWindows_Enforced_Kernel.xml","DefaultWindows_Enforced_Kernel.xml","4D1EFC2EC8AE373A7FDA3BC8666BF41A2D603FE150FA6F755439A6B1EF7352EAC687EED61888AB4478123D8A5BD7B3CD22BB48EB9192ACF3E75F4F917C8A1A64"
+"Resources\WDAC Policies\DefaultWindows_Enforced_Kernel_NoFlights.xml","DefaultWindows_Enforced_Kernel_NoFlights.xml","A50C9102ABF310CB5A0AE062E29EC45390C0DF192AA62E0F428804A0C9F0BBA704D22BFC41956886AFCA4342A64B91B30A6F2EA4DA0FAC2CF0367B3B46290706"
+"Resources\WDAC Policies-Archived\DefaultWindows_Enforced_Kernel.xml","DefaultWindows_Enforced_Kernel.xml","6AD8A2005DC250814353E9006A9B03F2F6E7633877C8590130A24985965C1C7F58AB1A40C00B0A9F7D80BAFBFFB1FC5091931FA1FF732DFB3AF321CEB7DAAD08"
+"Resources\WDAC Policies-Archived\DefaultWindows_Enforced_Kernel_NoFlights.xml","DefaultWindows_Enforced_Kernel_NoFlights.xml","046CF9A95CCF5288AF1D2BCFAB91E1CB3FB767A9E5B4131CEA4F4CBD4CD21AD36332AC304AA2E06D4509E77BD07309AB5EDC9978E84F51FFA4169D1CABBAB319"
+"Resources\WDAC Policies-Archived\Readme.md","Readme.md","80E8A8638027931E613409A3F80847EAF0D929D382A3A8FD996E6152FA25591CAE9D06AA7E5E3D7B4CCD38E912CEA0B22A1AAE8BA34DD00D202852ADE673493F"
+"C#\Shared Logics\Logging\Logger.cs","Logger.cs","09E1EC92DEEA93B4500ABD186807D70E7A485ACE01E305D4714568E8D44937F2BDDBB53D995724DAEA4483B1564C0345B473DD7D5FE1D3ED766A355FBA277DAA"
+"C#\Shared Logics\Logging\LoggerInitializer.cs","LoggerInitializer.cs","2AA9704711AAE853D594BAFC248C333DCD52F18484CFFCD1083A1FE806820C74BBF37873DE6B918D8D3368AB5BBDA0C93109A1AC83ED29842A73AA5B0BE215B5"
+"C#\Shared Logics\Main Cmdlets\AssertWDACConfigIntegrity.cs","AssertWDACConfigIntegrity.cs","C741C1C96F112B3D91E690186839C406D11135278EBE82301CE85555A744F615D7ABB91046EAF3BB3B17BBC3583DF5FF6F073C59E5CA19E853F152819B1016DB"
+"C#\Shared Logics\Main Cmdlets\BasePolicyCreator.cs","BasePolicyCreator.cs","9CACC3526625D865558869D5037190D280C8385B52F52D54C7EE73CE0D9AEB44728A1EC5716C007481B2D7018F9697B089ABC8A7C92D8D0290C06909A860CD9C"
+"C#\Shared Logics\Main Cmdlets\GetCiFileHashes.cs","GetCiFileHashes.cs","1E2BF8D04A3CE1010CA8375AEF6FE3B1CD68541AD9C05CC89550CD4CC9B5F3B4E0E59AFB6469A3133499A1CFD14E036B76279FEDF946554FDDA833BA85C80813"
+"C#\Shared Logics\Main Cmdlets\GetCIPolicySetting.cs","GetCIPolicySetting.cs","1A6072C733219877EE1F8DA02AAFFB6A6C783284AE2E9BB240B715E7C2930B8B15D8978EE90E29EE2B65944B5F8DD240FCF25FA44148051BF5A1C5EB83225303"
+"C#\Shared Logics\Main Cmdlets\InvokeWDACSimulation.cs","InvokeWDACSimulation.cs","412A31AAF1CE2F9F4E3FAF65C577EB49F6AC1D03E89D17D931AAEFACEF93D36427CE483A8DA52D2F004D36F14030F52C73FDB47D059D8E96D23E1D61F15FEEAF"
+"C#\Shared Logics\Main Cmdlets\SetCiRuleOptions.cs","SetCiRuleOptions.cs","5A0F20057D5498E1CEDF52779543449602EE49054E2E372930EC26026C8774832C02C325E73D21C6AA34E6A0498A3FB92F1D073D4FA71854E40A39EA7A2E181D"
+"C#\Shared Logics\Main Cmdlets\TestCiPolicy.cs","TestCiPolicy.cs","94CECE28F9A32C8E17C561E84BC33DF4A836A61EFAF9BC32DEE32856E3EF42D5BBCDDC9422917C889257EC5415506F126C4F3903840F4A55418101B8900497A7"
+"C#\Shared Logics\Main Cmdlets\UserConfiguration.cs","UserConfiguration.cs","666AB35310ED2CECFFF8C24ACE676E2AD11A7F4BA36D740DC3D38AD6758F0727E7626A97D016845B2D0ACEEFB594C3F163C5D19CD129024928A4C4A6323B70B8"
+"C#\Shared Logics\Types And Definitions\AuthenticodePageHashes.cs","AuthenticodePageHashes.cs","5DA1BA562B79A60098961187801E0F2696CF5F0652460F3BB92EA32B9653FE581F8556D07F0C67EC46A1D7E9020C591399C0A4E82BFAA937FFBE27309416878B"
+"C#\Shared Logics\Types And Definitions\CertificateDetailsCreator.cs","CertificateDetailsCreator.cs","65BC5095E89D1ECA40BDFE31F30FF41C7663D27574B702ABAE6A6DDFFE11E174FD1921D84D8E1EA3209A17763457F7DFBC0590C4167FFAE78162EAE66C5EE4C7"
+"C#\Shared Logics\Types And Definitions\CertificateSignerCreator.cs","CertificateSignerCreator.cs","51F30B59B6590ACC301DA7FCE8C5EDD9437C3084697B1D862B49F360EAAEE1A1BB6C4BE2C0487F3093244BFC8FC2450FEEF02D6D3ED1013C07A8344A655ABD2A"
+"C#\Shared Logics\Types And Definitions\ChainElement.cs","ChainElement.cs","B2D0CEE364C80C48976E2613D63AE562980A57FD68128AD88A47F6DF3B9F0F13CB506DC6385A7811FFC27B503C2A88D238E1CD30DC390604DDF1AF03EEA8C7E7"
+"C#\Shared Logics\Types And Definitions\ChainPackage.cs","ChainPackage.cs","69825F12DE650F5CA5DB1A5668FD8B86F9112720D33E09C957EE8E6C11BFC5922BAE75B08907477201C51AEAE0DE668938F912B11FB6BAAFC8DC8818EFB99555"
+"C#\Shared Logics\Types And Definitions\CodeIntegrityPolicy.cs","CodeIntegrityPolicy.cs","314D128914961D46B14255DF37CE8FDF547FE373B4AD7C455F6C098B5174245B72A4A12E74F56DD3484B5F30BE4F930930D75D5EF9DC1608DCF0E71E54BB1AE3"
+"C#\Shared Logics\Types And Definitions\FileBasedInfoPackage.cs","FileBasedInfoPackage.cs","58E04B52C587B0D7C930BB21FE4902157C5F48A6CC45F389C99E236FD0747B8B96E3811EDD14D582B7586F36C68F7F99D5D5562B7472D89978270EC51F5A66C3"
+"C#\Shared Logics\Types And Definitions\FilePublisherSignerCreator.cs","FilePublisherSignerCreator.cs","BF84C05961C09942DFB3D726EB3B15CD7DC997DA96F511C3E448F006D18A4FAD1D8ECAA5B9952DF42F7B8BE5EE0C4542705F3D8AE942E591F981BD186E115C77"
+"C#\Shared Logics\Types And Definitions\HashCreator.cs","HashCreator.cs","26D60846ED5561077AEF9961C4EDF4DDF82C305726F9B8870B3C16D72A6A5CEDEF722C3249578AAA66A77D31479A72C1544E0C677498916613F60102F3D32668"
+"C#\Shared Logics\Types And Definitions\OpusSigner.cs","OpusSigner.cs","C3BD7183DC28395C2735EDE0E159B39A795DDA0D5CE86643A718FD3EE471DBBD735EA6886C09E0AFEC2111DBFA2B04DB2BB8DDC92F6F9509C3FE359A72695DF3"
+"C#\Shared Logics\Types And Definitions\PolicyHashObj.cs","PolicyHashObj.cs","080DEB5A774F4C40311679E91E84B018234F9919B574D8E1111D28FB861748B3F3EF8AF0C7C2C3B811E3FCAB9DDBF5274B45170A6C38717C77F837A210D880FD"
+"C#\Shared Logics\Types And Definitions\PublisherSignerCreator.cs","PublisherSignerCreator.cs","C28483404BBA8A9C94E7945FF2C50D314797BCB29E3C2497AE5076DCC2E87EECF5CE7F9623A9B58E1925747AB53F5B4EFE5144813179FBC2F7DD5B64F5ADE82B"
+"C#\Shared Logics\Types And Definitions\Signer.cs","Signer.cs","4EDE0AD45D4C99548DCEA7985F1DAAB7F80A27E28520271FAE1CCEC7E5881125843D4159A546D5E6AECD0FDF62BE4D3A8B1F03914A2A87932E2F49E6D479F2D6"
+"C#\Shared Logics\Types And Definitions\SimulationInput.cs","SimulationInput.cs","6051874A10341F2D88B21A6E3C27F5B8D9DC1C3B8D941E610ECE95CE5A1447CF79AE43C2767AD000CDC68B7810C3D1E51DB7159DFA420BAE39E3DCEEF69BCD74"
+"C#\Shared Logics\Types And Definitions\SimulationOutput.cs","SimulationOutput.cs","8AE20635485A59399A0CAEE5971F3E6EED6A07BAF42EFB3E1713C6B17DCB63B77A6FD400D5D4B407F64F133B4D2B47D726BFCC6C3FDDF71E791451460F650882"
+"C#\Shared Logics\Types And Definitions\WinTrust.cs","WinTrust.cs","D4901CB08A6DE007E9AD17539ED187D4CCC433305E3C1BC8254CE31D7313EA13FADEBDF9A6CA14F55271B78EEF6AC652B6166773FD57468F625FF823BCE7FF59"
+"C#\Shared Logics\Variables\CILogIntel.cs","CILogIntel.cs","07F50AB2A202207CE05F9C7CF1D90BE9D9A6C4734999CBF4D73AA74A8382D6929C434E4A2690211093671EB8DEAA2E01D86FCCBB5CE28EF9D155C1BB73D7BF8A"
+"C#\Shared Logics\Variables\GlobalVars.cs","GlobalVars.cs","D778937F479F530893F94A3E1A6B6F1BA02CFA020220589C3D1595A62BF6371C93A2141DB83258907600425EE0B0E3D42A5FD2883BC6DBF34398DAF75B541C03"
+"C#\Shared Logics\WDAC Simulation\Arbitrator.cs","Arbitrator.cs","0743177A322DA1306CC1609F1F6971ABAF1F214C2A6321C68D87693AAEA7D72D7022B4F1FF9F827E4A39292A8DB71BF5C45A0CA480F43A3A1C831ADF4A19330F"
+"C#\Shared Logics\WDAC Simulation\GetCertificateDetails.cs","GetCertificateDetails.cs","ECB86C01EC7CD6993D4AC8581DDCE16A1CE98397B9F6BE19857898B7B31232378079C345D649FF59BEE68D8A95E5D003670207911704CA0EB6782A1AD87A3DEC"
+"C#\Shared Logics\WDAC Simulation\GetFileRuleOutput.cs","GetFileRuleOutput.cs","40771AC1A836CC9DB2CB76EECC17446EB25B6A5061AFB931AADBE8DCB51D2CE7E7D55EEE6926B7EC077FBA7A2D916C96332EB26B888B34917B8303EAE19EDC47"
+"C#\Shared Logics\WDAC Simulation\GetSignerInfo.cs","GetSignerInfo.cs","15E98D3E45143B5290B7A56D6F7363D64FC016CBCBC86D66F045E8173F993AB353C29B49706E65E4963A00D2202A14B0C53C0DAEFA30DCF5AC500F66C949D443"
+"C#\Shared Logics\XMLOps\ClearCiPolicySemantic.cs","ClearCiPolicySemantic.cs","1712C4EAA78DA352E77DC39CC433037CFEEAB0D2E829DF09AD141FC2CA8E9B56B746625FAB4EE53DE436B04CB7676D42F6A2A3C1326E24712E89DEAADF64EA17"
+"C#\Shared Logics\XMLOps\CloseEmptyXmlNodesSemantic.cs","CloseEmptyXmlNodesSemantic.cs","954833CE973415F135476C3CF45BB14FDD287F2E5E95B9122504A252E3963443ACE2378AFEFADC07816988FC3A72A082A83BD36CAA9AFDF4892620B7AB6E61BC"
+"C#\Shared Logics\XMLOps\Macros.cs","Macros.cs","B61C8F2D49615EDD65A19485980C1B092109A30B16E959B58AC63F826D5D5CDAC1F3BAB667DE7FA61D3411EF879D4413F0F7B2C59E60B69A44AB5EB9E61BA463"
+"C#\Shared Logics\XMLOps\NewCertificateSignerRules.cs","NewCertificateSignerRules.cs","326725AF782D43C4250D9ABC0E9D2294ACE95FA80BDD0E466249C5254F24E09BEA993BBF7508A46EE67DD13F9714C207A20B20E42F7B93B92FEA07A218D2DE18"
+"C#\Shared Logics\XMLOps\NewFilePublisherLevelRules.cs","NewFilePublisherLevelRules.cs","A272201A618178F432F4DD5219ACE6BCD81CC0F2840EDFED9437A6C7FF70017B748EF1C3405AA20268BAD7B7EAC3678959218A4D7A30B9C12945B9FD9D3C2A2E"
+"C#\Shared Logics\XMLOps\NewHashLevelRules.cs","NewHashLevelRules.cs","15670A8FB59EEEE2D69C699E0BD7CE882A014F3FBB91868F75F1B21FA6938B28EC0580B391B016AE0F5BF44A7094F1522E7057A20B6BCF060A8C03C37EDBA9D7"
+"C#\Shared Logics\XMLOps\NewPFNLevelRules.cs","NewPFNLevelRules.cs","B138069DB3368C69F7CD0318AED81A291316FCE4610A929733FE079B6B5B586AAE0D493E3E0665716FAAC2A955269968EE00F2285222058754FE053C8CA008F9"
+"C#\Shared Logics\XMLOps\NewPublisherLevelRules.cs","NewPublisherLevelRules.cs","19DC734F5BDC96AB86A1DC7EBC3734C5C4F65D51AD7C23C0CB71491D19622F84F6D5CDF9BD1C8EC3D5EE002C540006EB0B56D28D1841CFA46368A275330A170F"
+"C#\Shared Logics\XMLOps\RemoveAllowElementsSemantic.cs","RemoveAllowElementsSemantic.cs","2BB1A0C0AE2BFC6BC48D60E3B2E2944F50453F8C50B144A9D18C3D8DB2334BBFB2204D967F32C12C89A3604AAA1FA9A2FAAE7D7E6FC5971F31520B22D190447B"
+"C#\Shared Logics\XMLOps\RemoveUnreferencedFileRuleRefs.cs","RemoveUnreferencedFileRuleRefs.cs","AE6C0B6BA84C86D648F7360D887F19AFE0D09FA9A0AFB7C400F6DC73D823E7BDC2D6145A76A74DE9CDF0FC3F358CD76DE32B5A61C5983BD9578AC60F1CE1B29D"
+"C#\Shared Logics\XMLOps\SetCiPolicyInfo.cs","SetCiPolicyInfo.cs","6BF8DB217772D2DEC981BDD202A799087A25FEADAFDBAEEA5E9790E52754EA3D4592197582F23644F948613539D15C137216E3F9F91187C339AF29BF3C0382AC"
+"C#\Shared Logics\XMLOps\SignerAndHashBuilder.cs","SignerAndHashBuilder.cs","826538D9D4C58EB56A10171FCC75A5A83B2B9E8AE5F277E56E6C2D5517A0CA8FDE17D570405E61C8579066DFB7FDE7AFD30DBFD3CD5F034E7B60CED50598C801"
+"C#\Shared Logics\XMLOps\UpdateHvciOptions.cs","UpdateHvciOptions.cs","EF137821AB4F252C9086C0C18032ED4A80AA12193E64F3E8E058D54C030FEF3AEE6089F3EE51D0A5C7FE3BBDA8EC2CAEFCD4AA66271A89EEC283719904971086"
diff --git a/WDACConfig/Utilities/Invoke-WDACConfig.ps1 b/WDACConfig/Utilities/Invoke-WDACConfig.ps1
index 07a7a3eed..5da01a28a 100644
--- a/WDACConfig/Utilities/Invoke-WDACConfig.ps1
+++ b/WDACConfig/Utilities/Invoke-WDACConfig.ps1
@@ -12,4 +12,4 @@ Import-Module -FullyQualifiedName "$ScriptFilePath\..\WDACConfig Module Files\WD
# Converts the markdown help file to XML format for the ConvertTo-WDACPolicy cmdlet
# New-ExternalHelp -Path "$ScriptFilePath\..\WDACConfig Module Files\Help\ConvertTo-WDACPolicy.md" -OutputPath "$ScriptFilePath\..\WDACConfig Module Files\Help\ConvertTo-WDACPolicy.xml" -Force | Out-Null
# Get-Help ConvertTo-WDACPolicy -Full
-[WDACConfig.InvokeWDACSimulation]::Invoke("D:\testtt\tap_ovpnconnect - Copy (4).sys", "D:\testtt\SupplementalPolicy SS1.xml", $true)
+
diff --git a/WDACConfig/WDACConfig Module Files/.NETAssembliesToLoad.txt b/WDACConfig/WDACConfig Module Files/.NETAssembliesToLoad.txt
index 2057de1b1..f30b8c737 100644
--- a/WDACConfig/WDACConfig Module Files/.NETAssembliesToLoad.txt
+++ b/WDACConfig/WDACConfig Module Files/.NETAssembliesToLoad.txt
@@ -28,4 +28,5 @@ System.Runtime.InteropServices
System.Windows.Forms.Primitives
System.ComponentModel.Primitives
System.Security.Cryptography.Pkcs
+System.Diagnostics.FileVersionInfo
System.Security.Cryptography.X509Certificates
\ No newline at end of file
diff --git a/WDACConfig/WDACConfig Module Files/C#/Shared Logics/ConfigureISGServices.cs b/WDACConfig/WDACConfig Module Files/C#/Shared Logics/ConfigureISGServices.cs
index 78eaddd13..8a82adfd1 100644
--- a/WDACConfig/WDACConfig Module Files/C#/Shared Logics/ConfigureISGServices.cs
+++ b/WDACConfig/WDACConfig Module Files/C#/Shared Logics/ConfigureISGServices.cs
@@ -1,6 +1,6 @@
namespace WDACConfig
{
- internal static class ConfigureISGServices
+ public static class ConfigureISGServices
{
///
/// Starts the AppIdTel and sets the appidsvc service to auto start
diff --git a/WDACConfig/WDACConfig Module Files/C#/Shared Logics/SignToolHelper.cs b/WDACConfig/WDACConfig Module Files/C#/Shared Logics/SignToolHelper.cs
index cc4af4054..3fc085aa8 100644
--- a/WDACConfig/WDACConfig Module Files/C#/Shared Logics/SignToolHelper.cs
+++ b/WDACConfig/WDACConfig Module Files/C#/Shared Logics/SignToolHelper.cs
@@ -1,6 +1,11 @@
using System;
using System.Diagnostics;
using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Net.Http;
+using System.Runtime.InteropServices;
+using System.Text.Json;
#nullable enable
@@ -64,5 +69,204 @@ public static void Sign(FileInfo ciPath, FileInfo signToolPathFinal, string cert
throw new InvalidOperationException($"SignTool failed with exit code {process.ExitCode}. Error: {error}");
}
}
+
+
+ ///
+ /// Downloads the latest version of the Microsoft.Windows.SDK.BuildTools NuGet package.
+ /// Extracts the SignTool.exe from it and returns the path to it.
+ /// Copies it to the User Configurations directory.
+ ///
+ private static string Download()
+ {
+ DirectoryInfo stagingArea = StagingArea.NewStagingArea("GetSignTool");
+
+ using HttpClient client = new();
+
+ string packageName = "Microsoft.Windows.SDK.BuildTools";
+
+ Logger.Write("Finding the latest version of the Microsoft.Windows.SDK.BuildTools package from NuGet");
+
+ // Get the list of versions
+ string versionsUrl = $"https://api.nuget.org/v3-flatcontainer/{packageName}/index.json";
+ string versionsResponse = client.GetStringAsync(versionsUrl).GetAwaiter().GetResult();
+
+ // Parse the JSON to get the latest version
+ JsonDocument versionsJson = JsonDocument.Parse(versionsResponse);
+ JsonElement versions = versionsJson.RootElement.GetProperty("versions");
+ string? latestVersion = versions[versions.GetArrayLength() - 1].GetString() ?? throw new InvalidOperationException("Failed to get the latest version of the package.");
+
+ // Construct the download link for the latest version's .nupkg
+ string downloadUrl = $"https://api.nuget.org/v3-flatcontainer/{packageName}/{latestVersion}/{packageName}.{latestVersion}.nupkg";
+
+ Logger.Write($"Downloading the latest .nupkg package file version '{latestVersion}' from the following URL: {downloadUrl}");
+
+ // Download the .nupkg file
+ string filePath = Path.Combine(stagingArea.FullName, $"{packageName}.{latestVersion}.nupkg");
+ using (Stream downloadStream = client.GetStreamAsync(downloadUrl).GetAwaiter().GetResult())
+ using (FileStream fileStream = new(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
+ {
+ downloadStream.CopyTo(fileStream);
+ }
+
+ Logger.Write($"Downloaded package to {filePath}");
+
+ // Extract the .nupkg file
+ string extractPath = Path.Combine(stagingArea.FullName, "extracted");
+ ZipFile.ExtractToDirectory(filePath, extractPath);
+
+ Logger.Write($"Extracted package to {extractPath}");
+
+
+ string binDirectoryPath = Path.Combine(extractPath, "bin");
+ // Get the directory that has the version, since it varies we need to get it implicitly
+ string[] versionDirectories = Directory.GetDirectories(binDirectoryPath);
+
+ if (versionDirectories.Length == 0)
+ {
+ throw new DirectoryNotFoundException("No version directories found in 'bin'.");
+ }
+
+ // There should be only one
+ string versionDirectory = versionDirectories.First();
+ string signtoolPath = Path.Combine(versionDirectory, "x64", "signtool.exe");
+
+ if (!File.Exists(signtoolPath))
+ {
+ throw new FileNotFoundException("signtool.exe not found in the expected path.");
+ }
+
+ // The final path that is in the User configurations directory and will be returned and saved in User configs
+ string finalSignToolPath = Path.Combine(GlobalVars.UserConfigDir, "SignTool.exe");
+
+ File.Copy(signtoolPath, finalSignToolPath, true);
+
+ Directory.Delete(stagingArea.ToString(), true);
+
+ Logger.Write($"Path to signtool.exe: {finalSignToolPath}");
+
+ return finalSignToolPath;
+
+ }
+
+
+ ///
+ /// Verifies if the SignTool.exe is of a version greater than one specified in the method
+ ///
+ ///
+ ///
+ private static bool Verify(string filePath)
+ {
+ try
+ {
+ FileVersionInfo fileInfo = FileVersionInfo.GetVersionInfo(filePath);
+ return (new Version(fileInfo.ProductVersion!) > new Version("10.0.22621.2428"));
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+
+
+ ///
+ /// Returns the architecture of the current OS
+ ///
+ ///
+ ///
+ private static string GetArchitecture()
+ {
+ if (RuntimeInformation.OSArchitecture is Architecture.X64)
+ {
+ return "x64";
+ }
+ else if (RuntimeInformation.OSArchitecture is Architecture.Arm64)
+ {
+ return "arm64";
+ }
+ else
+ {
+ throw new InvalidOperationException("Only X64 and ARM64 platforms are supported.");
+ }
+ }
+
+
+
+ ///
+ /// Gets the path to SignTool.exe and verifies it to make sure it's valid
+ /// If the SignTool.exe path is not provided by parameter, it will try to detect it automatically by checking if Windows SDK is installed
+ /// If the SignTool.exe path is not provided by parameter and it could not be detected automatically, it will try to download it from NuGet
+ ///
+ ///
+ ///
+ public static string GetSignToolPath(string? filePath = null)
+ {
+ // The path to return at the end
+ string? signToolPath = null;
+
+ // If Sign tool path wasn't provided by parameter or it doesn't exist on the file system, try to detect it automatically
+ if (string.IsNullOrWhiteSpace(filePath) && !Path.Exists(filePath))
+ {
+
+ try
+ {
+
+ Logger.Write("SignTool.exe path was not provided by parameter, trying to detect it automatically");
+
+ string baseDir = @"C:\Program Files (x86)\Windows Kits\10\bin";
+ string targetArchitecture = GetArchitecture();
+
+ // Get the directory with the highest version in its name
+ string? latestSigntoolPath = Directory.GetDirectories(baseDir)
+ .Select(dir => new DirectoryInfo(dir))
+ .Where(dir => Version.TryParse(Path.GetFileName(dir.Name), out _)) // Ensure directory is a version
+ .OrderByDescending(dir => new Version(dir.Name)) // Order by version
+ .First().ToString(); // Get the highest version
+
+ if (latestSigntoolPath is not null)
+ {
+ // Construct the full SignTool.exe path
+ string constructedFinalPath = Path.Combine(latestSigntoolPath, targetArchitecture, "signtool.exe");
+
+ // If it checks out, assign it to the output variable
+ if (Verify(constructedFinalPath))
+ {
+ signToolPath = constructedFinalPath;
+ Logger.Write($"Successfully detected the SignTool.exe on the system: {constructedFinalPath}");
+ }
+ }
+
+ }
+ catch (Exception ex)
+ {
+ Logger.Write($"Failed to detect SignTool.exe path automatically: {ex.Message}");
+ }
+
+ }
+
+ // If Sign tool path was provided by parameter, use it
+ else
+ {
+ Logger.Write("SignTool.exe path was provided by parameter");
+
+ if (Verify(filePath))
+ {
+ Logger.Write("The provided SignTool.exe is valid");
+ signToolPath = filePath;
+ }
+ else
+ {
+ Logger.Write("The provided SignTool.exe is not valid");
+ }
+ }
+
+ // Download the SignTool.exe if it's still null
+ signToolPath ??= Download();
+
+ Logger.Write($"Setting the SignTool path in the common user configurations to: {signToolPath}");
+ _ = UserConfiguration.Set(SignToolCustomPath: signToolPath);
+
+ return signToolPath;
+ }
}
}
diff --git a/WDACConfig/WDACConfig Module Files/C#/Shared Logics/StagingArea.cs b/WDACConfig/WDACConfig Module Files/C#/Shared Logics/StagingArea.cs
index 51839f7a5..9bd8da5e6 100644
--- a/WDACConfig/WDACConfig Module Files/C#/Shared Logics/StagingArea.cs
+++ b/WDACConfig/WDACConfig Module Files/C#/Shared Logics/StagingArea.cs
@@ -7,6 +7,12 @@ namespace WDACConfig
{
public static class StagingArea
{
+ ///
+ /// Creating a directory as a staging area for a job and returns the path to that directory
+ ///
+ ///
+ ///
+ ///
public static DirectoryInfo NewStagingArea(string cmdletName)
{
if (string.IsNullOrWhiteSpace(cmdletName))
diff --git a/WDACConfig/WDACConfig Module Files/Core/Deploy-SignedWDACConfig.psm1 b/WDACConfig/WDACConfig Module Files/Core/Deploy-SignedWDACConfig.psm1
index e0892923d..8cd6edaa5 100644
--- a/WDACConfig/WDACConfig Module Files/Core/Deploy-SignedWDACConfig.psm1
+++ b/WDACConfig/WDACConfig Module Files/Core/Deploy-SignedWDACConfig.psm1
@@ -40,9 +40,6 @@ Function Deploy-SignedWDACConfig {
Begin {
[WDACConfig.LoggerInitializer]::Initialize($VerbosePreference, $DebugPreference, $Host)
- [WDACConfig.Logger]::Write('Importing the required sub-modules')
- Import-Module -Force -FullyQualifiedName @("$([WDACConfig.GlobalVars]::ModuleRootPath)\Shared\Get-SignTool.psm1")
-
if (-NOT $SkipVersionCheck) { Update-WDACConfigPSModule -InvocationStatement $MyInvocation.Statement }
if ([WDACConfig.GlobalVars]::ConfigCIBootstrap -eq $false) {
@@ -54,12 +51,7 @@ Function Deploy-SignedWDACConfig {
#Region User-Configurations-Processing-Validation
# Get SignToolPath from user parameter or user config file or auto-detect it
- if ($SignToolPath) {
- [System.IO.FileInfo]$SignToolPathFinal = Get-SignTool -SignToolExePathInput $SignToolPath
- } # If it is null, then Get-SignTool will behave the same as if it was called without any arguments.
- else {
- [System.IO.FileInfo]$SignToolPathFinal = Get-SignTool -SignToolExePathInput ([WDACConfig.UserConfiguration]::Get().SignToolCustomPath)
- }
+ [System.IO.FileInfo]$SignToolPathFinal = [WDACConfig.SignToolHelper]::GetSignToolPath($SignToolPath ?? ([WDACConfig.UserConfiguration]::Get().SignToolCustomPath))
# If CertPath parameter wasn't provided by user, check if a valid value exists in user configs, if so, use it, otherwise throw an error
if (!$CertPath ) {
diff --git a/WDACConfig/WDACConfig Module Files/Core/Edit-SignedWDACConfig.psm1 b/WDACConfig/WDACConfig Module Files/Core/Edit-SignedWDACConfig.psm1
index 1240a7174..87f443d40 100644
--- a/WDACConfig/WDACConfig Module Files/Core/Edit-SignedWDACConfig.psm1
+++ b/WDACConfig/WDACConfig Module Files/Core/Edit-SignedWDACConfig.psm1
@@ -108,7 +108,6 @@ Function Edit-SignedWDACConfig {
[WDACConfig.Logger]::Write('Importing the required sub-modules')
Import-Module -Force -FullyQualifiedName @(
- "$([WDACConfig.GlobalVars]::ModuleRootPath)\Shared\Get-SignTool.psm1",
"$([WDACConfig.GlobalVars]::ModuleRootPath)\Shared\Receive-CodeIntegrityLogs.psm1",
"$([WDACConfig.GlobalVars]::ModuleRootPath)\Shared\Set-LogPropertiesVisibility.psm1",
"$([WDACConfig.GlobalVars]::ModuleRootPath)\Shared\Select-LogProperties.psm1",
@@ -128,12 +127,7 @@ Function Edit-SignedWDACConfig {
#Region User-Configurations-Processing-Validation
# Get SignToolPath from user parameter or user config file or auto-detect it
- if ($SignToolPath) {
- [System.IO.FileInfo]$SignToolPathFinal = Get-SignTool -SignToolExePathInput $SignToolPath
- } # If it is null, then Get-SignTool will behave the same as if it was called without any arguments.
- else {
- [System.IO.FileInfo]$SignToolPathFinal = Get-SignTool -SignToolExePathInput ([WDACConfig.UserConfiguration]::Get().SignToolCustomPath)
- }
+ [System.IO.FileInfo]$SignToolPathFinal = [WDACConfig.SignToolHelper]::GetSignToolPath($SignToolPath ?? ([WDACConfig.UserConfiguration]::Get().SignToolCustomPath))
# If CertPath parameter wasn't provided by user, check if a valid value exists in user configs, if so, use it, otherwise throw an error
if (!$CertPath ) {
diff --git a/WDACConfig/WDACConfig Module Files/Core/Remove-WDACConfig.psm1 b/WDACConfig/WDACConfig Module Files/Core/Remove-WDACConfig.psm1
index bb5731e25..b08b12a0e 100644
--- a/WDACConfig/WDACConfig Module Files/Core/Remove-WDACConfig.psm1
+++ b/WDACConfig/WDACConfig Module Files/Core/Remove-WDACConfig.psm1
@@ -142,9 +142,6 @@ Function Remove-WDACConfig {
Begin {
[WDACConfig.LoggerInitializer]::Initialize($VerbosePreference, $DebugPreference, $Host)
- [WDACConfig.Logger]::Write('Importing the required sub-modules')
- Import-Module -Force -FullyQualifiedName @("$([WDACConfig.GlobalVars]::ModuleRootPath)\Shared\Get-SignTool.psm1")
-
if (-NOT $SkipVersionCheck) { Update-WDACConfigPSModule -InvocationStatement $MyInvocation.Statement }
[System.IO.DirectoryInfo]$StagingArea = [WDACConfig.StagingArea]::NewStagingArea('Remove-WDACConfig')
@@ -155,12 +152,7 @@ Function Remove-WDACConfig {
if ($PSCmdlet.ParameterSetName -eq 'Signed Base') {
# Get SignToolPath from user parameter or user config file or auto-detect it
- if ($SignToolPath) {
- [System.IO.FileInfo]$SignToolPathFinal = Get-SignTool -SignToolExePathInput $SignToolPath
- } # If it is null, then Get-SignTool will behave the same as if it was called without any arguments.
- else {
- [System.IO.FileInfo]$SignToolPathFinal = Get-SignTool -SignToolExePathInput ([WDACConfig.UserConfiguration]::Get().SignToolCustomPath)
- }
+ [System.IO.FileInfo]$SignToolPathFinal = [WDACConfig.SignToolHelper]::GetSignToolPath($SignToolPath ?? ([WDACConfig.UserConfiguration]::Get().SignToolCustomPath))
# If CertCN was not provided by user, check if a valid value exists in user configs, if so, use it, otherwise throw an error
if (!$CertCN) {
diff --git a/WDACConfig/WDACConfig Module Files/Shared/Get-SignTool.psm1 b/WDACConfig/WDACConfig Module Files/Shared/Get-SignTool.psm1
deleted file mode 100644
index dc2d268b1..000000000
--- a/WDACConfig/WDACConfig Module Files/Shared/Get-SignTool.psm1
+++ /dev/null
@@ -1,137 +0,0 @@
-Function Get-SignTool {
- <#
- .SYNOPSIS
- Gets the path to SignTool.exe and verifies it to make sure it's not tampered
- If the SignTool.exe path is not provided by parameter, it will try to detect it automatically, either by checking if Windows SDK is installed or by reading the user configs (this part actually happens in the main cmdlet that calls Get-SignTool function)
- If the SignTool.exe path is not provided by parameter and it could not be detected automatically, it will ask the user to try to download it from NuGet
- .PARAMETER SignToolExePathInput
- Path to the SignTool.exe
- It's optional
- .INPUTS
- System.IO.FileInfo
- .OUTPUTS
- System.IO.FileInfo
- #>
- [CmdletBinding()]
- param(
- [parameter(Mandatory = $false)][System.IO.FileInfo]$SignToolExePathInput
- )
- Begin {
- [System.IO.DirectoryInfo]$StagingArea = [WDACConfig.StagingArea]::NewStagingArea('Get-SignTool')
- }
-
- Process {
-
- Try {
-
- # If Sign tool path wasn't provided by parameter, try to detect it automatically
- if (!$SignToolExePathInput) {
-
- [WDACConfig.Logger]::Write('SignTool.exe path was not provided by parameter, trying to detect it automatically')
-
- try {
- if ($Env:PROCESSOR_ARCHITECTURE -eq 'AMD64') {
- if ( Test-Path -Path 'C:\Program Files (x86)\Windows Kits\*\bin\*\x64\signtool.exe') {
- $SignToolExePathOutput = 'C:\Program Files (x86)\Windows Kits\*\bin\*\x64\signtool.exe'
- }
- else {
- Throw [System.IO.FileNotFoundException] 'signtool.exe could not be found'
- }
- }
- elseif ($Env:PROCESSOR_ARCHITECTURE -eq 'ARM64') {
- if (Test-Path -Path 'C:\Program Files (x86)\Windows Kits\*\bin\*\arm64\signtool.exe') {
- $SignToolExePathOutput = 'C:\Program Files (x86)\Windows Kits\*\bin\*\arm64\signtool.exe'
- }
- else {
- Throw [System.IO.FileNotFoundException] 'signtool.exe could not be found'
- }
- }
- }
- catch [System.IO.FileNotFoundException] {
-
- # If Sign tool path wasn't provided by parameter and couldn't be detected automatically, try to download it from NuGet, if fails or user declines this, stop the operation
-
- if ($PSCmdlet.ShouldContinue('Would you like to try to download it from the official Microsoft server? It will be saved in the WDACConfig directory in Program Files.', 'SignTool.exe path was not provided, it could not be automatically detected on the system, nor could it be found in the common WDAC user configurations.')) {
-
- if (-NOT (Get-PackageSource | Where-Object -FilterScript { $_.Name -ieq 'nuget.org' })) {
- [WDACConfig.Logger]::Write('Registering the nuget.org package source because it was not found in the system.')
- $null = Register-PackageSource -Name 'nuget.org' -ProviderName 'NuGet' -Location 'https://api.nuget.org/v3/index.json'
- }
-
- [WDACConfig.Logger]::Write('Finding the latest version of the Microsoft.Windows.SDK.BuildTools package from NuGet')
-
- # Use a script block to convert the Version property to a semantic version object for proper sorting based on the version number
- [Microsoft.PackageManagement.Packaging.SoftwareIdentity[]]$Package = Find-Package -Name 'Microsoft.Windows.SDK.BuildTools' -Source 'nuget.org' -AllVersions -Force -MinimumVersion '10.0.22621.3233'
-
- [Microsoft.PackageManagement.Packaging.SoftwareIdentity]$Package = $Package | Sort-Object -Property { [System.Version]$_.Version } -Descending | Select-Object -First 1
-
- [WDACConfig.Logger]::Write('Downloading SignTool.exe from NuGet...')
- $null = Save-Package -InputObject $Package -Path $StagingArea -Force
-
- [WDACConfig.Logger]::Write('Extracting the nupkg')
- Expand-Archive -Path "$StagingArea\*.nupkg" -DestinationPath $StagingArea -Force
-
- [WDACConfig.Logger]::Write('Detecting the CPU Arch')
- switch ($Env:PROCESSOR_ARCHITECTURE) {
- 'AMD64' { [System.String]$CPUArch = 'x64' }
- 'ARM64' { [System.String]$CPUArch = 'arm64' }
- default { Throw [System.PlatformNotSupportedException] 'Only AMD64 and ARM64 architectures are supported.' }
- }
- # Defining the final path to return for SignTool.exe
- [System.IO.FileInfo]$SignToolExePathOutput = Join-Path -Path ([WDACConfig.GlobalVars]::UserConfigDir) -ChildPath 'SignTool.exe'
-
- # Move the SignTool.exe from the temp directory to the User Config directory
- Move-Item -Path "$StagingArea\bin\*\$CPUArch\signtool.exe" -Destination $SignToolExePathOutput -Force
- }
- else {
- Throw [System.IO.FileNotFoundException] 'signtool.exe could not be found and an attempt to download it was declined.'
- }
- }
- }
- # If Sign tool path was provided by parameter, use it
- else {
- [WDACConfig.Logger]::Write('SignTool.exe path was provided by parameter')
- $SignToolExePathOutput = $SignToolExePathInput
- }
-
- # Since WDAC Simulation doesn't support path with wildcards and accepts them literally, doing this to make sure the path is valid when automatically detected from Windows SDK installations which is a wildcard path
- [System.IO.FileInfo]$SignToolExePathOutput = (Resolve-Path -Path $SignToolExePathOutput).Path
-
- # At this point the SignTool.exe path was either provided by user, was found in the user configs, was detected automatically or was downloaded from NuGet
- try {
- # Validate the SignTool executable
- [WDACConfig.Logger]::Write("Validating the SignTool executable: $SignToolExePathOutput")
- # Setting the minimum version of SignTool that is allowed to be executed
- [System.Version]$WindowsSdkVersion = '10.0.22621.2428'
- [System.Boolean]$GreenFlag1 = (((Get-Item -Path $SignToolExePathOutput).VersionInfo).ProductVersionRaw -ge $WindowsSdkVersion)
- [System.Boolean]$GreenFlag2 = (((Get-Item -Path $SignToolExePathOutput).VersionInfo).FileVersionRaw -ge $WindowsSdkVersion)
- [System.Boolean]$GreenFlag3 = ((Get-Item -Path $SignToolExePathOutput).VersionInfo).CompanyName -eq 'Microsoft Corporation'
- [System.Boolean]$GreenFlag4 = ((Get-AuthenticodeSignature -FilePath $SignToolExePathOutput).Status -eq 'Valid')
- [System.Boolean]$GreenFlag5 = ((Get-AuthenticodeSignature -FilePath $SignToolExePathOutput).StatusMessage -eq 'Signature verified.')
- }
- catch {
- # Display an extra error message to provide more information to the user
- if ($SignToolExePathInput) {
- Write-Error -Message 'The SignTool.exe path that was provided by parameter or found in user configuration could not be validated.' -ErrorAction Continue
- }
- Throw $_
- }
- # If any of the 5 checks above fails, the operation stops
- if (!$GreenFlag1 -or !$GreenFlag2 -or !$GreenFlag3 -or !$GreenFlag4 -or !$GreenFlag5) {
- Throw [System.Security.VerificationException] 'The SignTool executable was found but could not be verified. Please download the latest Windows SDK to get the newest SignTool executable. Official download link: http://aka.ms/WinSDK'
- }
- else {
- [WDACConfig.Logger]::Write('SignTool executable was found and verified successfully.')
-
- [WDACConfig.Logger]::Write('Setting the SignTool path in the common WDAC user configurations')
- $null = [WDACConfig.UserConfiguration]::Set($null, $null, $SignToolExePathOutput, $null, $null, $null, $null, $null , $null)
-
- return $SignToolExePathOutput
- }
- }
- Finally {
- Remove-Item -Path $StagingArea -Recurse -Force
- }
- }
-}
-Export-ModuleMember -Function 'Get-SignTool'