Skip to content

AppControl Manager

Violet Hansen edited this page Jul 31, 2025 · 61 revisions

AppControl Manager

AppControl Manager is a modern secure app that provides easy to use graphical user interface to manage App Control and Code Integrity on your local or remote devices.

⚡What is App Control? Check Out This Article ⚡


How To Install or Update The App

Use The Microsoft Store

install AppControl Manager from Microsoft Store

AppControl Manager is available on the Microsoft Store. This is the easiest and recommended way to install it. You will use Microsoft Store to receive future updates.


Use GitHub Packages

Use the following PowerShell command as Admin, it will automatically download the latest MSIXBundle file from this repository's release page and install it for you.

(irm 'https://raw.githubusercontent.com/HotCakeX/Harden-Windows-Security/main/Harden-Windows-Security.ps1')+'AppControl'|iex

Use Winget

You can utilize Winget to automate the installation of the AppControl Manager. It will use the Microsoft Store source.

winget install --id 9PNG1JDDTGP8 --exact --accept-package-agreements --accept-source-agreements --force --source msstore

Please feel free to open a discussion if you have any questions about the build process, security, how to use or have feedbacks. Source code on this repository


Supported Operation Systems

  • Windows 11 24H2
  • Windows 11 23H2
  • Windows 11 22H2
  • Windows Server 2025

Preview of the App


Technical Details of The App

  • Secure and transparent development and build process.
  • Built using WinUI3 / XAML / C#.
  • Built using the latest .NET SDK.
  • Powered by the WinAppSDK (formerly Project Reunion).
  • Packaged with the modern MSIX format.
  • Incorporates the Mica material design for backgrounds.
  • Adopts the Windows 11 Fluent design system.
  • Fast execution and startup time.
  • 0 required dependency.
  • 0 Third-party library or file used.
  • 0 Telemetry or data collection.
  • 0 Windows Registry changes.
  • 100% clean uninstallation.
  • 100% open-source and free to use.
  • Natively supports X64 and ARM64 architectures.
  • Full Trimming and Native AOT support.

Features Implemented So Far

More features will come very quickly in the near future.


Supported Languages

The AppControl Manager fully supports the following languages. You can request for more languages to be supported.

  • Country flag English
  • Country flag Hebrew
  • Country flag Greek
  • Country flag Hindi
  • Country flag Malayalam
  • Country flag Arabic
  • Country flag Spanish
  • Country flag Polish

Security

Important

The AppControl Manager application is built publicly using a GitHub Workflow and uploaded to the GitHub release. The action uses Artifact Attestation and SBOM (Software Bill of Materials) generation to comply with the highest security standards such as SLSA level 3. The source code as well as the package is uploaded to Virus Total automatically. Also GitHub's CodeQL Advanced workflow with extended security model scans the entire repository.

Security is paramount when selecting any application designed to safeguard your systems. The last thing you want is a security-focused tool that inadvertently expands your attack surface or one that doesn't prioritize security at its core.

AppControl Manager is engineered with a security-first approach from the ground up. It's crafted specifically for defense teams, yet its design has been rigorously shaped with a keen awareness of potential offensive strategies, ensuring resilience against emerging threats.

  • The AppControl Manager does not rely on any 3rd party component or dependency. All the logics are built securely and specifically for the app.

  • Any file(s) the AppControl Manager ever produces, uses or expects is only from an Administrator-protected location in C:\Program Files\AppControl Manager.

  • The AppControl Manager supports process mitigations / Exploit Protections such as: Blocking low integrity images, Blocking remote images, Blocking untrusted fonts, Strict Control Flow Guard, Disabling extension points, Export Address Filtering, Hardware enforced stack protection, Import Address Filtering, Validate handle usage, Validate stack integrity.

  • The AppControl Manager always uses the latest .NET SDK and NuGet package versions, ensuring all the security patches released by Microsoft will be included.

  • The entire codebase is thoroughly commented, allowing code reviewers to effortlessly examine and verify every aspect of AppControl Manager's source code.

  • AppControl Manager leverages MSAL from Microsoft to manage Microsoft 365 authentications. This industry-standard library adheres to best practices for secure authentication token management.


Why Do Certain Features of The AppControl Manager Require Administrator Privileges?

  • AppControl Manager operates exclusively within the "AppControl Manager" directory located in the Program Files directory for all read and write operations. No data is accessed or modified outside this directory. This design ensures that non-elevated processes, unauthorized software, or unprivileged malware on the system cannot alter the policies you create, the certificates you generate, or the CIP binary files you deploy.

  • AppControl Manager employs MediumIL (Medium Integrity Level) when running as an Administrator, ensuring that non-elevated processes cannot access its memory or attach debuggers. Given that the app handles sensitive information—such as Microsoft 365 authentication tokens stored in private variables—this design decision safeguards these tokens from unauthorized, unelevated access or tampering.

  • Administrator privileges are required for scanning Code Integrity and AppLocker logs. These scans are integral to several application functions, providing enhanced insights and enabling the generation of precise supplemental policies tailored to your needs.

  • Deploying, removing, modifying, or checking the status of policies also necessitates Administrator privileges to ensure secure and reliable execution of these operations.

  • Creating scheduled tasks that run as SYSTEM account requires Administrator privilege. This feature is used in places such as Creating auto-update task for Microsoft Recommended driver block rules or when Allowing new apps.


Where Are The Temporary Files Saved To?

Every new instance of the app that is launched creates a new StagingArea directory in the location below (if needed) with the Date and Time of that moment appended to it:

C:\Program Files\AppControl Manager\StagingArea[+ current Date Time]

Additionally, each applicable feature of the AppControl Manager that you start using will generate a uniquely named subdirectory within the StagingArea to store its temporary files (if needed). Upon closing the application, the entire StagingArea directory, along with its contents, will be automatically deleted. These files are utilized by the application for tasks such as creating policies, storing temporary scan results, and other related functions.


Where Is The User Configurations Directory?

The User Configurations directory is located in the following location:

C:\Program Files\AppControl Manager

Everything the AppControl Manager creates/generates will be saved in that directory or one of its sub-directories, such as:

  • XML policy files
  • CIP files
  • Generated certificates
  • Automatically acquired SignTool.exe
  • Logs
  • User Configurations JSON file
  • Temporary files (Staging Areas)

Which URLs does the AppControl Manager Connect To?

Here is the complete list of all of the URLs the AppControl Manager application connects to (or is mentioned in the User Interface) with proper justification for each of them.


