NugetInstall/NugetInstall.psm1

function Get-EveryDependency {
    $buildToolsInfo = Get-BuildToolsPackageInfo
    $trustedSigningInfo = Get-TrustedSigningPackageInfo
    $signCliInfo = Get-SignCliPackageInfo

    $buildToolsContentPath = $buildToolsInfo.ContentPath
    $trustedSigningContentPath = $trustedSigningInfo.ContentPath
    $signCliContentPath = $signCliInfo.ContentPath

    $buildToolsInstalled = Test-Path -Path $buildToolsInfo.PackageInstallPath
    $trustedSigningInstalled = Test-Path -Path $trustedSigningInfo.PackageInstallPath
    $signCliInstalled = Test-Path -Path $signCliInfo.PackageInstallPath

    Write-Information -MessageData "`tBuild tools package installed: $buildToolsInstalled" -InformationAction Continue
    Write-Information -MessageData "`tTrusted signing package installed: $trustedSigningInstalled" -InformationAction Continue
    Write-Information -MessageData "`tSign CLI package installed: $signCliInstalled" -InformationAction Continue

    if (-Not $buildToolsInstalled -or -Not $trustedSigningInstalled) {
        Write-Information -MessageData "`tInstalling required dependencies." -InformationAction Continue
        $packageSource = Get-NugetV2PackageSource

        $buildToolsInfo.Remove("ContentPath")
        Install-NugetPackage @buildToolsInfo -PackageSource $packageSource

        $trustedSigningInfo.Remove("ContentPath")
        Install-NugetPackage @trustedSigningInfo -PackageSource $packageSource

        $signCliInfo.Remove("ContentPath")
        Install-NugetToolPackage @signCliInfo -PackageSource $packageSource
    } else {
        Write-Information -MessageData "`tAll required dependencies are installed." -InformationAction Continue
    }

    return @{
        DlibFolderPath = $trustedSigningContentPath
        SignToolFolderPath = $buildToolsContentPath
        SignCliFolderPath = $signCliContentPath
    }
}

function Get-BuildToolsPackageInfo {
    $getPackageInfoParams = @{
        PackageName = "Microsoft.Windows.SDK.BuildTools"
        PackageVersion = "10.0.22621.3233"
        ContentPath = "bin\10.0.22621.0\x64"
    }
    return Get-PackageInfo @getPackageInfoParams
}

function Get-TrustedSigningPackageInfo {
    $getPackageInfoParams = @{
        PackageName = "Microsoft.Trusted.Signing.Client"
        PackageVersion = "1.0.53"
        ContentPath = "bin\x64"
    }
    return Get-PackageInfo @getPackageInfoParams
}

function Get-SignCliPackageInfo {
    $getPackageInfoParams = @{
        PackageName = "sign"
        PackageVersion = "0.9.1-beta.24469.1"
        ContentPath = "tools\net8.0\any"
    }
    return Get-PackageInfo @getPackageInfoParams
}

function Get-PackageInfo {
    param (
        [Parameter(Mandatory)]
        [string]$PackageName,

        [Parameter(Mandatory)]
        [string]$PackageVersion,

        [Parameter(Mandatory)]
        [string]$ContentPath
    )

    $appDataPath = $env:localappdata
    $trustedSigningPath = Join-Path -Path $appDataPath -ChildPath "TrustedSigning"
    $packageVersionsPath = Join-Path -Path $trustedSigningPath -ChildPath $PackageName
    $packageInstallPath = Join-Path -Path $packageVersionsPath -ChildPath "$PackageName.$PackageVersion"
    $packageContentPath = Join-Path -Path $packageInstallPath -ChildPath $ContentPath

    return @{
        PackageName = $PackageName
        PackageVersion = $PackageVersion
        PackageVersionsPath = $packageVersionsPath
        PackageInstallPath = $packageInstallPath
        ContentPath = $packageContentPath
    }
}

