diff --git a/images/windows/scripts/build/Install-AliyunCli.ps1 b/images/windows/scripts/build/Install-AliyunCli.ps1 index 29463fdd9..d4d5c13cb 100644 --- a/images/windows/scripts/build/Install-AliyunCli.ps1 +++ b/images/windows/scripts/build/Install-AliyunCli.ps1 @@ -12,10 +12,9 @@ $downloadUrl = ($assets.browser_download_url -ilike "*aliyun-cli-windows-*-amd64 $packagePath = Invoke-DownloadWithRetry $downloadUrl #region Supply chain security - Alibaba Cloud CLI -$fileHash = (Get-FileHash -Path $packagePath -Algorithm SHA256).Hash $hashUrl = ($assets.browser_download_url -ilike "*SHASUMS256.txt*") | Select-Object -First 1 $externalHash = (Invoke-RestMethod -Uri $hashURL).ToString().Split("`n").Where({ $_ -ilike "*$installerFileName*" }).Split(' ')[0] -Use-ChecksumComparison $fileHash $externalHash +Test-FileChecksum $packagePath -ExpectedSHA256Sum $externalHash #endregion Write-Host "Expand aliyun-cli archive" diff --git a/images/windows/scripts/build/Install-AndroidSDK.ps1 b/images/windows/scripts/build/Install-AndroidSDK.ps1 index 32eb14287..e5da5c85d 100644 --- a/images/windows/scripts/build/Install-AndroidSDK.ps1 +++ b/images/windows/scripts/build/Install-AndroidSDK.ps1 @@ -35,7 +35,7 @@ function Install-AndroidSDKPackages { [Parameter(Mandatory = $true)] [AllowEmptyCollection()] [AllowNull()] - [string[]]$Packages + [string[]] $Packages ) # The sdkmanager.bat script is used to install Android SDK packages. @@ -63,11 +63,7 @@ $androidToolset = (Get-ToolsetContent).android $cmdlineToolsUrl = $androidToolset.commandline_tools_url $cmdlineToolsArchPath = Invoke-DownloadWithRetry $cmdlineToolsUrl -#region Supply chain security -$localFileHash = (Get-FileHash -Path $cmdlineToolsArchPath -Algorithm SHA256).Hash - -Use-ChecksumComparison -LocalFileHash $localFileHash -DistributorFileHash $androidToolset.hash -#endregion +Test-FileChecksum $cmdlineToolsArchPath -ExpectedSHA256Sum $androidToolset.hash Expand-7ZipArchive -Path $cmdlineToolsArchPath -DestinationPath "${SDKInstallRoot}\cmdline-tools" diff --git a/images/windows/scripts/build/Install-Chocolatey.ps1 b/images/windows/scripts/build/Install-Chocolatey.ps1 index c3b2feffc..2f9a4b873 100644 --- a/images/windows/scripts/build/Install-Chocolatey.ps1 +++ b/images/windows/scripts/build/Install-Chocolatey.ps1 @@ -25,7 +25,7 @@ if ($userPath) { # Verify and run choco installer $signatureThumbprint = "83AC7D88C66CB8680BCE802E0F0F5C179722764B" $InstallScriptPath = Invoke-DownloadWithRetry 'https://chocolatey.org/install.ps1' -Test-FileSignature -FilePath $InstallScriptPath -ExpectedThumbprint $signatureThumbprint +Test-FileSignature -Path $InstallScriptPath -ExpectedThumbprint $signatureThumbprint Invoke-Expression $InstallScriptPath # Turn off confirmation diff --git a/images/windows/scripts/build/Install-CloudFoundryCli.ps1 b/images/windows/scripts/build/Install-CloudFoundryCli.ps1 index f989a63bb..5df9c8a41 100644 --- a/images/windows/scripts/build/Install-CloudFoundryCli.ps1 +++ b/images/windows/scripts/build/Install-CloudFoundryCli.ps1 @@ -21,6 +21,6 @@ Add-MachinePathItem $CloudFoundryCliPath # Validate cf signature $CloudFoundrySignatureThumbprint = "4C69EDD13930ED01B83DD1D17B09C434DC1F2177" -Test-FileSignature -FilePath "$CloudFoundryCliPath\cf.exe" -ExpectedThumbprint $CloudFoundrySignatureThumbprint +Test-FileSignature -Path "$CloudFoundryCliPath\cf.exe" -ExpectedThumbprint $CloudFoundrySignatureThumbprint Invoke-PesterTests -TestFile "CLI.Tools" -TestName "CloudFoundry CLI" diff --git a/images/windows/scripts/build/Install-DotnetSDK.ps1 b/images/windows/scripts/build/Install-DotnetSDK.ps1 index 3eb9461bd..d4198c92b 100644 --- a/images/windows/scripts/build/Install-DotnetSDK.ps1 +++ b/images/windows/scripts/build/Install-DotnetSDK.ps1 @@ -22,7 +22,7 @@ function Get-SDKVersionsToInstall ( $currentReleases = $currentReleases.'releases' | Where-Object { !$_.'release-version'.Contains('-') } $sdks = @() - ForEach ($release in $currentReleases) { + foreach ($release in $currentReleases) { $sdks += $release.'sdk' $sdks += $release.'sdks' } @@ -30,7 +30,7 @@ function Get-SDKVersionsToInstall ( return $sdks.version ` | Sort-Object { [Version] $_ } -Unique ` | Group-Object { $_.Substring(0, $_.LastIndexOf('.') + 2) } ` - | Foreach-Object { $_.Group[-1] } + | ForEach-Object { $_.Group[-1] } } function Invoke-Warmup ( @@ -62,9 +62,7 @@ function InstallSDKVersion ( #region Supply chain security $distributorFileHash = (Invoke-RestMethod -Uri "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/$dotnetVersion/releases.json").releases.sdks.Where({ $_.version -eq $SdkVersion }).files.Where({ $_.name -eq 'dotnet-sdk-win-x64.zip' }).hash - $localFileHash = (Get-FileHash -Path $ZipPath -Algorithm 'SHA512').Hash - - Use-ChecksumComparison -LocalFileHash $localFileHash -DistributorFileHash $distributorFileHash + Test-FileChecksum $ZipPath -ExpectedSHA512Sum $distributorFileHash #endregion } else { Write-Host "Sdk version $sdkVersion already installed" @@ -87,29 +85,23 @@ function InstallAllValidSdks() { $installationUrl = "https://dot.net/v1/${installationName}" Invoke-DownloadWithRetry -Url $installationUrl -Path ".\$installationName" - ForEach ($dotnetVersion in $dotnetVersions) - { + foreach ($dotnetVersion in $dotnetVersions) { $sdkVersionsToInstall = Get-SDKVersionsToInstall -DotnetVersion $dotnetVersion - - ForEach ($sdkVersion in $sdkVersionsToInstall) - { + foreach ($sdkVersion in $sdkVersionsToInstall) { InstallSDKVersion -SdkVersion $sdkVersion -DotnetVersion $dotnetVersion -Warmup $warmup } } } -function InstallTools() -{ +function InstallTools() { $dotnetTools = (Get-ToolsetContent).dotnet.tools - ForEach ($dotnetTool in $dotnetTools) - { + foreach ($dotnetTool in $dotnetTools) { dotnet tool install $($dotnetTool.name) --tool-path "C:\Users\Default\.dotnet\tools" --add-source https://api.nuget.org/v3/index.json | Out-Null } } -function RunPostInstallationSteps() -{ +function RunPostInstallationSteps() { # Add dotnet to PATH Add-MachinePathItem "C:\Program Files\dotnet" diff --git a/images/windows/scripts/build/Install-EdgeDriver.ps1 b/images/windows/scripts/build/Install-EdgeDriver.ps1 index a4a4223c0..a8c54c354 100644 --- a/images/windows/scripts/build/Install-EdgeDriver.ps1 +++ b/images/windows/scripts/build/Install-EdgeDriver.ps1 @@ -28,7 +28,7 @@ Expand-7ZipArchive -Path $archivePath -DestinationPath $edgeDriverPath #Validate the EdgeDriver signature $signatureThumbprint = "CB9C4FBEA1D87D2D468AC5A9CAAB0163F6AD8401" -Test-FileSignature -FilePath "$edgeDriverPath\msedgedriver.exe" -ExpectedThumbprint $signatureThumbprint +Test-FileSignature -Path "$edgeDriverPath\msedgedriver.exe" -ExpectedThumbprint $signatureThumbprint Write-Host "Setting the environment variables..." [Environment]::SetEnvironmentVariable("EdgeWebDriver", $EdgeDriverPath, "Machine") diff --git a/images/windows/scripts/build/Install-Firefox.ps1 b/images/windows/scripts/build/Install-Firefox.ps1 index 66e6d443c..b9c847774 100644 --- a/images/windows/scripts/build/Install-Firefox.ps1 +++ b/images/windows/scripts/build/Install-Firefox.ps1 @@ -50,7 +50,7 @@ Expand-7ZipArchive -Path $GeckoDriverArchPath -DestinationPath $GeckoDriverPath # Validate Gecko WebDriver signature $GeckoDriverSignatureThumbprint = "1326B39C3D5D2CA012F66FB439026F7B59CB1974" -Test-FileSignature -FilePath "$GeckoDriverPath/geckodriver.exe" -ExpectedThumbprint $GeckoDriverSignatureThumbprint +Test-FileSignature -Path "$GeckoDriverPath/geckodriver.exe" -ExpectedThumbprint $GeckoDriverSignatureThumbprint Write-Host "Setting the environment variables..." Add-MachinePathItem -PathItem $GeckoDriverPath diff --git a/images/windows/scripts/build/Install-JavaTools.ps1 b/images/windows/scripts/build/Install-JavaTools.ps1 index 5769f38ff..1a9572876 100644 --- a/images/windows/scripts/build/Install-JavaTools.ps1 +++ b/images/windows/scripts/build/Install-JavaTools.ps1 @@ -64,12 +64,7 @@ function Install-JavaJDK { # Download and extract java binaries to temporary folder $downloadUrl = $asset.binary.package.link $archivePath = Invoke-DownloadWithRetry $downloadUrl - - #region Supply chain security - JDK - $fileHash = (Get-FileHash -Path $archivePath -Algorithm SHA256).Hash - $externalHash = $asset.binary.package.checksum - Use-ChecksumComparison $fileHash $externalHash - #endregion + Test-FileChecksum $archivePath -ExpectedSHA256Sum $asset.binary.package.checksum # We have to replace '+' sign in the version to '-' due to the issue with incorrect path in Android builds https://github.com/actions/runner-images/issues/3014 $fullJavaVersion = $asset.version.semver -replace '\+', '-' @@ -123,7 +118,7 @@ Install-ChocoPackage maven -ArgumentList "--version=$versionToInstall" Install-ChocoPackage gradle # Add maven env variables to Machine -[string]$m2 = ([Environment]::GetEnvironmentVariable("PATH", "Machine")).Split(";") -match "maven" +[string] $m2 = ([Environment]::GetEnvironmentVariable("PATH", "Machine")).Split(";") -match "maven" $m2_repo = 'C:\ProgramData\m2' New-Item -Path $m2_repo -ItemType Directory -Force | Out-Null @@ -138,8 +133,7 @@ $sha256sum = '79479DDE416B082F38ECD1F2F7C6DEBD4D0C2249AF80FD046D1CE05D628F2EC6' $coberturaPath = "C:\cobertura-2.1.1" $archivePath = Invoke-DownloadWithRetry $uri -$fileHash = (Get-FileHash -Path $archivePath -Algorithm SHA256).Hash -Use-ChecksumComparison $fileHash $sha256sum +Test-FileChecksum $archivePath -ExpectedSHA256Sum $sha256sum Expand-7ZipArchive -Path $archivePath -DestinationPath "C:\" [Environment]::SetEnvironmentVariable("COBERTURA_HOME", $coberturaPath, "Machine") diff --git a/images/windows/scripts/build/Install-Kotlin.ps1 b/images/windows/scripts/build/Install-Kotlin.ps1 index 9d848abfa..71fe90510 100644 --- a/images/windows/scripts/build/Install-Kotlin.ps1 +++ b/images/windows/scripts/build/Install-Kotlin.ps1 @@ -14,9 +14,8 @@ $kotlinDownloadUrl = Resolve-GithubReleaseAssetUrl ` $kotlinArchivePath = Invoke-DownloadWithRetry $kotlinDownloadUrl #region Supply chain security -$fileHash = (Get-FileHash -Path $kotlinArchivePath -Algorithm SHA256).Hash $externalHash = Get-HashFromGitHubReleaseBody -RepoOwner "JetBrains" -RepoName "kotlin" -FileName "$kotlinBinaryName-*.zip" -Version $kotlinVersion -WordNumber 2 -Use-ChecksumComparison $fileHash $externalHash +Test-FileChecksum $kotlinArchivePath -ExpectedSHA256Sum $externalHash #endregion Write-Host "Expand Kotlin archive" diff --git a/images/windows/scripts/build/Install-KubernetesTools.ps1 b/images/windows/scripts/build/Install-KubernetesTools.ps1 index 1e82244dc..529957f7a 100644 --- a/images/windows/scripts/build/Install-KubernetesTools.ps1 +++ b/images/windows/scripts/build/Install-KubernetesTools.ps1 @@ -14,10 +14,9 @@ $null = New-Item -Path $destFilePath -ItemType Directory -Force $packagePath = Invoke-DownloadWithRetry -Url $kindDownloadLink -Path "$destFilePath\kind.exe" #region Supply chain security - Kind -$fileHash = (Get-FileHash -Path $packagePath -Algorithm SHA256).Hash $hashUrl = ($assets.browser_download_url -match "kind-windows-amd64.sha256sum") | Select-Object -First 1 $externalHash = (Invoke-RestMethod -Uri $hashURL).ToString().Split("`n").Where({ $_ -ilike "*kind-windows-amd64*" }).Split(' ')[0] -Use-ChecksumComparison $fileHash $externalHash +Test-FileChecksum $packagePath -ExpectedSHA256Sum $externalHash #endregion Add-MachinePathItem $destFilePath diff --git a/images/windows/scripts/build/Install-Msys2.ps1 b/images/windows/scripts/build/Install-Msys2.ps1 index 09ba95a10..45e0793f1 100644 --- a/images/windows/scripts/build/Install-Msys2.ps1 +++ b/images/windows/scripts/build/Install-Msys2.ps1 @@ -21,10 +21,9 @@ function Install-Msys2 { Write-Host "Finished download" #region Supply chain security - Kind - $fileHash = (Get-FileHash -Path $msys2File -Algorithm SHA256).Hash $hashUrl = ($assets.browser_download_url -match "msys2-checksums.txt") | Select-Object -First 1 $externalHash = (Invoke-RestMethod -Uri $hashURL).ToString().Split("`n").Where({ $_ -ilike "*msys2-x86_64*" }).Split(' ')[0] - Use-ChecksumComparison $fileHash $externalHash + Test-FileChecksum $msys2File -ExpectedSHA256Sum $externalHash #endregion # extract tar.xz to C:\ diff --git a/images/windows/scripts/build/Install-PyPy.ps1 b/images/windows/scripts/build/Install-PyPy.ps1 index 9fb92b718..d0ae9fb2a 100644 --- a/images/windows/scripts/build/Install-PyPy.ps1 +++ b/images/windows/scripts/build/Install-PyPy.ps1 @@ -7,8 +7,8 @@ function Install-PyPy { param( - [String]$PackagePath, - [String]$Architecture + [String] $PackagePath, + [String] $Architecture ) # Create PyPy toolcache folder @@ -102,16 +102,13 @@ foreach($toolsetVersion in $toolsetVersions.versions) $tempPyPyPackagePath = Invoke-DownloadWithRetry $latestMajorPyPyVersion.download_url #region Supply chain security - $localFileHash = (Get-FileHash -Path $tempPyPyPackagePath -Algorithm SHA256).Hash $distributorFileHash = $null - - ForEach($node in $checksums) { - if($node.InnerText -ilike "*${filename}*") { + foreach ($node in $checksums) { + if ($node.InnerText -ilike "*${filename}*") { $distributorFileHash = $node.InnerText.ToString().Split("`n").Where({ $_ -ilike "*${filename}*" }).Split(' ')[0] } } - - Use-ChecksumComparison -LocalFileHash $localFileHash -DistributorFileHash $distributorFileHash + Test-FileChecksum $tempPyPyPackagePath -ExpectedSHA256Sum $distributorFileHash #endregion Install-PyPy -PackagePath $tempPyPyPackagePath -Architecture $toolsetVersions.arch diff --git a/images/windows/scripts/build/Install-Rust.ps1 b/images/windows/scripts/build/Install-Rust.ps1 index 032915af5..e8d19f406 100644 --- a/images/windows/scripts/build/Install-Rust.ps1 +++ b/images/windows/scripts/build/Install-Rust.ps1 @@ -13,10 +13,8 @@ $env:CARGO_HOME = "C:\Users\Default\.cargo" $rustupPath = Invoke-DownloadWithRetry "https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe" #region Supply chain security -$localFileHash = (Get-FileHash -Path (Join-Path ${env:TEMP} 'rustup-init.exe') -Algorithm SHA256).Hash $distributorFileHash = (Invoke-RestMethod -Uri 'https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe.sha256').Trim() - -Use-ChecksumComparison -LocalFileHash $localFileHash -DistributorFileHash $distributorFileHash +Test-FileChecksum (Join-Path ${env:TEMP} 'rustup-init.exe') -ExpectedSHA256Sum $distributorFileHash #endregion # Install Rust by running rustup-init.exe (disabling the confirmation prompt with -y) diff --git a/images/windows/scripts/build/Install-Stack.ps1 b/images/windows/scripts/build/Install-Stack.ps1 index 85e1a1994..5c5180407 100644 --- a/images/windows/scripts/build/Install-Stack.ps1 +++ b/images/windows/scripts/build/Install-Stack.ps1 @@ -16,10 +16,9 @@ $DestinationPath = Join-Path $StackToolcachePath "x64" $StackArchivePath = Invoke-DownloadWithRetry $DownloadUrl #region Supply chain security - Stack -$fileHash = (Get-FileHash -Path $StackArchivePath -Algorithm SHA256).Hash $hashUrl = $StackReleasesJson.assets | Where-Object { $_.name.EndsWith("$DownloadFilePattern.sha256") } | Select-Object -ExpandProperty "browser_download_url" -First 1 $externalHash = (Invoke-RestMethod -Uri $hashURL).ToString().Split("`n").Where({ $_ -ilike "*$DownloadFilePattern*" }).Split(' ')[0] -Use-ChecksumComparison $fileHash $externalHash +Test-FileChecksum $StackArchivePath -ExpectedSHA256Sum $externalHash #endregion Write-Host "Expand stack archive" diff --git a/images/windows/scripts/helpers/ImageHelpers.psm1 b/images/windows/scripts/helpers/ImageHelpers.psm1 index fbc2ae041..ed65b201a 100644 --- a/images/windows/scripts/helpers/ImageHelpers.psm1 +++ b/images/windows/scripts/helpers/ImageHelpers.psm1 @@ -38,8 +38,8 @@ Export-ModuleMember -Function @( 'Get-VisualStudioInstance' 'Get-VisualStudioComponents' 'Get-WindowsUpdateStates' - 'Use-ChecksumComparison' 'Get-HashFromGitHubReleaseBody' + 'Test-FileChecksum' 'Test-FileSignature' 'Update-Environment' ) diff --git a/images/windows/scripts/helpers/InstallHelpers.ps1 b/images/windows/scripts/helpers/InstallHelpers.ps1 index c6c05f5b1..5a5bef1e8 100644 --- a/images/windows/scripts/helpers/InstallHelpers.ps1 +++ b/images/windows/scripts/helpers/InstallHelpers.ps1 @@ -75,20 +75,18 @@ function Install-Binary { if ($PSBoundParameters.ContainsKey('ExpectedSignature')) { if ($ExpectedSignature) { - Test-FileSignature -FilePath $filePath -ExpectedThumbprint $ExpectedSignature + Test-FileSignature -Path $filePath -ExpectedThumbprint $ExpectedSignature } else { throw "ExpectedSignature parameter is specified, but no signature is provided." } } if ($ExpectedSHA256Sum) { - $fileHash = (Get-FileHash -Path $filePath -Algorithm SHA256).Hash - Use-ChecksumComparison $fileHash $ExpectedSHA256Sum + Test-FileChecksum $filePath -ExpectedSHA256Sum $ExpectedSHA256Sum } if ($ExpectedSHA512Sum) { - $fileHash = (Get-FileHash -Path $filePath -Algorithm SHA512).Hash - Use-ChecksumComparison $fileHash $ExpectedSHA512Sum + Test-FileChecksum $filePath -ExpectedSHA512Sum $ExpectedSHA512Sum } if ($ExtraInstallArgs -and $InstallArgs) { @@ -388,7 +386,7 @@ function Get-TCToolVersionPath { # Take latest installed version in case if toolset version contains wildcards $foundVersion = Get-Item $versionPath ` - | Sort-Object -Property { [version]$_.name } -Descending ` + | Sort-Object -Property { [version] $_.name } -Descending ` | Select-Object -First 1 if (-not $foundVersion) { @@ -414,11 +412,11 @@ function Expand-7ZipArchive { Param ( [Parameter(Mandatory = $true)] - [string]$Path, + [string] $Path, [Parameter(Mandatory = $true)] - [string]$DestinationPath, + [string] $DestinationPath, [ValidateSet("x", "e")] - [char]$ExtractMethod = "x" + [char] $ExtractMethod = "x" ) Write-Host "Expand archive '$PATH' to '$DestinationPath' directory" @@ -455,7 +453,7 @@ function Get-AndroidPackages { #> Param ( - [string]$SDKRootPath + [string] $SDKRootPath ) if (-not $SDKRootPath) { @@ -503,9 +501,9 @@ function Get-AndroidPlatformPackages { #> Param ( - [string]$SDKRootPath, + [string] $SDKRootPath, [Alias("minVersion")] - [int]$minimumVersion = 0 + [int] $minimumVersion = 0 ) if (-not $SDKRootPath) { @@ -545,9 +543,9 @@ function Get-AndroidBuildToolPackages { #> Param ( - [string]$SDKRootPath, + [string] $SDKRootPath, [Alias("minVersion")] - [version]$minimumVersion = "0.0.0" + [version] $minimumVersion = "0.0.0" ) if (-not $SDKRootPath) { @@ -582,7 +580,7 @@ function Get-AndroidInstalledPackages { Param ( - [string]$SDKRootPath + [string] $SDKRootPath ) if (-not $SDKRootPath) { @@ -750,7 +748,7 @@ function Resolve-GithubReleaseAssetUrl { } # Sort releases by version - $releases = $releases | Sort-Object -Descending { [version]$_.version } + $releases = $releases | Sort-Object -Descending { [version] $_.version } # Select releases matching version if ($Version -eq "latest") { @@ -789,35 +787,18 @@ function Resolve-GithubReleaseAssetUrl { return ($matchedUrl -as [string]) } -function Use-ChecksumComparison { - param ( - [Parameter(Mandatory = $true)] - [string]$LocalFileHash, - [Parameter(Mandatory = $true)] - [string]$DistributorFileHash - ) - - Write-Verbose "Performing checksum verification" - - if ($LocalFileHash -ne $DistributorFileHash) { - throw "Checksum verification failed. Expected hash: $DistributorFileHash; Actual hash: $LocalFileHash." - } else { - Write-Verbose "Checksum verification passed" - } -} - function Get-HashFromGitHubReleaseBody { param ( - [string]$RepoOwner, - [string]$RepoName, + [string] $RepoOwner, + [string] $RepoName, [Parameter(Mandatory = $true)] - [string]$FileName, - [string]$Url, - [string]$Version = "latest", - [boolean]$IsPrerelease = $false, - [int]$SearchInCount = 100, - [string]$Delimiter = '|', - [int]$WordNumber = 1 + [string] $FileName, + [string] $Url, + [string] $Version = "latest", + [boolean] $IsPrerelease = $false, + [int] $SearchInCount = 100, + [string] $Delimiter = '|', + [int] $WordNumber = 1 ) if ($Url) { @@ -846,15 +827,104 @@ function Get-HashFromGitHubReleaseBody { } return $result } -function Test-FileSignature { - param( - [Parameter(Mandatory = $true)] - [string]$FilePath, - [Parameter(Mandatory = $true)] - [string[]]$ExpectedThumbprint + +function Test-FileChecksum { + <# + .SYNOPSIS + Verifies the checksum of a file. + + .DESCRIPTION + The Test-FileChecksum function verifies the SHA256 or SHA512 checksum of a file against an expected value. + If the checksum does not match the expected value, the function throws an error. + + .PARAMETER Path + The path to the file for which to verify the checksum. + + .PARAMETER ExpectedSHA256Sum + The expected SHA256 checksum. If this parameter is provided, the function will calculate the SHA256 checksum of the file and compare it to this value. + + .PARAMETER ExpectedSHA512Sum + The expected SHA512 checksum. If this parameter is provided, the function will calculate the SHA512 checksum of the file and compare it to this value. + + .EXAMPLE + Test-FileChecksum -Path "C:\temp\file.txt" -ExpectedSHA256Sum "ABC123" + + Verifies that the SHA256 checksum of the file at C:\temp\file.txt is ABC123. + + .EXAMPLE + Test-FileChecksum -Path "C:\temp\file.txt" -ExpectedSHA512Sum "DEF456" + + Verifies that the SHA512 checksum of the file at C:\temp\file.txt is DEF456. + + #> + + param ( + [Parameter(Mandatory = $true, Position = 0)] + [string] $Path, + [Parameter(Mandatory = $false)] + [String] $ExpectedSHA256Sum, + [Parameter(Mandatory = $false)] + [String] $ExpectedSHA512Sum ) - $signature = Get-AuthenticodeSignature $FilePath + Write-Verbose "Performing checksum verification" + + if ($ExpectedSHA256Sum -and $ExpectedSHA512Sum) { + throw "Only one of the ExpectedSHA256Sum and ExpectedSHA512Sum parameters can be provided" + } + + if (-not (Test-Path $Path)) { + throw "File not found: $Path" + } + + if ($ExpectedSHA256Sum) { + $fileHash = (Get-FileHash -Path $Path -Algorithm SHA256).Hash + $expectedHash = $ExpectedSHA256Sum + } + + if ($ExpectedSHA512Sum) { + $fileHash = (Get-FileHash -Path $Path -Algorithm SHA512).Hash + $expectedHash = $ExpectedSHA512Sum + } + + if ($fileHash -ne $expectedHash) { + throw "Checksum verification failed: expected $expectedHash, got $fileHash" + } else { + Write-Verbose "Checksum verification passed" + } +} + +function Test-FileSignature { + <# + .SYNOPSIS + Tests the file signature of a given file. + + .DESCRIPTION + The Test-FileSignature function checks the signature of a file against the expected thumbprints. + It uses the Get-AuthenticodeSignature cmdlet to retrieve the signature information of the file. + If the signature status is not valid or the thumbprint does not match the expected thumbprints, an exception is thrown. + + .PARAMETER Path + Specifies the path of the file to test. + + .PARAMETER ExpectedThumbprint + Specifies the expected thumbprints to match against the file's signature. + + .EXAMPLE + Test-FileSignature -Path "C:\Path\To\File.exe" -ExpectedThumbprint "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0" + + This example tests the signature of the file "C:\Path\To\File.exe" against the expected thumbprint "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0". + + #> + + param( + [Parameter(Mandatory = $true, Position = 0)] + [string] $Path, + [Parameter(Mandatory = $true)] + [string[]] $ExpectedThumbprint + ) + + $signature = Get-AuthenticodeSignature $Path if ($signature.Status -ne "Valid") { throw "Signature status is not valid. Status: $($signature.Status)" @@ -862,14 +932,14 @@ function Test-FileSignature { foreach ($thumbprint in $ExpectedThumbprint) { if ($signature.SignerCertificate.Thumbprint.Contains($thumbprint)) { - Write-Output "Signature for $FilePath is valid" + Write-Output "Signature for $Path is valid" $signatureMatched = $true return } } if ($signatureMatched) { - Write-Output "Signature for $FilePath is valid" + Write-Output "Signature for $Path is valid" } else { throw "Signature thumbprint do not match expected." } diff --git a/images/windows/scripts/helpers/VisualStudioHelpers.ps1 b/images/windows/scripts/helpers/VisualStudioHelpers.ps1 index 33fd7ffbb..a75baac49 100644 --- a/images/windows/scripts/helpers/VisualStudioHelpers.ps1 +++ b/images/windows/scripts/helpers/VisualStudioHelpers.ps1 @@ -41,7 +41,7 @@ Function Install-VisualStudio { $bootstrapperFilePath = Invoke-DownloadWithRetry $BootstrapperUrl # Verify that the bootstrapper is signed by Microsoft - Test-FileSignature -FilePath $bootstrapperFilePath -ExpectedThumbprint $SignatureThumbprint + Test-FileSignature -Path $bootstrapperFilePath -ExpectedThumbprint $SignatureThumbprint try { Write-Host "Enable short name support on Windows needed for Xamarin Android AOT, defaults appear to have been changed in Azure VMs"