URL Justification
https://api.nuget.org/v3-flatcontainer/ To access Microsoft NuGet repository to download SignTool.exe
https://aka.ms/VulnerableDriverBlockList To download the Microsoft Recommended Drivers Block List
https://api.github.com/repos/MicrosoftDocs/windows-itpro-docs/commits To check the latest commit details of the Microsoft Recommended Drivers Block List and display them to the user on the UI
https://raw.githubusercontent.com/MicrosoftDocs/windows-itpro-docs/refs/heads/public/windows/security/application-security/application-control/app-control-for-business/design/applications-that-can-bypass-appcontrol.md Source for the Microsoft Recommended User-Mode Block Rules
https://raw.githubusercontent.com/MicrosoftDocs/windows-itpro-docs/refs/heads/public/windows/security/application-security/application-control/app-control-for-business/design/microsoft-recommended-driver-block-rules.md Source for the Microsoft Recommended Drivers Block Rules
https://raw.githubusercontent.com/HotCakeX/Harden-Windows-Security/refs/heads/main/AppControl%20Manager/MSIXBundleDownloadURL.txt The file on this repository that contains the download link to the latest version of the AppControl Manager. That text file is updated via automated GitHub action workflow that securely builds and uploads the MSIXBundle package to the GitHub releases.
https://raw.githubusercontent.com/HotCakeX/Harden-Windows-Security/refs/heads/main/AppControl%20Manager/version.txt The latest available version of the AppControl Manager application. That text file is updated via automated GitHub action workflow that securely builds and uploads the MSIXBundle package to the GitHub releases.
https://github.com/HotCakeX/Harden-Windows-Security/wiki/Introduction The link that opens in the GitHub documentations page in the app via the built-in WebView 2
https://learn.microsoft.com/windows/security/application-security/application-control/app-control-for-business/appcontrol The link that opens in the Microsoft documentations page in the app via the built-in WebView 2
https://github.com/HotCakeX/Harden-Windows-Security/releases During the update process, this link that is for the GitHub releases will be displayed on the update page as a quick way to read the release notes
https://github.com/HotCakeX/Harden-Windows-Security/wiki/AppControl-Manager Will be displayed on the Update page when a new version is available and being downloaded
https://github.com/HotCakeX/Harden-Windows-Security/issues/new/choose Link for the "Send Feedback" button at the bottom of the about section in settings
https://github.com/HotCakeX/Harden-Windows-Security Mentioned in the Links section at the bottom of the About section in Settings
https://github.com/HotCakeX/Harden-Windows-Security/wiki/AppControl-Manager Mentioned in the Links section at the bottom of the About section in Settings
https://spynetgirl.github.io/ Mentioned in the Links section at the bottom of the About section in Settings
https://www.youtube.com/@hotcakex Mentioned in the Links section at the bottom of the About section in Settings
https://x.com/CyberCakeX Mentioned in the Links section at the bottom of the About section in Settings
https://icons8.com Mentioned in the Links section at the bottom of the About section in Settings as credit
https://graph.microsoft.com Used when signing into your Azure tenant for uploading policies to Intune

How To Install AppControl Manager Completely Offline?

  1. Download this PowerShell script.

  2. Have SignTool.exe. You can find it in here if you don't already have it.

  3. Download the latest MSIXBundle package of the AppControl Manager from the GitHub releases or build it from the source code yourself.

  4. Start an elevated PowerShell and import the script file via Import-Module "Path to script file".

  5. Use the following syntax to Install the AppControl Manager

AppControl -MSIXBundlePath "Path To the MSIXBundle" -SignTool "Path to signtool.exe" -Verbose

About the GitHub Packages Installation Process

Warning

The following only happens during GitHub installation method, when you run the one-liner script to install the AppControl Manager then the steps described below will automatically run. However, if you choose to install the AppControl Manager from the Microsoft Store then the following steps are not necessary and will not be used.

The installation process for AppControl Manager is uniquely streamlined. When you execute the PowerShell one-liner command mentioned above, it initiates a file containing the AppControl function, which serves as the bootstrapper script. This script is thoroughly documented, with detailed explanations and justifications for each step, as outlined below:

  • The latest version of the AppControl Manager MSIXBundle package is securely downloaded from the GitHub release page, where it is built publicly with full artifact attestation and SBOMs.

  • The SignTool.exe utility is sourced directly from Microsoft by retrieving the associated Nuget package, ensuring a trusted origin.

  • A secure, on-device code-signing certificate is then generated. This certificate, managed by the Microsoft-signed SignTool.exe, is used to sign the MSIXBundle package obtained from GitHub.

  • The private key of the certificate is non-exportable, never written on the disk and is securely discarded once signing is complete, leaving only the public key on the device to allow AppControl Manager to function properly on the system and prevent the certificate from being able to sign anything else.

  • The entire process is designed to leave no residual files. Each time the script runs, any certificates from previous executions are detected and removed, ensuring a clean system.

  • Finally, the AppControlManager.dll and AppControlManager.exe files are added to the Attack Surface Reduction (ASR) exclusions to prevent ASR rules from blocking these newly released binaries. Previous version exclusions are also removed from the ASRs exclusions list to maintain a clean, streamlined setup for the user.


How To Build The AppControl Manager Locally?

You can build the AppControl Manager application directly from the source code locally on your device without using any 3rd party tools in a completely automated way.

It will create the MSIXBundle file containing the X64 and ARM64 MSIX packages. You can even optionally chain it with the Bootstrapper script to sign and install the application on your system at the end.

The build process will generate complete log files and you can use the MSBuild Structured Log Viewer to inspect them.