function Get-NugetV2PackageSource {
    $location = "https://www.nuget.org/api/v2/"

    try {
        $source = Get-PackageSource -Location $location -ErrorAction Stop
        $source = $source | Select-Object -First 1
        Write-Information -MessageData "`t`tFound existing package source: $($source.Name)" -InformationAction Continue
        return $source.Name
    } catch {
        $registerPackageSourceParams = @{
            Name = "trusted-signing-ps"
            Location = $location
            ProviderName = "NuGet"
        }
        $source = Register-PackageSource @registerPackageSourceParams
        Write-Information -MessageData "`t`tRegistered new package source: $($source.Name)" -InformationAction Continue
        return $source.Name
    }
}

function Install-NugetPackage {
    param (
        [Parameter(Mandatory)]
        [string]$PackageName,

        [Parameter(Mandatory)]
        [string]$PackageVersion,

        [Parameter(Mandatory)]
        [string]$PackageVersionsPath,

        [Parameter(Mandatory)]
        [string]$PackageInstallPath,

        [Parameter(Mandatory)]
        [string]$PackageSource
    )

    Write-Information -MessageData "`t`tInstalling package: $PackageName $PackageVersion" -InformationAction Continue

    if (-Not (Test-Path -Path $PackageVersionsPath)) {
        New-Item -Path $PackageVersionsPath -ItemType Directory | Out-Null
    }

    if (-Not (Test-Path -Path $PackageInstallPath)) {
        Remove-Item -Path "$PackageVersionsPath\*" -Recurse -Force

        $installPackageParams = @{
            Name = $PackageName
            RequiredVersion = $PackageVersion
            Source = $PackageSource
            Destination = $PackageVersionsPath
            Force = $true
        }
        Install-Package @installPackageParams | Out-Null
    }
}

function Install-NugetToolPackage {
    param (
        [Parameter(Mandatory)]
        [string]$PackageName,

        [Parameter(Mandatory)]
        [string]$PackageVersion,

        [Parameter(Mandatory)]
        [string]$PackageVersionsPath,

        [Parameter(Mandatory)]
        [string]$PackageInstallPath,

        [Parameter(Mandatory)]
        [string]$PackageSource
    )

    Write-Information -MessageData "`t`tInstalling package: $PackageName $PackageVersion" -InformationAction Continue

    if (-Not (Test-Path -Path $PackageVersionsPath)) {
        New-Item -Path $PackageVersionsPath -ItemType Directory | Out-Null
    }

    if (-Not (Test-Path -Path $PackageInstallPath)) {
        Remove-Item -Path "$PackageVersionsPath\*" -Recurse -Force

        $installToolPackageArguments = @(
            "tool",
            "install",
            $PackageName,
            "--version",
            $PackageVersion,
            "--tool-path",
            $PackageVersionsPath,
            "--add-source",
            $PackageSource
        )
        $startProcessParams = @{
            FilePath = "dotnet"
            ArgumentList = $installToolPackageArguments
            NoNewWindow = $true
            PassThru = $true
            RedirectStandardOutput = "NUL"
        }
        $process = Start-Process @startProcessParams

        try {
            Wait-Process -InputObject $process -Timeout 300
            if ($process.ExitCode -ne 0) {
                throw "Failed to install package: $PackageName $PackageVersion"
            }

            $storePath = Join-Path -Path $PackageVersionsPath -ChildPath ".store\$PackageName\$PackageVersion\$PackageName\$PackageVersion"
            $packagePath = Join-Path -Path $PackageVersionsPath -ChildPath "$PackageName.$PackageVersion"
            Move-Item -Path $storePath -Destination $packagePath -Force
            Remove-Item -Path "$PackageVersionsPath\.store" -Recurse -Force
            Remove-Item -Path "$PackageVersionsPath\sign.exe" -Force
        } catch [TimeoutException] {
            throw "Failed to install package in allotted time: $PackageName $PackageVersion"
        }
    }
}