✨ Click/Tap here to see the PowerShell code ✨
# Requires -Version 5.1
# Requires -RunAsAdministrator
function Build_ACM {
    param(
        [ValidateSet('Store', 'Self')]
        [string]$Type,
        [bool]$DownloadRepo,
        [bool]$InstallDeps,
        [bool]$Workflow,
        [bool]$UpdateWorkLoads,
        [bool]$Install,
        [bool]$Upload,
        [bool]$X64ONLY
    )

    [string]$PackageFamilyName = ''
    [string]$PackageHashAlgo = ''
    [string]$PackagePublisher = ''
    [string]$PackageName = ''
    [string]$PackagePhoneProductId = ''
    [string]$PackagePhonePublisherId = ''
    [string]$PackagePublisherDisplayName = ''

    Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1 -Force

    if ($Type -eq 'Store') {
        $PackageFamilyName = 'VioletHansen.AppControlManager_ea7andspwdn10'
        $PackageHashAlgo = 'SHA256'
        $PackagePublisher = 'CN=C62E63B6-6EF1-4F86-B80F-41A725BD0189'
        $PackageName = 'VioletHansen.AppControlManager'
        $PackagePhoneProductId = '4157a676-f4c2-4a8c-a511-b7fb2255c6f5'
        $PackagePhonePublisherId = '387464d6-cb95-4e5f-9c8f-f153a4855fb2'
        $PackagePublisherDisplayName = 'Violet Hansen'
    }
    else {
        $PackageFamilyName = 'AppControlManager_sadt7br7jpt02'
        $PackageHashAlgo = 'SHA512'
        $PackagePublisher = 'CN=SelfSignedCertForAppControlManager'
        $PackageName = 'AppControlManager'
        $PackagePhoneProductId = '199a23ec-7cb6-4ab5-ab50-8baca348bc79'
        $PackagePhonePublisherId = '00000000-0000-0000-0000-000000000000'
        $PackagePublisherDisplayName = 'SelfSignedCertForAppControlManager'
    }

    $ErrorActionPreference = 'Stop'
    # Start the stopwatch
    $Stopwatch = [System.Diagnostics.Stopwatch]::StartNew()

    [System.String]$script:AppControlManagerDirectory

    if ($DownloadRepo) {

        [System.String]$BranchName = 'main'
        [System.String]$RepoName = 'Harden-Windows-Security'
        [System.String]$RepoUrl = "https://github.com/HotCakeX/$RepoName/archive/refs/heads/$BranchName.zip"
        [System.String]$ZipPath = [System.IO.Path]::Combine($env:TEMP, "$RepoName.zip")
        [System.String]$InitialWorkingDirectory = $PWD.Path
        $script:AppControlManagerDirectory = [System.IO.Path]::Combine($InitialWorkingDirectory, "$RepoName-$BranchName", 'AppControl Manager')

        if (Test-Path -Path $script:AppControlManagerDirectory -PathType Container) {
            Remove-Item -Path $script:AppControlManagerDirectory -Recurse -Force
        }

        Invoke-WebRequest -Uri $RepoUrl -OutFile $ZipPath
        Expand-Archive -Path $ZipPath -DestinationPath $InitialWorkingDirectory -Force
        Remove-Item -Path $ZipPath -Force
        Set-Location -Path $script:AppControlManagerDirectory
    }
    else {
        $script:AppControlManagerDirectory = $PWD.Path
    }

    if ($InstallDeps) {

        # Install Winget if it doesn't exist
        if (!(Get-Command -Name 'winget.exe' -ErrorAction Ignore)) {

            # Retrieve the latest Winget release information
            $WingetReleases = Invoke-RestMethod -Uri 'https://api.github.com/repos/microsoft/winget-cli/releases'
            $LatestRelease = $WingetReleases | Select-Object -First 1
            # Direct links to the latest Winget release assets
            [string]$WingetURL = $LatestRelease.assets.browser_download_url | Where-Object -FilterScript { $_.EndsWith('.msixbundle') } | Select-Object -First 1
            [string]$WingetLicense = $LatestRelease.assets.browser_download_url | Where-Object -FilterScript { $_.EndsWith('License1.xml') } | Select-Object -First 1
            [string]$LatestWingetReleaseDependenciesZipURL = $LatestRelease.assets.browser_download_url | Where-Object -FilterScript { $_.EndsWith('DesktopAppInstaller_Dependencies.zip') } | Select-Object -First 1
            [hashtable]$Downloads = @{
                # 'Winget.msixbundle'                 = 'https://aka.ms/getwinget' This is updated slower than the GitHub release
                'DesktopAppInstaller_Dependencies.zip' = $LatestWingetReleaseDependenciesZipURL
                'Winget.msixbundle'                    = $WingetURL
                'License1.xml'                         = $WingetLicense
            }
            $Downloads.GetEnumerator() | ForEach-Object -Parallel {
                Invoke-RestMethod -Uri $_.Value -OutFile $_.Key
            }

            Expand-Archive -Path 'DesktopAppInstaller_Dependencies.zip' -DestinationPath .\ -Force

            # Required to update the Winget
            Stop-Process -Name 'WindowsTerminal' -Force -ErrorAction Ignore

            # Get the paths to all of the dependencies
            [string[]]$DependencyPaths = (Get-ChildItem -Path .\x64 -Filter '*.appx' -File -Force).FullName
            Add-AppxProvisionedPackage -Online -PackagePath 'Winget.msixbundle' -DependencyPackagePath $DependencyPaths -LicensePath 'License1.xml'

            Add-AppPackage -Path 'Winget.msixbundle' -DependencyPath "$($DependencyPaths[0])", "$($DependencyPaths[1])" -ForceTargetApplicationShutdown -ForceUpdateFromAnyVersion

        }

        Write-Host -Object 'The version of the Winget currently in use:'
        Write-Host -Object (winget --version)

        winget source update

        Write-Host -Object "`nInstalling Rust toolchain" -ForegroundColor Magenta
        $null = winget install --id Rustlang.Rustup --exact --accept-package-agreements --accept-source-agreements --uninstall-previous --force --source winget
        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed to install the Rust toolchain: $LASTEXITCODE") }

        Write-Host -Object "`nInstalling .NET SDK" -ForegroundColor Magenta
        $null = winget install --id Microsoft.DotNet.SDK.Preview --exact --accept-package-agreements --accept-source-agreements --uninstall-previous --force --source winget
        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed to install .NET SDK: $LASTEXITCODE") }

        Write-Host -Object "`nInstalling Visual Studio Build Tools" -ForegroundColor Magenta
        # Downloads the online installer and automatically runs it and installs the build tools
        # https://learn.microsoft.com/windows/apps/windows-app-sdk/set-up-your-development-environment
        # https://learn.microsoft.com/visualstudio/install/workload-component-id-vs-build-tools
        # https://learn.microsoft.com/visualstudio/install/use-command-line-parameters-to-install-visual-studio
        # https://learn.microsoft.com/visualstudio/install/workload-component-id-vs-community
        winget install --id Microsoft.VisualStudio.2022.BuildTools --exact --accept-package-agreements --accept-source-agreements --uninstall-previous --force --source winget --override '--force --wait --passive --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Workload.MSBuildTools --add Microsoft.VisualStudio.Workload.UniversalBuildTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows11SDK.26100 --includeRecommended --add Microsoft.VisualStudio.Component.VC.Tools.ARM64'

        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New('Failed to install Visual Studio Build Tools') }

        winget install --id Microsoft.VCRedist.2015+.x64 --exact --accept-package-agreements --accept-source-agreements --uninstall-previous --force --source winget

    }

    # Refresh the environment variables so the current session detects the new dotnet installation
    $Env:Path = [System.Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::Machine) + ';' +
    [System.Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::User)

    # https://github.com/Microsoft/vswhere/wiki/Start-Developer-Command-Prompt#using-powershell
    $installationPath = . 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -prerelease -latest -property installationPath
    if ($installationPath -and (Test-Path -Path "$installationPath\Common7\Tools\vsdevcmd.bat" -PathType Leaf)) {
        & "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -no_logo && set" | ForEach-Object -Process {
            $name, $value = $_ -split '=', 2
            Set-Content -Path env:\"$name" -Value $value -Force
            Write-Host -Object "Setting environment variable: $name=$value"
        }
    }

    # Remove any possible existing directories
    Remove-Item -Path .\MSIXOutputX64 -Recurse -Force -ErrorAction Ignore
    Remove-Item -Path .\MSIXOutputARM64 -Recurse -Force -ErrorAction Ignore
    Remove-Item -Path .\MSIXBundleOutput -Recurse -Force -ErrorAction Ignore
    Remove-Item -Path .\bin -Recurse -Force -ErrorAction Ignore
    Remove-Item -Path .\obj -Recurse -Force -ErrorAction Ignore

    if ($UpdateWorkLoads) {
        # Update the workloads
        dotnet workload update
        dotnet workload config --update-mode workload-set
        dotnet workload update
        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed updating the workloads. Exit Code: $LASTEXITCODE") }
    }

    Write-Host -Object "`nChecking .NET info`n`n" -ForegroundColor Magenta
    dotnet --info
    Write-Host -Object "`nListing installed .NET SDKs`n`n" -ForegroundColor Magenta
    dotnet --list-sdks

    function Find-mspdbcmf {
        # "-products *" is necessary to detect BuildTools too
        [string]$VisualStudioPath = . 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -prerelease -latest -property resolvedInstallationPath -products *

        [string]$BasePath = [System.IO.Path]::Combine($VisualStudioPath, 'VC', 'Tools', 'MSVC')

        # Get all subdirectories under the base path
        [System.String[]]$VersionDirs = [System.IO.Directory]::GetDirectories($BasePath)

        # Initialize the highest version with a minimal version value.
        [System.Version]$HighestVersion = [System.Version]::New('0.0.0.0')
        [System.String]$HighestVersionFolder = $null

        # Loop through each directory to find the highest version folder.
        foreach ($Dir in $VersionDirs) {
            # Extract the folder name
            [System.String]$FolderName = [System.IO.Path]::GetFileName($Dir)
            [System.Version]$CurrentVersion = $null
            # Try parsing the folder name as a Version.
            if ([System.Version]::TryParse($FolderName, [ref] $CurrentVersion)) {
                # Compare versions
                if ($CurrentVersion.CompareTo($HighestVersion) -gt 0) {
                    $HighestVersion = $CurrentVersion
                    $HighestVersionFolder = $FolderName
                }
            }
        }

        # If no valid version folder is found
        if (!$HighestVersionFolder) {
            throw [System.IO.DirectoryNotFoundException]::New("No valid version directories found in $BasePath")
        }

        # Combine the base path, the highest version folder, the architecture folder, and the file name.
        [System.String]$mspdbcmfPath = [System.IO.Path]::Combine($BasePath, $HighestVersionFolder, 'bin', 'Hostx64', 'x64', 'mspdbcmf.exe')

        if (![System.IO.File]::Exists($mspdbcmfPath)) {
            throw [System.IO.FileNotFoundException]::New("mspdbcmf.exe not found at $mspdbcmfPath")
        }

        return $mspdbcmfPath
    }

    [string]$mspdbcmfPath = Find-mspdbcmf

    function Find-MSBuild {
        # "-products *" is necessary to detect BuildTools too
        [string]$VisualStudioPath = . 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -prerelease -latest -property resolvedInstallationPath -products *

        [string]$MSBuildPath = [System.IO.Path]::Combine($VisualStudioPath, 'MSBuild', 'Current', 'Bin', 'MSBuild.exe')

        if (![System.IO.File]::Exists($MSBuildPath)) {
            throw [System.IO.FileNotFoundException]::New("MSBuild.exe not found at $MSBuildPath")
        }

        return $MSBuildPath
    }

    [string]$MSBuildPath = Find-MSBuild

    #region --- Compile C++ projects ---

    ### ManageDefender

    . $MSBuildPath 'eXclude\C++ WMI Interop\ManageDefender\ManageDefender.slnx' /p:Configuration=Release /p:Platform=x64 /target:"clean;Rebuild"

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building MS Defender solution for X64. Exit Code: $LASTEXITCODE") }

    if (!$X64ONLY) {

        . $MSBuildPath 'eXclude\C++ WMI Interop\ManageDefender\ManageDefender.slnx' /p:Configuration=Release /p:Platform=arm64 /target:"clean;Rebuild"

        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building MS Defender solution for ARM64. Exit Code: $LASTEXITCODE") }
    }

    ### ScheduledTaskManager

    . $MSBuildPath 'eXclude\C++ ScheduledTaskManager\ScheduledTaskManager\ScheduledTaskManager.slnx' /p:Configuration=Release /p:Platform=x64 /target:"clean;Rebuild"

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building ScheduledTaskManager solution for X64. Exit Code: $LASTEXITCODE") }

    if (!$X64ONLY) {

        . $MSBuildPath 'eXclude\C++ ScheduledTaskManager\ScheduledTaskManager\ScheduledTaskManager.slnx' /p:Configuration=Release /p:Platform=arm64 /target:"clean;Rebuild"

        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building ScheduledTaskManager solution for ARM64. Exit Code: $LASTEXITCODE") }
    }

    ### Shell

    [string]$newPFN = "$PackageFamilyName!App"
    [string]$content = Get-Content 'eXclude\Shell\Shell.cpp' -Raw
    [string]$content = $content -replace 'static constexpr LPCWSTR APP_CONTROL_MANAGER_PFN = L"[^"]*";', "static constexpr LPCWSTR APP_CONTROL_MANAGER_PFN = L`"$newPFN`";"
    $content | Set-Content 'eXclude\Shell\Shell.cpp' -NoNewline -Force

    . $MSBuildPath 'eXclude\Shell\Shell.slnx' /p:Configuration=Release /p:Platform=x64 /target:"clean;Rebuild"

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building the Shell solution for X64. Exit Code: $LASTEXITCODE") }

    if (!$X64ONLY) {

        . $MSBuildPath 'eXclude\Shell\Shell.slnx' /p:Configuration=Release /p:Platform=arm64 /target:"clean;Rebuild"

        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building the Shell solution for ARM64. Exit Code: $LASTEXITCODE") }
    }

    #endregion


    #region --- RUST projects ---

    # Uncomment this once stable toolchain supports ehcont security feature, till then we use nightly only
    # rustup default stable
    rustup default nightly

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed setting Rust toolchain to Stable. Exit Code: $LASTEXITCODE") }

    if (!$X64ONLY) {

        rustup target add aarch64-pc-windows-msvc

        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed adding aarch64-pc-windows-msvc target to Rust toolchain. Exit Code: $LASTEXITCODE") }

    }

    rustup target add x86_64-pc-windows-msvc

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed adding x86_64-pc-windows-msvc target to Rust toolchain. Exit Code: $LASTEXITCODE") }

    rustup update

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed updating Rust. Exit Code: $LASTEXITCODE") }

    cargo version

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed checking for Rust version. Exit Code: $LASTEXITCODE") }

    [string]$Current_Location = (Get-Location).Path

    Set-Location -Path '.\eXclude\Rust WMI Interop\Device Guard\Program'

    if (Test-Path -PathType Leaf -LiteralPath 'Cargo.lock') {
        Remove-Item -Force -LiteralPath 'Cargo.lock'
    }

    cargo clean

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed cleaning the Rust project. Exit Code: $LASTEXITCODE") }

    cargo update --verbose

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed updating Rust. Exit Code: $LASTEXITCODE") }

    cargo tree

    rustup show active-toolchain

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed showing active Rust toolchain. Exit Code: $LASTEXITCODE") }

    cargo build_x64

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building x64 Device Guard Rust project. Exit Code: $LASTEXITCODE") }

    if (!$X64ONLY) {

        cargo build_arm64

        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building arm64 Device Guard Rust project. Exit Code: $LASTEXITCODE") }

    }

    Set-Location -Path $Current_Location


    Set-Location -Path '.\eXclude\Rust Interop Library'

    if (Test-Path -PathType Leaf -LiteralPath 'Cargo.lock') {
        Remove-Item -Force -LiteralPath 'Cargo.lock'
    }

    rustup toolchain install nightly

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed installing nightly Rust toolchain. Exit Code: $LASTEXITCODE") }

    rustup default nightly

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed setting Rust toolchain to Nightly. Exit Code: $LASTEXITCODE") }

    rustup component add rust-src --toolchain nightly-x86_64-pc-windows-msvc

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed adding rust-src component to Nightly toolchain. Exit Code: $LASTEXITCODE") }

    rustup update

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed updating Rust. Exit Code: $LASTEXITCODE") }

    cargo version

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed checking for Rust version. Exit Code: $LASTEXITCODE") }

    cargo clean

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed cleaning the Rust project. Exit Code: $LASTEXITCODE") }

    cargo update --verbose

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed updating Rust. Exit Code: $LASTEXITCODE") }

    cargo tree

    rustup show active-toolchain

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed showing active Rust toolchain. Exit Code: $LASTEXITCODE") }

    cargo build_x64

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building x64 Rust Interop project. Exit Code: $LASTEXITCODE") }

    if (!$X64ONLY) {

        cargo build_arm64

        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building ARM64 Rust Interop project. Exit Code: $LASTEXITCODE") }

    }

    Set-Location -Path $Current_Location

    #endregion

    #region XML Modifications

    [string]$CsProjFilePath = (Resolve-Path -Path '.\AppControl Manager.csproj').Path
    [string]$AppxManifestFilePath = (Resolve-Path -Path '.\Package.appxmanifest').Path

    # Adjust the Digest Algorithm based on the package source
    [xml]$ProjXMLContent = Get-Content -Path $CsProjFilePath -Force

    # Grab ALL existing nodes, wherever they are
    $nodes = $ProjXMLContent.SelectNodes('//AppxPackageSigningTimestampDigestAlgorithm')

    foreach ($node in $nodes) {
        $node.InnerText = $PackageHashAlgo
    }

    $ProjXMLContent.Save($CsProjFilePath)

    # Configure the Package Manifest Dits
    [xml]$AppxManifestContent = Get-Content -Path $AppxManifestFilePath -Force

    $ns = New-Object System.Xml.XmlNamespaceManager($AppxManifestContent.NameTable)
    $ns.AddNamespace('ns', 'http://schemas.microsoft.com/appx/manifest/foundation/windows10')
    $ns.AddNamespace('mp', 'http://schemas.microsoft.com/appx/2014/phone/manifest')

    # Update the <Identity> attributes
    $identity = $AppxManifestContent.SelectSingleNode('/ns:Package/ns:Identity', $ns)
    $identity.SetAttribute('Name', $PackageName)
    $identity.SetAttribute('Publisher', $PackagePublisher)

    # Update the <mp:PhoneIdentity> attributes
    $phoneId = $AppxManifestContent.SelectSingleNode('/ns:Package/mp:PhoneIdentity', $ns)
    $phoneId.SetAttribute('PhoneProductId', $PackagePhoneProductId)
    $phoneId.SetAttribute('PhonePublisherId', $PackagePhonePublisherId)

    # Update the <PublisherDisplayName> element
    $pubDisplay = $AppxManifestContent.SelectSingleNode('/ns:Package/ns:Properties/ns:PublisherDisplayName', $ns)
    $pubDisplay.InnerText = $PackagePublisherDisplayName

    $AppxManifestContent.Save($AppxManifestFilePath)

    #endregion XML Modifications

    # https://learn.microsoft.com/dotnet/core/tools/dotnet-build
    # https://learn.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
    # https://learn.microsoft.com/visualstudio/msbuild/common-msbuild-project-properties

    # Copy the X64 components to the directory before the build starts
    Copy-Item -Path '.\eXclude\Shell\x64\Release\Shell.dll' -Destination 'Shell' -Force

    Copy-Item -Path '.\eXclude\C++ ScheduledTaskManager\ScheduledTaskManager\x64\Release\ScheduledTaskManager-x64.exe' -Destination '.\CppInterop\ScheduledTaskManager.exe' -Force

    Copy-Item -Path '.\eXclude\C++ WMI Interop\ManageDefender\x64\Release\ManageDefender-x64.exe' -Destination '.\CppInterop\ManageDefender.exe' -Force

    Copy-Item -Path '.\eXclude\Rust WMI Interop\Device Guard\Program\target\x86_64-pc-windows-msvc\release\DeviceGuardWMIRetriever-X64.exe' -Destination '.\RustInterop\DeviceGuardWMIRetriever.exe' -Force

    # Generate for X64 architecture
    dotnet clean 'AppControl Manager.slnx' --configuration Release
    dotnet build 'AppControl Manager.slnx' --configuration Release --verbosity minimal /p:Platform=x64

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building x64 AppControl Manager project. Exit Code: $LASTEXITCODE") }

    dotnet msbuild 'AppControl Manager.slnx' /p:Configuration=Release /p:AppxPackageDir="MSIXOutputX64\" /p:GenerateAppxPackageOnBuild=true /p:Platform=x64 -v:minimal /p:MsPdbCmfExeFullpath=$mspdbcmfPath -bl:X64MSBuildLog.binlog

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed packaging x64 AppControl Manager project. Exit Code: $LASTEXITCODE") }

    if (!$X64ONLY) {

        # Copy the ARM64 components to the directory before the build starts
        Copy-Item -Path '.\eXclude\Shell\ARM64\Release\Shell.dll' -Destination 'Shell' -Force

        Copy-Item -Path '.\eXclude\C++ ScheduledTaskManager\ScheduledTaskManager\ARM64\Release\ScheduledTaskManager-ARM64.exe' -Destination '.\CppInterop\ScheduledTaskManager.exe' -Force

        Copy-Item -Path '.\eXclude\C++ WMI Interop\ManageDefender\ARM64\Release\ManageDefender-ARM64.exe' -Destination '.\CppInterop\ManageDefender.exe' -Force

        Copy-Item -Path '.\eXclude\Rust WMI Interop\Device Guard\Program\target\aarch64-pc-windows-msvc\release\DeviceGuardWMIRetriever-ARM64.exe' -Destination '.\RustInterop\DeviceGuardWMIRetriever.exe' -Force

        # Generate for ARM64 architecture
        dotnet clean 'AppControl Manager.slnx' --configuration Release
        dotnet build 'AppControl Manager.slnx' --configuration Release --verbosity minimal /p:Platform=ARM64

        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed building ARM64 AppControl Manager project. Exit Code: $LASTEXITCODE") }

        dotnet msbuild 'AppControl Manager.slnx' /p:Configuration=Release /p:AppxPackageDir="MSIXOutputARM64\" /p:GenerateAppxPackageOnBuild=true /p:Platform=ARM64 -v:minimal /p:MsPdbCmfExeFullpath=$mspdbcmfPath -bl:ARM64MSBuildLog.binlog

        if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("Failed packaging ARM64 AppControl Manager project. Exit Code: $LASTEXITCODE") }
    }

    function Get-MSIXFile {
        param(
            [System.String]$BasePath,
            [System.String]$FolderPattern,
            [System.String]$FileNamePattern,
            [System.String]$ErrorMessageFolder,
            [System.String]$ErrorMessageFile
        )
        # Get all subdirectories in the base path matching the folder pattern
        [System.String[]]$Folders = [System.IO.Directory]::GetDirectories($BasePath)
        [System.String]$DetectedFolder = $null
        foreach ($Folder in $Folders) {
            if ([System.Text.RegularExpressions.Regex]::IsMatch($Folder, $FolderPattern)) {
                $DetectedFolder = $Folder
                break
            }
        }

        if (!$DetectedFolder) {
            throw [System.InvalidOperationException]::New($ErrorMessageFolder)
        }

        # Get the full path of the first file matching the file name pattern inside the found folder
        [System.String[]]$Files = [System.IO.Directory]::GetFiles($DetectedFolder)
        [System.String]$DetectedFile = $null
        foreach ($File in $Files) {
            if ([System.Text.RegularExpressions.Regex]::IsMatch($File, $FileNamePattern)) {
                $DetectedFile = $File
                break
            }
        }

        if (!$DetectedFile) {
            throw [System.InvalidOperationException]::New($ErrorMessageFile)
        }
        return $DetectedFile
    }

    #region Finding X64 outputs
    [System.String]$FinalMSIXX64Path = Get-MSIXFile -BasePath ([System.IO.Path]::Combine($PWD.Path, 'MSIXOutputX64')) -FolderPattern 'AppControl Manager_\d+\.\d+\.\d+\.\d+_Test' -FileNamePattern 'AppControl Manager_\d+\.\d+\.\d+\.\d+_x64\.msix' -ErrorMessageFolder 'Could not find the directory for X64 MSIX file' -ErrorMessageFile 'Could not find the X64 MSIX file'
    [System.String]$FinalMSIXX64Name = [System.IO.Path]::GetFileName($FinalMSIXX64Path)
    [System.String]$FinalMSIXX64SymbolPath = Get-MSIXFile -BasePath ([System.IO.Path]::Combine($PWD.Path, 'MSIXOutputX64')) -FolderPattern 'AppControl Manager_\d+\.\d+\.\d+\.\d+_Test' -FileNamePattern 'AppControl Manager_\d+\.\d+\.\d+\.\d+_x64\.msixsym' -ErrorMessageFolder 'Could not find the directory for X64 symbol file' -ErrorMessageFile 'Could not find the X64 symbol file'
    [System.String]$FinalMSIXX64SymbolName = [System.IO.Path]::GetFileName($FinalMSIXX64SymbolPath)
    #endregion

    if (!$X64ONLY) {

        #region Finding ARM64 outputs
        [System.String]$FinalMSIXARM64Path = Get-MSIXFile -BasePath ([System.IO.Path]::Combine($PWD.Path, 'MSIXOutputARM64')) -FolderPattern 'AppControl Manager_\d+\.\d+\.\d+\.\d+_Test' -FileNamePattern 'AppControl Manager_\d+\.\d+\.\d+\.\d+_arm64\.msix' -ErrorMessageFolder 'Could not find the directory for ARM64 MSIX file' -ErrorMessageFile 'Could not find the ARM64 MSIX file'
        [System.String]$FinalMSIXARM64Name = [System.IO.Path]::GetFileName($FinalMSIXARM64Path)
        [System.String]$FinalMSIXARM64SymbolPath = Get-MSIXFile -BasePath ([System.IO.Path]::Combine($PWD.Path, 'MSIXOutputARM64')) -FolderPattern 'AppControl Manager_\d+\.\d+\.\d+\.\d+_Test' -FileNamePattern 'AppControl Manager_\d+\.\d+\.\d+\.\d+_arm64\.msixsym' -ErrorMessageFolder 'Could not find the directory for ARM64 symbol file' -ErrorMessageFile 'Could not find the ARM64 symbol file'
        [System.String]$FinalMSIXARM64SymbolName = [System.IO.Path]::GetFileName($FinalMSIXARM64SymbolPath)
        #endregion

    }

    #region Detect and Validate File Versions
    [System.Text.RegularExpressions.Regex]$versionRegexX64 = [System.Text.RegularExpressions.Regex]::New('AppControl Manager_(\d+\.\d+\.\d+\.\d+)_x64\.msix')

    if (!$X64ONLY) {

        [System.Text.RegularExpressions.Regex]$versionRegexARM64 = [System.Text.RegularExpressions.Regex]::New('AppControl Manager_(\d+\.\d+\.\d+\.\d+)_arm64\.msix')
    }

    [System.Text.RegularExpressions.Match]$MatchX64 = $versionRegexX64.Match($FinalMSIXX64Name)

    if (!$X64ONLY) {

        [System.Text.RegularExpressions.Match]$MatchARM64 = $versionRegexARM64.Match($FinalMSIXARM64Name)

    }

    if (!$MatchX64.Success) {
        throw [System.InvalidOperationException]::New('Could not detect version from X64 file name')
    }

    if (!$X64ONLY) {

        if (!$MatchARM64.Success) {
            throw [System.InvalidOperationException]::New('Could not detect version from ARM64 file name')
        }
    }

    [System.String]$versionX64 = $MatchX64.Groups[1].Value

    if (!$X64ONLY) {

        [System.String]$versionARM64 = $MatchARM64.Groups[1].Value


        if ($versionX64 -ne $versionARM64) {
            throw [System.InvalidOperationException]::New('The versions in X64 and ARM64 files do not match')
        }

    }

    # Craft the file name for the MSIX Bundle file
    [System.String]$FinalBundleFileName = "AppControl Manager_$versionX64.msixbundle"
    #endregion

    # Creating the directory where the MSIX packages will be copied to
    [System.String]$MSIXBundleOutput = [System.IO.Directory]::CreateDirectory([System.IO.Path]::Combine($script:AppControlManagerDirectory, 'MSIXBundleOutput')).FullName

    [System.IO.File]::Copy($FinalMSIXX64Path, [System.IO.Path]::Combine($MSIXBundleOutput, $FinalMSIXX64Name), $true)

    if (!$X64ONLY) {

        [System.IO.File]::Copy($FinalMSIXARM64Path, [System.IO.Path]::Combine($MSIXBundleOutput, $FinalMSIXARM64Name), $true)

    }

    # The path to the final MSIX Bundle file
    [System.String]$MSIXBundle = [System.IO.Path]::Combine($MSIXBundleOutput, $FinalBundleFileName)

    function Get-MakeAppxPath {
        [System.String]$BasePath = 'C:\Program Files (x86)\Windows Kits\10\bin'

        # Get all subdirectories under the base path
        [System.String[]]$VersionDirs = [System.IO.Directory]::GetDirectories($BasePath)

        # Initialize the highest version with a minimal version value.
        [System.Version]$HighestVersion = [System.Version]::New('0.0.0.0')
        [System.String]$HighestVersionFolder = $null

        # Loop through each directory to find the highest version folder.
        foreach ($Dir in $VersionDirs) {
            # Extract the folder name
            [System.String]$FolderName = [System.IO.Path]::GetFileName($Dir)
            [System.Version]$CurrentVersion = $null
            # Try parsing the folder name as a Version.
            if ([System.Version]::TryParse($FolderName, [ref] $CurrentVersion)) {
                # Compare versions
                if ($CurrentVersion.CompareTo($HighestVersion) -gt 0) {
                    $HighestVersion = $CurrentVersion
                    $HighestVersionFolder = $FolderName
                }
            }
        }

        # If no valid version folder is found
        if (!$HighestVersionFolder) {
            throw [System.IO.DirectoryNotFoundException]::New("No valid version directories found in $BasePath")
        }

        [string]$CPUArch = @{AMD64 = 'x64'; ARM64 = 'arm64' }[$Env:PROCESSOR_ARCHITECTURE]
        if ([System.String]::IsNullOrWhiteSpace($CPUArch)) { throw [System.PlatformNotSupportedException]::New('Only AMD64 and ARM64 architectures are supported.') }

        # Combine the base path, the highest version folder, the architecture folder, and the file name.
        [System.String]$MakeAppxPath = [System.IO.Path]::Combine($BasePath, $HighestVersionFolder, $CPUArch, 'makeappx.exe')

        return $MakeAppxPath
    }

    [System.String]$MakeAppxPath = Get-MakeAppxPath

    if ([System.string]::IsNullOrWhiteSpace($MakeAppxPath)) {
        throw [System.IO.FileNotFoundException]::New('Could not find the makeappx.exe')
    }

    # https://learn.microsoft.com/windows/win32/appxpkg/make-appx-package--makeappx-exe-#to-create-a-package-bundle-using-a-directory-structure
    . $MakeAppxPath bundle /d $MSIXBundleOutput /p $MSIXBundle /o /v

    if ($LASTEXITCODE -ne 0) { throw [System.InvalidOperationException]::New("MakeAppx failed creating the MSIXBundle. Exit Code: $LASTEXITCODE") }

    #Endregion

    Write-Host -Object "X64 MSIX File Path: $FinalMSIXX64Path" -ForegroundColor Green
    Write-Host -Object "X64 MSIX File Name: $FinalMSIXX64Name" -ForegroundColor Green
    Write-Host -Object "X64 Symbols: $FinalMSIXX64SymbolPath" -ForegroundColor Green

    if (!$X64ONLY) {

        Write-Host -Object "ARM64 MSIX File Path: $FinalMSIXARM64Path" -ForegroundColor Cyan
        Write-Host -Object "ARM64 MSIX File Name: $FinalMSIXARM64Name" -ForegroundColor Cyan
        Write-Host -Object "ARM64 Symbols: $FinalMSIXARM64SymbolPath" -ForegroundColor Cyan

    }

    Write-Host -Object "MSIX Bundle File Path: $MSIXBundle" -ForegroundColor Yellow
    Write-Host -Object "MSIX Bundle File Name: $FinalBundleFileName" -ForegroundColor Yellow

    if ($Workflow) {

        [XML]$CSProjXMLContent = Get-Content -Path $CsProjFilePath -Force
        [string]$MSIXVersion = $CSProjXMLContent.Project.PropertyGroup.FileVersion
        [string]$MSIXVersion = $MSIXVersion.Trim() # It would have trailing whitespaces
        if ([string]::IsNullOrWhiteSpace($FinalMSIXX64Path) -or [string]::IsNullOrWhiteSpace($FinalMSIXX64Name) -or [string]::IsNullOrWhiteSpace($MSIXVersion)) { throw 'Necessary info could not be found' }

        # Write the MSIXVersion to GITHUB_ENV to set it as an environment variable for the entire workflow
        Add-Content -Path ($env:GITHUB_ENV, $env:GITHUB_OUTPUT) -Value "PACKAGE_VERSION=$MSIXVersion"

        # Saving the details for the MSIX Bundle file
        Add-Content -Path ($env:GITHUB_ENV, $env:GITHUB_OUTPUT) -Value "MSIXBundle_PATH=$MSIXBundle"
        Add-Content -Path ($env:GITHUB_ENV, $env:GITHUB_OUTPUT) -Value "MSIXBundle_NAME=$FinalBundleFileName"

        # Saving the details of the log files
        Add-Content -Path ($env:GITHUB_ENV, $env:GITHUB_OUTPUT) -Value "X64MSBuildLog_PATH=$((Resolve-Path -Path .\X64MSBuildLog.binlog).Path)"
        Add-Content -Path ($env:GITHUB_ENV, $env:GITHUB_OUTPUT) -Value "ARM64MSBuildLog_PATH=$((Resolve-Path -Path .\ARM64MSBuildLog.binlog).Path)"

        # Saving the details of the X64 symbol file
        Add-Content -Path ($env:GITHUB_ENV, $env:GITHUB_OUTPUT) -Value "X64Symbol_PATH=$FinalMSIXX64SymbolPath"
        Add-Content -Path ($env:GITHUB_ENV, $env:GITHUB_OUTPUT) -Value "X64Symbol_NAME=$FinalMSIXX64SymbolName"

        # Saving the details of the ARM64 symbol file
        Add-Content -Path ($env:GITHUB_ENV, $env:GITHUB_OUTPUT) -Value "ARM64Symbol_PATH=$FinalMSIXARM64SymbolPath"
        Add-Content -Path ($env:GITHUB_ENV, $env:GITHUB_OUTPUT) -Value "ARM64Symbol_NAME=$FinalMSIXARM64SymbolName"

        # https://github.com/microsoft/sbom-tool
        # Generating SBOM
        Invoke-WebRequest -Uri 'https://github.com/microsoft/sbom-tool/releases/latest/download/sbom-tool-win-x64.exe' -OutFile "${Env:RUNNER_TEMP}\sbom-tool.exe"

        # https://github.com/microsoft/sbom-tool/blob/main/docs/sbom-tool-arguments.md
        . "${Env:RUNNER_TEMP}\sbom-tool.exe" generate -b $MSIXBundleOutput -bc .\ -pn 'AppControl Manager' -ps 'Violet Hansen' -pv $MSIXVersion -nsb 'https://github.com/HotCakeX/Harden-Windows-Security' -V Verbose -gt true -li true -pm true -D true -lto 80

        # Saving the details of the SBOM file
        Add-Content -Path ($env:GITHUB_ENV, $env:GITHUB_OUTPUT) -Value "SBOM_PATH=$MSIXBundleOutput/_manifest/spdx_2.2/manifest.spdx.json"
        Add-Content -Path ($env:GITHUB_ENV, $env:GITHUB_OUTPUT) -Value 'SBOM_NAME=manifest.spdx.json'
    }

    if ($Install -and $PackageFamilyName -eq 'AppControlManager_sadt7br7jpt02') {
        (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/HotCakeX/Harden-Windows-Security/main/Harden-Windows-Security.ps1') + "AppControl -Verbose -MSIXBundlePath '$MSIXBundle'" | Invoke-Expression
    }

    if ($Upload) {
        dotnet clean '.\eXclude\PartnerCenter\PartnerCenter.slnx' --configuration Release
        dotnet build '.\eXclude\PartnerCenter\PartnerCenter.slnx' --configuration Release --verbosity minimal
        dotnet msbuild '.\eXclude\PartnerCenter\PartnerCenter.slnx' /p:Platform=x64 /p:PublishProfile=win-x64 /t:Publish -v:minimal

        [System.String]$TokenEndpoint = $env:PARTNERCENTER_TOKENENDPOINT
        [System.String]$ClientId = $env:PARTNERCENTER_CLIENTID
        [System.String]$ClientSecret = $env:PARTNERCENTER_CLIENTSECRET
        [System.String]$ApplicationId = $env:PARTNERCENTER_APPLICATIONID

        [System.String]$PackageFilePath = $MSIXBundle
        [System.String]$ReleaseNotesFilePath = (Resolve-Path -Path ReleaseNotes.txt).Path

        . '.\eXclude\PartnerCenter\X64Output\PartnerCenter.exe' $TokenEndpoint $ClientId $ClientSecret $ApplicationId $PackageFilePath $ReleaseNotesFilePath
    }

    if ($null -ne $Stopwatch) {

        $Stopwatch.Stop()

        $Elapsed = $Stopwatch.Elapsed
        [string]$Result = @"
Execution Time:
----------------------------
Total Time   : $($Elapsed.ToString('g'))
Hours        : $($Elapsed.Hours)
Minutes      : $($Elapsed.Minutes)
Seconds      : $($Elapsed.Seconds)
Milliseconds : $($Elapsed.Milliseconds)
----------------------------
"@

        Write-Host -Object $Result -ForegroundColor Cyan
    }
}

# For GitHub workflow 1
# Build_ACM -Type Self -DownloadRepo $false -InstallDeps $false -Workflow $true -UpdateWorkLoads $false -Install $false -Upload $false -X64ONLY $false
# For GitHub workflow 2
# Build_ACM -Type Store -DownloadRepo $false -InstallDeps $false -Workflow $true -UpdateWorkLoads $false -Install $false -Upload $true -X64ONLY $false
# Example of building the app from the source code and installing it on a clean system with self-signed certificate
# Build_ACM -Type Self -DownloadRepo $true -InstallDeps $true -Workflow $false -UpdateWorkLoads $false -Install $true -Upload $false -X64ONLY $false
# Example of building the app from the source code on a clean system and uploading it to the Partner Center
# Build_ACM -Type Store -DownloadRepo $true -InstallDeps $true -Workflow $false -UpdateWorkLoads $false -Install $false -Upload $true -X64ONLY $false
# Local Test - X64 only
# Build_ACM -Type Self -DownloadRepo $false -InstallDeps $false -Workflow $false -UpdateWorkLoads $false -Install $false -Upload $false -X64ONLY $true
# Local Test - ARM64 + X64
# Build_ACM -Type Self -DownloadRepo $false -InstallDeps $false -Workflow $false -UpdateWorkLoads $false -Install $false -Upload $false -X64ONLY $false










C#


Clone this wiki locally