[Windows] Cleanup various scripts (#8942)

* Use Resolve-GithubReleaseAssetUrl more widely

* Add the Get-ChecksumFromUrl function

* Sort exported functions and add docs

* Remove alias and fix typo

* Fix kind checksum url and syntax

* Fix checksums url for gh cli and msys2

* [Windows] Cleanup various scripts

* Add spaces after type specifications

* Rename the Take-Part function
This commit is contained in:
Vasilii Polikarpov
2023-12-04 10:50:53 +01:00
committed by GitHub
parent ed911223ab
commit 5ed2615017
56 changed files with 770 additions and 568 deletions

View File

@@ -13,7 +13,7 @@ Set-PSRepository -InstallationPolicy Trusted -Name PSGallery
Write-Host 'Warmup PSModuleAnalysisCachePath (speedup first powershell invocation by 20s)'
$PSModuleAnalysisCachePath = 'C:\PSModuleAnalysisCachePath\ModuleAnalysisCache'
[Environment]::SetEnvironmentVariable('PSModuleAnalysisCachePath', $PSModuleAnalysisCachePath, [System.EnvironmentVariableTarget]::Machine)
[Environment]::SetEnvironmentVariable('PSModuleAnalysisCachePath', $PSModuleAnalysisCachePath, "Machine")
# make variable to be available in the current session
${env:PSModuleAnalysisCachePath} = $PSModuleAnalysisCachePath

View File

@@ -19,7 +19,7 @@ $downloadUrl = Resolve-GithubReleaseAssetUrl `
-Repo "awslabs/aws-sam-cli" `
-Version "latest" `
-UrlMatchPattern "AWS_SAM_CLI_64_PY3.msi"
$externalHash = Get-GithubReleaseAssetHash `
$externalHash = Get-ChecksumFromGithubRelease `
-Repo "awslabs/aws-sam-cli" `
-Version "latest" `
-FileName (Split-Path $downloadUrl -Leaf) `

View File

@@ -5,15 +5,17 @@
################################################################################
Write-Host "Download Latest aliyun-cli archive"
$repoUrl = "https://api.github.com/repos/aliyun/aliyun-cli/releases/latest"
$installerFileName = "aliyun-cli-windows"
$assets = (Invoke-RestMethod -Uri $repoUrl).assets
$downloadUrl = ($assets.browser_download_url -ilike "*aliyun-cli-windows-*-amd64.zip*") | Select-Object -First 1
$downloadUrl = Resolve-GithubReleaseAssetUrl `
-Repo "aliyun/aliyun-cli" `
-Version "latest" `
-UrlMatchPattern "aliyun-cli-windows-*-amd64.zip"
$packagePath = Invoke-DownloadWithRetry $downloadUrl
#region Supply chain security - Alibaba Cloud CLI
$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]
$packageName = Split-Path $downloadUrl -Leaf
$externalHash = Get-ChecksumFromUrl -Type "SHA256" `
-Url ($downloadUrl -replace $packageName, "SHASUMS256.txt") `
-FileName $packageName
Test-FileChecksum $packagePath -ExpectedSHA256Sum $externalHash
#endregion

View File

@@ -7,26 +7,20 @@ Write-Host 'Install the latest Azure CLI release'
$azureCliConfigPath = 'C:\azureCli'
# Store azure-cli cache outside of the provisioning user's profile
[Environment]::SetEnvironmentVariable('AZURE_CONFIG_DIR', $azureCliConfigPath, [System.EnvironmentVariableTarget]::Machine)
# make variable to be available in the current session
${env:AZURE_CONFIG_DIR} = $azureCliConfigPath
[Environment]::SetEnvironmentVariable('AZURE_CONFIG_DIR', $azureCliConfigPath, "Machine")
$azureCliExtensionPath = Join-Path $Env:CommonProgramFiles 'AzureCliExtensionDirectory'
New-Item -ItemType 'Directory' -Path $azureCliExtensionPath | Out-Null
[Environment]::SetEnvironmentVariable('AZURE_EXTENSION_DIR', $azureCliExtensionPath, "Machine")
Install-Binary -Type MSI `
-Url 'https://aka.ms/installazurecliwindowsx64' `
-ExpectedSignature '72105B6D5F370B62FD5C82F1512F7AD7DEE5F2C0'
$azureCliExtensionPath = Join-Path $Env:CommonProgramFiles 'AzureCliExtensionDirectory'
$null = New-Item -ItemType 'Directory' -Path $azureCliExtensionPath
[Environment]::SetEnvironmentVariable('AZURE_EXTENSION_DIR', $azureCliExtensionPath, [System.EnvironmentVariableTarget]::Machine)
# make variable to be available in the current session
${env:AZURE_EXTENSION_DIR} = $azureCliExtensionPath
Update-Environment
# Warm-up Azure CLI
Write-Host "Warmup 'az'"
$env:PATH = [Environment]::GetEnvironmentVariable('PATH', 'Machine')
az --help | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Command 'az --help' failed"

View File

@@ -5,34 +5,26 @@
$azureDevOpsCliConfigPath = 'C:\azureDevOpsCli'
# Store azure-devops-cli cache outside of the provisioning user's profile
[Environment]::SetEnvironmentVariable('AZ_DEVOPS_GLOBAL_CONFIG_DIR', $azureDevOpsCliConfigPath, [System.EnvironmentVariableTarget]::Machine)
# make variable to be available in the current session
${env:AZ_DEVOPS_GLOBAL_CONFIG_DIR} = $azureDevOpsCliConfigPath
[Environment]::SetEnvironmentVariable('AZ_DEVOPS_GLOBAL_CONFIG_DIR', $azureDevOpsCliConfigPath, "Machine")
$azureDevOpsCliCachePath = Join-Path $azureDevOpsCliConfigPath 'cache'
$null = New-Item -ItemType 'Directory' -Path $azureDevOpsCliCachePath
New-Item -ItemType 'Directory' -Path $azureDevOpsCliCachePath | Out-Null
[Environment]::SetEnvironmentVariable('AZURE_DEVOPS_CACHE_DIR', $azureDevOpsCliCachePath, "Machine")
[Environment]::SetEnvironmentVariable('AZURE_DEVOPS_CACHE_DIR', $azureDevOpsCliCachePath, [System.EnvironmentVariableTarget]::Machine)
# make variable to be available in the current session
${env:AZURE_DEVOPS_CACHE_DIR} = $azureDevOpsCliCachePath
Update-Environment
az extension add -n azure-devops
if ($LASTEXITCODE -ne 0)
{
if ($LASTEXITCODE -ne 0) {
throw "Command 'az extension add -n azure-devops' failed"
}
# Warm-up Azure DevOps CLI
Write-Host "Warmup 'az-devops'"
@('devops', 'pipelines', 'boards', 'repos', 'artifacts') | ForEach-Object {
az $_ --help
if ($LASTEXITCODE -ne 0)
{
throw "Command 'az $_ --help' failed"
}
az $_ --help
if ($LASTEXITCODE -ne 0) {
throw "Command 'az $_ --help' failed"
}
}
# calling az devops login to force it to install `keyring`. Login will actually fail, redirecting error to null

View File

@@ -6,5 +6,8 @@
Install-ChocoPackage bazel
npm install -g @bazel/bazelisk
if ($LASTEXITCODE -ne 0) {
throw "Command 'npm install -g @bazel/bazelisk' failed"
}
Invoke-PesterTests -TestFile "Tools" -TestName "Bazel"

View File

@@ -7,20 +7,10 @@ Write-Host "Set TLS1.2"
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor "Tls12"
Write-Host "Install chocolatey"
$chocoExePath = 'C:\ProgramData\Chocolatey\bin'
# Add to system PATH
$systemPath = [Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::Machine)
$systemPath += ';' + $chocoExePath
[Environment]::SetEnvironmentVariable("PATH", $systemPath, [System.EnvironmentVariableTarget]::Machine)
# Update local process' path
$userPath = [Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::User)
if ($userPath) {
$env:Path = $systemPath + ";" + $userPath
} else {
$env:Path = $systemPath
}
Add-MachinePathItem 'C:\ProgramData\Chocolatey\bin'
Update-Environment
# Verify and run choco installer
$signatureThumbprint = "83AC7D88C66CB8680BCE802E0F0F5C179722764B"

View File

@@ -33,8 +33,7 @@ $regGoogleParameters = @(
$regGoogleParameters | ForEach-Object {
$Arguments = $_
if (-not ($Arguments.Path))
{
if (-not ($Arguments.Path)) {
$Arguments.Add("Path", $regGoogleUpdatePath)
}
$Arguments.Add("Force", $true)
@@ -44,15 +43,14 @@ $regGoogleParameters | ForEach-Object {
# Install Chrome WebDriver
Write-Host "Install Chrome WebDriver..."
$ChromeDriverPath = "$($env:SystemDrive)\SeleniumWebDrivers\ChromeDriver"
if (-not (Test-Path -Path $ChromeDriverPath))
{
if (-not (Test-Path -Path $ChromeDriverPath)) {
New-Item -Path $ChromeDriverPath -ItemType Directory -Force
}
Write-Host "Get the Chrome WebDriver download URL..."
$RegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths"
$ChromePath = (Get-ItemProperty "$RegistryPath\chrome.exe").'(default)'
[version]$ChromeVersion = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($ChromePath).ProductVersion
[version] $ChromeVersion = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($ChromePath).ProductVersion
$ChromeBuild = "$($ChromeVersion.Major).$($ChromeVersion.Minor).$($ChromeVersion.Build)"
$ChromeDriverVersionsUrl = "https://googlechromelabs.github.io/chrome-for-testing/latest-patch-versions-per-build-with-downloads.json"
@@ -63,7 +61,7 @@ $ChromeDriverVersion = $ChromeDriverVersions.builds.$ChromeBuild
if (-not ($ChromeDriverVersion)) {
$availableVersions = $ChromeDriverVersions.builds | Get-Member | Select-Object -ExpandProperty Name
Write-Host "Available chromedriver builds are $availableVersions"
Throw "Can't determine chromedriver version that matches chrome build $ChromeBuild"
throw "Can't determine chromedriver version that matches chrome build $ChromeBuild"
}
$ChromeDriverVersion.version | Out-File -FilePath "$ChromeDriverPath\versioninfo.txt" -Force;
@@ -79,10 +77,7 @@ Expand-7ZipArchive -Path $ChromeDriverArchPath -DestinationPath $ChromeDriverPat
Write-Host "Setting the environment variables..."
[Environment]::SetEnvironmentVariable("ChromeWebDriver", $ChromeDriverPath, "Machine")
$regEnvKey = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\'
$PathValue = Get-ItemPropertyValue -Path $regEnvKey -Name 'Path'
$PathValue += ";$ChromeDriverPath\"
Set-ItemProperty -Path $regEnvKey -Name 'Path' -Value $PathValue
Add-MachinePathItem $ChromeDriverPath
Update-Environment
Invoke-PesterTests -TestFile "Browsers" -TestName "Chrome"

View File

@@ -6,15 +6,16 @@
################################################################################
Write-Host "Get latest Moby release"
$mobyLatestReleaseVersion = (Invoke-RestMethod -Uri "https://api.github.com/repos/moby/moby/releases/latest").tag_name.Trim("v")
$mobyLatestVersion = (Get-GithubReleasesByVersion -Repo "moby/moby" -Version "latest").version
$dockerceUrl = "https://download.docker.com/win/static/stable/x86_64/"
$dockerceBinaries = Invoke-WebRequest -Uri $dockerceUrl -UseBasicParsing
Write-Host "Check Moby version $mobyLatestReleaseVersion"
$mobyRelease = $dockerceBinaries.Links.href -match "${mobyLatestReleaseVersion}\.zip" | Select-Object -Last 1
Write-Host "Check Moby version $mobyLatestVersion"
$mobyRelease = $dockerceBinaries.Links.href -match "${mobyLatestVersion}\.zip" | Select-Object -Last 1
if (-not $mobyRelease) {
Write-Host "Release not found for $mobyLatestRelease version"
$versions = [regex]::Matches($dockerceBinaries.Links.href, "docker-(\d+\.\d+\.\d+)\.zip") | Sort-Object { [version]$_.Groups[1].Value }
$versions = [regex]::Matches($dockerceBinaries.Links.href, "docker-(\d+\.\d+\.\d+)\.zip") | Sort-Object { [version] $_.Groups[1].Value }
$mobyRelease = $versions | Select-Object -ExpandProperty Value -Last 1
Write-Host "Found $mobyRelease"
}
@@ -47,8 +48,7 @@ foreach ($dockerImage in $dockerImages) {
docker pull $dockerImage
if (!$?) {
Write-Host "Docker pull failed with a non-zero exit code"
exit 1
throw "Docker pull failed with a non-zero exit code ($LastExitCode)"
}
}

View File

@@ -4,32 +4,19 @@
## Supply chain security: checksum validation
################################################################################
#region functions
function Get-DockerWincredHash {
Param (
[Parameter(Mandatory = $True)]
[string] $Release
)
$hashURL = "https://github.com/docker/docker-credential-helpers/releases/download/${Release}/checksums.txt"
(Invoke-RestMethod -Uri $hashURL).ToString().Split("`n").Where({ $_ -ilike "*docker-credential-wincred-${Release}.windows-amd64.exe*" }).Split(' ')[0]
}
#endregion
Write-Host "Install docker-wincred"
$dockerCredLatestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/docker/docker-credential-helpers/releases/latest"
$dockerCredDownloadUrl = $dockerCredLatestRelease.assets.browser_download_url -match "docker-credential-wincred-.+\.exe" | Select-Object -First 1
Invoke-DownloadWithRetry -Url $dockerCredDownloadUrl -Path "C:\Windows\System32\docker-credential-wincred.exe"
$downloadUrl = Resolve-GithubReleaseAssetUrl `
-Repo "docker/docker-credential-helpers" `
-Version "latest" `
-UrlMatchPattern "docker-credential-wincred-*amd64.exe"
$binaryPath = Invoke-DownloadWithRetry -Url $downloadUrl -Path "C:\Windows\System32\docker-credential-wincred.exe"
#region Supply chain security
$distributor_file_hash = Get-DockerWincredHash -Release $dockerCredLatestRelease.name
$local_file_hash = (Get-FileHash -Path 'C:\Windows\System32\docker-credential-wincred.exe' -Algorithm SHA256).Hash
if ($local_file_hash -ne $distributor_file_hash) {
Write-Host "hash must be equal to: ${distributor_file_hash}"
Write-Host "actual hash is: ${local_file_hash}"
throw 'Checksum verification failed, please rerun install'
}
$binaryName = Split-Path $downloadUrl -Leaf
$externalHash = Get-ChecksumFromUrl -Type "SHA256" `
-Url ($downloadUrl -replace $binaryName, "checksums.txt") `
-FileName $binaryName
Test-FileChecksum -Path $binaryPath -ExpectedSHA256Sum $externalHash
#endregion
Invoke-PesterTests -TestFile "Docker" -TestName "DockerWinCred"

View File

@@ -6,36 +6,40 @@
################################################################################
# Set environment variables
[System.Environment]::SetEnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0", "Machine")
[System.Environment]::SetEnvironmentVariable("DOTNET_NOLOGO", "1", "Machine")
[System.Environment]::SetEnvironmentVariable("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "1", "Machine")
[Environment]::SetEnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0", "Machine")
[Environment]::SetEnvironmentVariable("DOTNET_NOLOGO", "1", "Machine")
[Environment]::SetEnvironmentVariable("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "1", "Machine")
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor "Tls12"
#region "Functions"
function Get-SDKVersionsToInstall (
$DotnetVersion
) {
$metadataJsonUri = "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/${DotnetVersion}/releases.json"
$currentReleases = Invoke-DownloadWithRetry $metadataJsonUri | Get-Item | Get-Content | ConvertFrom-Json
function Get-SDKVersionsToInstall {
param (
[Parameter(Mandatory)]
[string] $DotnetVersion
)
$releasesJsonUri = "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/${DotnetVersion}/releases.json"
$releasesData = (Invoke-DownloadWithRetry $releasesJsonUri) | Get-Item | Get-Content | ConvertFrom-Json
# filtering out the preview/rc releases
$currentReleases = $currentReleases.'releases' | Where-Object { !$_.'release-version'.Contains('-') }
$releases = $releasesData.'releases' | Where-Object { !$_.'release-version'.Contains('-') }
$sdks = @()
foreach ($release in $currentReleases) {
foreach ($release in $releases) {
$sdks += $release.'sdk'
$sdks += $release.'sdks'
}
return $sdks.version `
| Sort-Object { [Version] $_ } -Unique `
| Group-Object { $_.Substring(0, $_.LastIndexOf('.') + 2) } `
| ForEach-Object { $_.Group[-1] }
| Sort-Object { [Version] $_ } -Unique `
| Group-Object { $_.Substring(0, $_.LastIndexOf('.') + 2) } `
| ForEach-Object { $_.Group[-1] }
}
function Invoke-Warmup (
$SdkVersion
) {
function Invoke-DotnetWarmup {
param (
[Parameter(Mandatory)]
[string] $SDKVersion
)
# warm up dotnet for first time experience
$projectTypes = @('console', 'mstest', 'web', 'mvc', 'webapi')
$projectTypes | ForEach-Object {
@@ -43,85 +47,76 @@ function Invoke-Warmup (
$projectPath = Join-Path -Path C:\temp -ChildPath $template
New-Item -Path $projectPath -Force -ItemType Directory
Push-Location -Path $projectPath
& $env:ProgramFiles\dotnet\dotnet.exe new globaljson --sdk-version "$sdkVersion"
& $env:ProgramFiles\dotnet\dotnet.exe new globaljson --sdk-version "$SDKVersion"
& $env:ProgramFiles\dotnet\dotnet.exe new $template
Pop-Location
Remove-Item $projectPath -Force -Recurse
}
}
function InstallSDKVersion (
$SdkVersion,
$dotnetVersion,
$Warmup
) {
if (!(Test-Path -Path "C:\Program Files\dotnet\sdk\$sdkVersion")) {
Write-Host "Installing dotnet $sdkVersion"
$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
.\dotnet-install.ps1 -Version $sdkVersion -InstallDir $(Join-Path -Path $env:ProgramFiles -ChildPath 'dotnet') -ZipPath $ZipPath -KeepZip
function Install-DotnetSDK {
param (
[Parameter(Mandatory)]
[string] $InstallScriptPath,
[Parameter(Mandatory)]
[Alias('Version')]
[string] $SDKVersion,
[Parameter(Mandatory)]
[string] $DotnetVersion
)
#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
Test-FileChecksum $ZipPath -ExpectedSHA512Sum $distributorFileHash
#endregion
} else {
Write-Host "Sdk version $sdkVersion already installed"
if (Test-Path -Path "C:\Program Files\dotnet\sdk\$SDKVersion") {
Write-Host "Sdk version $SDKVersion already installed"
return
}
if ($Warmup) {
Invoke-Warmup -SdkVersion $SdkVersion
}
Write-Host "Installing dotnet $SDKVersion"
$zipPath = Join-Path ([IO.Path]::GetTempPath()) ([IO.Path]::GetRandomFileName())
& $InstallScriptPath -Version $SDKVersion -InstallDir $(Join-Path -Path $env:ProgramFiles -ChildPath 'dotnet') -ZipPath $zipPath -KeepZip
#region Supply chain security
$releasesJsonUri = "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/${DotnetVersion}/releases.json"
$releasesData = (Invoke-DownloadWithRetry $releasesJsonUri) | Get-Item | Get-Content | ConvertFrom-Json
$distributorFileHash = $releasesData.releases.sdks.Where({ $_.version -eq $SDKVersion }).files.Where({ $_.name -eq 'dotnet-sdk-win-x64.zip' }).hash
Test-FileChecksum $zipPath -ExpectedSHA512Sum $distributorFileHash
#endregion
}
#endregion
function InstallAllValidSdks() {
# Consider all channels except preview/eol channels.
# Sort the channels in ascending order
$dotnetToolset = (Get-ToolsetContent).dotnet
$dotnetVersions = $dotnetToolset.versions
$warmup = $dotnetToolset.warmup
$dotnetToolset = (Get-ToolsetContent).dotnet
# Download installation script.
$installationName = "dotnet-install.ps1"
$installationUrl = "https://dot.net/v1/${installationName}"
Invoke-DownloadWithRetry -Url $installationUrl -Path ".\$installationName"
# Download installation script.
$installScriptPath = Invoke-DownloadWithRetry -Url "https://dot.net/v1/dotnet-install.ps1"
foreach ($dotnetVersion in $dotnetVersions) {
$sdkVersionsToInstall = Get-SDKVersionsToInstall -DotnetVersion $dotnetVersion
foreach ($sdkVersion in $sdkVersionsToInstall) {
InstallSDKVersion -SdkVersion $sdkVersion -DotnetVersion $dotnetVersion -Warmup $warmup
# Install and warm up dotnet
foreach ($dotnetVersion in $dotnetToolset.versions) {
$sdkVersionsToInstall = Get-SDKVersionsToInstall -DotnetVersion $dotnetVersion
foreach ($sdkVersion in $sdkVersionsToInstall) {
Install-DotnetSDK -InstallScriptPath $installScriptPath -SDKVersion $sdkVersion -DotnetVersion $dotnetVersion
if ($dotnetToolset.warmup) {
Invoke-DotnetWarmup -SDKVersion $sdkVersion
}
}
}
function InstallTools() {
$dotnetTools = (Get-ToolsetContent).dotnet.tools
# Add dotnet to PATH
Add-MachinePathItem "C:\Program Files\dotnet"
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
}
# Remove NuGet Folder
$nugetPath = "$env:APPDATA\NuGet"
if (Test-Path $nugetPath) {
Remove-Item -Path $nugetPath -Force -Recurse
}
function RunPostInstallationSteps() {
# Add dotnet to PATH
Add-MachinePathItem "C:\Program Files\dotnet"
# Generate and copy new NuGet.Config config
dotnet nuget list source | Out-Null
Copy-Item -Path $nugetPath -Destination C:\Users\Default\AppData\Roaming -Force -Recurse
# Remove NuGet Folder
$nugetPath = "$env:APPDATA\NuGet"
if (Test-Path $nugetPath) {
Remove-Item -Path $nugetPath -Force -Recurse
}
# Generate and copy new NuGet.Config config
dotnet nuget list source | Out-Null
Copy-Item -Path $nugetPath -Destination C:\Users\Default\AppData\Roaming -Force -Recurse
# Add %USERPROFILE%\.dotnet\tools to USER PATH
Add-DefaultPathItem "%USERPROFILE%\.dotnet\tools"
# Install dotnet tools
Write-Host "Installing dotnet tools"
Add-DefaultPathItem "%USERPROFILE%\.dotnet\tools"
foreach ($dotnetTool in $dotnetToolset.tools) {
dotnet tool install $($dotnetTool.name) --tool-path "C:\Users\Default\.dotnet\tools" --add-source https://api.nuget.org/v3/index.json | Out-Null
}
#endregion
InstallAllValidSdks
RunPostInstallationSteps
InstallTools
Invoke-PesterTests -TestFile "DotnetSDK"

View File

@@ -11,7 +11,10 @@ $VersionsManifest = Invoke-RestMethod "https://product-details.mozilla.org/1.0/f
Write-Host "Install Firefox browser..."
$installerUrl = "https://download.mozilla.org/?product=firefox-$($VersionsManifest.LATEST_FIREFOX_VERSION)&os=win64&lang=en-US"
$hashUrl = "https://archive.mozilla.org/pub/firefox/releases/$($VersionsManifest.LATEST_FIREFOX_VERSION)/SHA256SUMS"
$externalHash = (Invoke-RestMethod -Uri $hashURL).ToString().Split("`n").Where({ $_ -ilike "*win64/en-US/Firefox Setup*exe*" }).Split(' ')[0]
$externalHash = Get-ChecksumFromUrl -Type "SHA256" `
-Url $hashUrl `
-FileName "win64/en-US/Firefox Setup*exe"
Install-Binary -Type EXE `
-Url $installerUrl `
@@ -36,13 +39,14 @@ if (-not (Test-Path -Path $GeckoDriverPath)) {
}
Write-Host "Get the Gecko WebDriver version..."
$GeckoDriverJson = Invoke-RestMethod "https://api.github.com/repos/mozilla/geckodriver/releases/latest"
$GeckoDriverWindowsAsset = $GeckoDriverJson.assets | Where-Object { $_.name -Match "win64" } | Select-Object -First 1
$GeckoDriverVersion = $GeckoDriverJson.tag_name
$GeckoDriverVersion.Substring(1) | Out-File -FilePath "$GeckoDriverPath\versioninfo.txt" -Force;
$GeckoDriverVersion = (Get-GithubReleasesByVersion -Repo "mozilla/geckodriver" -Version "latest").version
$GeckoDriverVersion | Out-File -FilePath "$GeckoDriverPath\versioninfo.txt" -Force
Write-Host "Download Gecko WebDriver WebDriver..."
$GeckoDriverDownloadUrl = $GeckoDriverWindowsAsset.browser_download_url
$GeckoDriverDownloadUrl = Resolve-GithubReleaseAssetUrl `
-Repo "mozilla/geckodriver" `
-Version $GeckoDriverVersion `
-UrlMatchPattern "geckodriver-*-win64.zip"
$GeckoDriverArchPath = Invoke-DownloadWithRetry $GeckoDriverDownloadUrl
Write-Host "Expand Gecko WebDriver archive..."

View File

@@ -11,7 +11,7 @@ $downloadUrl = Resolve-GithubReleaseAssetUrl `
-Version "latest" `
-UrlMatchPattern "Git-*-64-bit.exe"
$externalHash = Get-GithubReleaseAssetHash `
$externalHash = Get-ChecksumFromGithubRelease `
-Repo "git-for-windows/git" `
-Version "latest" `
-FileName (Split-Path $downloadUrl -Leaf) `
@@ -37,7 +37,7 @@ Update-Environment
git config --system --add safe.directory "*"
# Disable GCM machine-wide
[Environment]::SetEnvironmentVariable("GCM_INTERACTIVE", "Never", [System.EnvironmentVariableTarget]::Machine)
[Environment]::SetEnvironmentVariable("GCM_INTERACTIVE", "Never", "Machine")
# Add to PATH
Add-MachinePathItem "C:\Program Files\Git\bin"

View File

@@ -6,16 +6,22 @@
Write-Host "Get the latest gh version..."
$repoUrl = "https://api.github.com/repos/cli/cli/releases/latest"
$assets = (Invoke-RestMethod -Uri $repoUrl).assets
$downloadUrl = ($assets.browser_download_url -match "windows_amd64.msi") | Select-Object -First 1
$downloadUrl = Resolve-GithubReleaseAssetUrl `
-Repo "cli/cli" `
-Version "latest" `
-UrlMatchPattern "gh_*_windows_amd64.msi"
$hashUrl = ($assets.browser_download_url -match "checksums.txt") | Select-Object -First 1
$externalHash = (Invoke-RestMethod -Uri $hashURL).ToString().Split("`n").Where({ $_ -ilike "*windows_amd64.msi*" }).Split(' ')[0]
$checksumsUrl = Resolve-GithubReleaseAssetUrl `
-Repo "cli/cli" `
-Version "latest" `
-UrlMatchPattern "gh_*_checksums.txt"
$externalHash = Get-ChecksumFromUrl -Type "SHA256" `
-Url $checksumsUrl `
-FileName (Split-Path $downloadUrl -Leaf)
Install-Binary `
-Url $downloadUrl `
-ExpectedSHA256Sum $externalHash
-Url $downloadUrl `
-ExpectedSHA256Sum $externalHash
Add-MachinePathItem "C:\Program Files (x86)\GitHub CLI"

View File

@@ -22,9 +22,9 @@ New-Item -Path "$ghcupPrefix\ghcup" -ItemType 'directory' -ErrorAction SilentlyC
New-Item -Path "$ghcupPrefix\ghcup\bin" -ItemType 'directory' -ErrorAction SilentlyContinue | Out-Null
Invoke-DownloadWithRetry -Url $ghcupDownloadURL -Path "$ghcupPrefix\ghcup\bin\ghcup.exe"
[System.Environment]::SetEnvironmentVariable("GHCUP_INSTALL_BASE_PREFIX", $ghcupPrefix, "Machine")
[System.Environment]::SetEnvironmentVariable("GHCUP_MSYS2", $msysPath, "Machine")
[System.Environment]::SetEnvironmentVariable("CABAL_DIR", $cabalDir, "Machine")
[Environment]::SetEnvironmentVariable("GHCUP_INSTALL_BASE_PREFIX", $ghcupPrefix, "Machine")
[Environment]::SetEnvironmentVariable("GHCUP_MSYS2", $msysPath, "Machine")
[Environment]::SetEnvironmentVariable("CABAL_DIR", $cabalDir, "Machine")
Add-MachinePathItem "$ghcupPrefix\ghcup\bin"
Add-MachinePathItem "$cabalDir\bin"
Update-Environment
@@ -32,12 +32,11 @@ Update-Environment
# Get 3 latest versions of GHC
$Versions = ghcup list -t ghc -r | Where-Object {$_ -notlike "prerelease"}
$VersionsOutput = [Version[]]($Versions | ForEach-Object{ $_.Split(' ')[1]; })
$LatestMajorMinor = $VersionsOutput | Group-Object { $_.ToString(2) } | Sort-Object { [Version]$_.Name } | Select-Object -last 3
$LatestMajorMinor = $VersionsOutput | Group-Object { $_.ToString(2) } | Sort-Object { [Version] $_.Name } | Select-Object -last 3
$VersionsList = $LatestMajorMinor | ForEach-Object { $_.Group | Select-Object -Last 1 } | Sort-Object
# The latest version will be installed as a default
ForEach ($version in $VersionsList)
{
foreach ($version in $VersionsList) {
Write-Host "Installing ghc $version..."
ghcup install ghc $version
ghcup set ghc $version

View File

@@ -15,7 +15,7 @@ $driverZipFile = Invoke-DownloadWithRetry $ieDriverUrl
$ieDriverPath = "C:\SeleniumWebDrivers\IEDriver"
if (-not (Test-Path -Path $ieDriverPath)) {
$null = New-Item -Path $ieDriverPath -ItemType Directory -Force
New-Item -Path $ieDriverPath -ItemType Directory -Force | Out-Null
}
Expand-7ZipArchive -Path $driverZipFile -DestinationPath $ieDriverPath

View File

@@ -39,7 +39,7 @@ function Set-JavaPath {
$newPath = $javaPath + '\bin;' + $newPath
Write-Host "Add $javaPath\bin to PATH"
[System.Environment]::SetEnvironmentVariable("PATH", $newPath, "Machine")
[Environment]::SetEnvironmentVariable("PATH", $newPath, "Machine")
Write-Host "Set JAVA_HOME environmental variable as $javaPath"
[Environment]::SetEnvironmentVariable("JAVA_HOME", $javaPath, "Machine")
@@ -118,13 +118,13 @@ 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] $m2Path = ([Environment]::GetEnvironmentVariable("PATH", "Machine")).Split(";") -match "maven"
$m2_repo = 'C:\ProgramData\m2'
New-Item -Path $m2_repo -ItemType Directory -Force | Out-Null
$m2RepoPath = 'C:\ProgramData\m2'
New-Item -Path $m2RepoPath -ItemType Directory -Force | Out-Null
[Environment]::SetEnvironmentVariable("M2", $m2, "Machine")
[Environment]::SetEnvironmentVariable("M2_REPO", $m2_repo, "Machine")
[Environment]::SetEnvironmentVariable("M2", $m2Path, "Machine")
[Environment]::SetEnvironmentVariable("M2_REPO", $m2RepoPath, "Machine")
[Environment]::SetEnvironmentVariable("MAVEN_OPTS", "-Xms256m", "Machine")
# Download cobertura jars

View File

@@ -14,7 +14,7 @@ $kotlinDownloadUrl = Resolve-GithubReleaseAssetUrl `
$kotlinArchivePath = Invoke-DownloadWithRetry $kotlinDownloadUrl
#region Supply chain security
$externalHash = Get-GithubReleaseAssetHash `
$externalHash = Get-ChecksumFromGithubRelease `
-Repo "JetBrains/kotlin" `
-Version "$kotlinVersion" `
-FileName (Split-Path $kotlinDownloadUrl -Leaf) `

View File

@@ -6,20 +6,24 @@
Write-Host "Install Kind"
# Choco installation can't be used because it depends on docker-desktop
$repoUrl = 'https://api.github.com/repos/kubernetes-sigs/kind/releases/latest'
$assets = (Invoke-RestMethod -Uri $repoUrl).assets
[System.String] $kindDownloadLink = $assets.browser_download_url -match "kind-windows-amd64$"
$destFilePath = "C:\ProgramData\kind"
$null = New-Item -Path $destFilePath -ItemType Directory -Force
$packagePath = Invoke-DownloadWithRetry -Url $kindDownloadLink -Path "$destFilePath\kind.exe"
$targetDir = "C:\ProgramData\kind"
New-Item -Path $targetDir -ItemType Directory -Force | Out-Null
$downloadUrl = Resolve-GithubReleaseAssetUrl `
-Repo "kubernetes-sigs/kind" `
-Version "latest" `
-UrlMatchPattern "kind-windows-amd64"
$packagePath = Invoke-DownloadWithRetry -Url $downloadUrl -Path "$targetDir\kind.exe"
#region Supply chain security - Kind
$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]
$externalHash = Get-ChecksumFromUrl -Type "SHA256" `
-Url "$downloadUrl.sha256sum" `
-FileName (Split-Path $downloadUrl -Leaf)
Test-FileChecksum $packagePath -ExpectedSHA256Sum $externalHash
#endregion
Add-MachinePathItem $destFilePath
Add-MachinePathItem $targetDir
Write-Host "Install Kubectl"
Install-ChocoPackage kubernetes-cli

View File

@@ -4,67 +4,67 @@
################################################################################
if (Test-IsWin19) {
# If Windows 2019, install version 8.1.0 form sourceforge
$baseUrl = "https://sourceforge.net/projects/mingw-w64/files"
# If Windows 2019, install version 8.1.0 form sourceforge
$baseUrl = "https://sourceforge.net/projects/mingw-w64/files"
$("mingw32", "mingw64") | ForEach-Object {
if ($_ -eq "mingw32") {
$url = "$baseUrl/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/8.1.0/threads-posix/dwarf/i686-8.1.0-release-posix-dwarf-rt_v6-rev0.7z/download"
$sha256sum = 'adb84b70094c0225dd30187ff995e311d19424b1eb8f60934c60e4903297f946'
} elseif ($_ -eq "mingw64") {
$url = "$baseUrl/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/8.1.0/threads-posix/seh/x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z/download"
$sha256sum = '853970527b5de4a55ec8ca4d3fd732c00ae1c69974cc930c82604396d43e79f8'
} else {
throw "Unknown architecture $_"
$("mingw32", "mingw64") | ForEach-Object {
if ($_ -eq "mingw32") {
$url = "$baseUrl/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/8.1.0/threads-posix/dwarf/i686-8.1.0-release-posix-dwarf-rt_v6-rev0.7z/download"
$sha256sum = 'adb84b70094c0225dd30187ff995e311d19424b1eb8f60934c60e4903297f946'
} elseif ($_ -eq "mingw64") {
$url = "$baseUrl/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/8.1.0/threads-posix/seh/x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z/download"
$sha256sum = '853970527b5de4a55ec8ca4d3fd732c00ae1c69974cc930c82604396d43e79f8'
} else {
throw "Unknown architecture $_"
}
$packagePath = Invoke-DownloadWithRetry $url
Test-FileChecksum -Path $packagePath -ExpectedSHA256Sum $sha256sum
Expand-7ZipArchive -Path $packagePath -DestinationPath "C:\"
# Make a copy of mingw-make.exe to make.exe, which is a more discoverable name
# and so the same command line can be used on Windows as on macOS and Linux
$path = "C:\$_\bin\mingw32-make.exe" | Get-Item
Copy-Item -Path $path -Destination (Join-Path $path.Directory 'make.exe')
}
Add-MachinePathItem "C:\mingw64\bin"
}
if (Test-IsWin22) {
# If Windows 2022, install version specified in the toolset
$version = (Get-ToolsetContent).mingw.version
$runtime = (Get-ToolsetContent).mingw.runtime
$("mingw32", "mingw64") | ForEach-Object {
if ($_ -eq "mingw32") {
$arch = "i686"
$threads = "posix"
$exceptions = "dwarf"
} elseif ($_ -eq "mingw64") {
$arch = "x86_64"
$threads = "posix"
$exceptions = "seh"
} else {
throw "Unknown architecture $_"
}
$url = Resolve-GithubReleaseAssetUrl `
-Repo "niXman/mingw-builds-binaries" `
-Version "$version" `
-Asset "$arch-*-release-$threads-$exceptions-$runtime-*.7z"
$packagePath = Invoke-DownloadWithRetry $url
Expand-7ZipArchive -Path $packagePath -DestinationPath "C:\"
# Make a copy of mingw-make.exe to make.exe, which is a more discoverable name
# and so the same command line can be used on Windows as on macOS and Linux
$path = "C:\$_\bin\mingw32-make.exe" | Get-Item
Copy-Item -Path $path -Destination (Join-Path $path.Directory 'make.exe')
}
$packagePath = Invoke-DownloadWithRetry $url
$hash = Get-FileHash -Path $packagePath -Algorithm SHA256
if ($hash.Hash -ne $sha256sum) {
throw "Checksum verification failed for $packagePath"
}
Expand-7ZipArchive -Path $packagePath -DestinationPath "C:\"
# Make a copy of mingw-make.exe to make.exe, which is a more discoverable name
# and so the same command line can be used on Windows as on macOS and Linux
$path = "C:\$_\bin\mingw32-make.exe" | Get-Item
Copy-Item -Path $path -Destination (Join-Path $path.Directory 'make.exe')
}
Add-MachinePathItem "C:\mingw64\bin"
} else {
$version = (Get-ToolsetContent).mingw.version
$runtime = (Get-ToolsetContent).mingw.runtime
$("mingw32", "mingw64") | ForEach-Object {
if ($_ -eq "mingw32") {
$arch = "i686"
$threads = "posix"
$exceptions = "dwarf"
} elseif ($_ -eq "mingw64") {
$arch = "x86_64"
$threads = "posix"
$exceptions = "seh"
} else {
throw "Unknown architecture $_"
}
$url = Resolve-GithubReleaseAssetUrl `
-Repo "niXman/mingw-builds-binaries" `
-Version "$version" `
-Asset "$arch-*-release-$threads-$exceptions-$runtime-*.7z"
$packagePath = Invoke-DownloadWithRetry $url
Expand-7ZipArchive -Path $packagePath -DestinationPath "C:\"
# Make a copy of mingw-make.exe to make.exe, which is a more discoverable name
# and so the same command line can be used on Windows as on macOS and Linux
$path = "C:\$_\bin\mingw32-make.exe" | Get-Item
Copy-Item -Path $path -Destination (Join-Path $path.Directory 'make.exe')
}
Add-MachinePathItem "C:\mingw64\bin"
Add-MachinePathItem "C:\mingw64\bin"
}
Invoke-PesterTests -TestFile "Tools" -TestName "Mingw64"

View File

@@ -27,6 +27,6 @@ Install-Binary `
-InstallArgs @("/S", "/AddToPath=0", "/RegisterPython=0", "/D=$CondaDestination") `
-ExpectedSHA256Sum $distributorFileHash
[System.Environment]::SetEnvironmentVariable("CONDA", $CondaDestination, "Machine")
[Environment]::SetEnvironmentVariable("CONDA", $CondaDestination, "Machine")
Invoke-PesterTests -TestFile "Miniconda"

View File

@@ -6,24 +6,24 @@
# Install mongodb package
$toolsetVersion = (Get-ToolsetContent).mongodb.version
$getMongoReleases = Invoke-WebRequest -Uri "mongodb.com/docs/manual/release-notes/$toolsetVersion/" -UseBasicParsing
$getMongoReleases = Invoke-WebRequest -Uri "mongodb.com/docs/manual/release-notes/$toolsetVersion/" -UseBasicParsing
$TargetReleases = $getMongoReleases.Links.href | Where-Object {$_ -like "#$toolsetVersion*---*"}
$MinorVersions = @()
foreach ($release in $TargetReleases) {
if ($release -notlike "*upcoming*") {
$pattern = '\d+\.\d+\.\d+'
$version = $release | Select-String -Pattern $pattern -AllMatches | ForEach-Object { $_.Matches } | ForEach-Object { $_.Value }
$MinorVersions += $version
$pattern = '\d+\.\d+\.\d+'
$version = $release | Select-String -Pattern $pattern -AllMatches | ForEach-Object { $_.Matches } | ForEach-Object { $_.Value }
$MinorVersions += $version
}
}
}
$LatestVersion = $MinorVersions[0]
Install-Binary `
-Url "https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-$LatestVersion-signed.msi" `
-ExtraInstallArgs @('TARGETDIR=C:\PROGRA~1\MongoDB ADDLOCAL=ALL') `
-ExpectedSignature (Get-ToolsetContent).mongodb.signature
-Url "https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-$LatestVersion-signed.msi" `
-ExtraInstallArgs @('TARGETDIR=C:\PROGRA~1\MongoDB ADDLOCAL=ALL') `
-ExpectedSignature (Get-ToolsetContent).mongodb.signature
# Add mongodb to the PATH
$mongoPath = (Get-CimInstance Win32_Service -Filter "Name LIKE 'mongodb'").PathName

View File

@@ -11,25 +11,27 @@ $dash = "-" * 40
$origPath = $env:PATH
function Install-Msys2 {
$msys2_release = "https://api.github.com/repos/msys2/msys2-installer/releases/latest"
$assets = (Invoke-RestMethod -Uri $msys2_release).assets
$msys2Uri = ($assets | Where-Object { $_.name -match "^msys2-x86_64" -and $_.name.EndsWith(".exe") }).browser_download_url
# We can't use Resolve-GithubReleaseAssetUrl function here
# because msys2-installer releases don't have a consistent versioning scheme
$assets = (Invoke-RestMethod -Uri "https://api.github.com/repos/msys2/msys2-installer/releases/latest").assets
$downloadUri = ($assets | Where-Object { $_.name -match "^msys2-x86_64" -and $_.name.EndsWith(".exe") }).browser_download_url
$installerName = Split-Path $downloadUri -Leaf
# Download the latest msys2 x86_64, filename includes release date
Write-Host "Starting msys2 download using $($msys2Uri.split('/')[-1])"
$msys2File = Invoke-DownloadWithRetry $msys2Uri
Write-Host "Finished download"
Write-Host "Download msys2 installer $installerName"
$installerPath = Invoke-DownloadWithRetry $downloadUri
#region Supply chain security - Kind
$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]
Test-FileChecksum $msys2File -ExpectedSHA256Sum $externalHash
#region Supply chain security - MSYS2
$externalHash = Get-ChecksumFromUrl -Type "SHA256" `
-Url ($downloadUri -replace $installerName, "msys2-checksums.txt") `
-FileName $installerName
Test-FileChecksum $installerPath -ExpectedSHA256Sum $externalHash
#endregion
# extract tar.xz to C:\
Write-Host "Starting msys2 installation"
& $msys2File in --confirm-command --accept-messages --root C:/msys64
Remove-Item $msys2File
& $installerPath in --confirm-command --accept-messages --root C:/msys64
Remove-Item $installerPath
}
function Install-Msys2Packages($Packages) {

View File

@@ -10,12 +10,14 @@ Install-Binary `
-ExpectedSignature '3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC'
# Downloading mysql
[version]$MysqlVersion = (Get-ToolsetContent).mysql.version
[version] $MysqlVersion = (Get-ToolsetContent).mysql.version
$MysqlVersionMajorMinor = $MysqlVersion.ToString(2)
if ($MysqlVersion.Build -lt 0) {
$MysqlVersion = (Invoke-RestMethod -Uri "https://dev.mysql.com/downloads/mysql/${MysqlVersionMajorMinor}.html" -Headers @{ 'User-Agent' = 'curl/8.4.0' } |
Select-String -Pattern "${MysqlVersionMajorMinor}\.\d+").Matches.Value
$downloadsPageUrl = "https://dev.mysql.com/downloads/mysql/${MysqlVersionMajorMinor}.html"
$MysqlVersion = Invoke-RestMethod -Uri $downloadsPageUrl -Headers @{ 'User-Agent' = 'curl/8.4.0' } `
| Select-String -Pattern "${MysqlVersionMajorMinor}\.\d+" `
| ForEach-Object { $_.Matches.Value }
}
$MysqlVersionFull = $MysqlVersion.ToString()

View File

@@ -10,8 +10,8 @@ $env:PIPX_HOME = "${env:ProgramFiles(x86)}\pipx"
pip install pipx
Add-MachinePathItem "${env:PIPX_BIN_DIR}"
[System.Environment]::SetEnvironmentVariable("PIPX_BIN_DIR", $env:PIPX_BIN_DIR, "Machine")
[System.Environment]::SetEnvironmentVariable("PIPX_HOME", $env:PIPX_HOME, "Machine")
[Environment]::SetEnvironmentVariable("PIPX_BIN_DIR", $env:PIPX_BIN_DIR, "Machine")
[Environment]::SetEnvironmentVariable("PIPX_HOME", $env:PIPX_HOME, "Machine")
Invoke-PesterTests -TestFile "Tools" -TestName "Pipx"

View File

@@ -3,20 +3,20 @@ $pgUser = "postgres"
$pgPwd = "root"
# Prepare environment variable for validation
[System.Environment]::SetEnvironmentVariable("PGUSER", $pgUser, "Machine")
[System.Environment]::SetEnvironmentVariable("PGPASSWORD", $pgPwd, "Machine")
[Environment]::SetEnvironmentVariable("PGUSER", $pgUser, "Machine")
[Environment]::SetEnvironmentVariable("PGPASSWORD", $pgPwd, "Machine")
# Define latest available version to install based on version specified in the toolset
$toolsetVersion = (Get-ToolsetContent).postgresql.version
$getPostgreReleases = Invoke-WebRequest -Uri "https://git.postgresql.org/gitweb/?p=postgresql.git;a=tags" -UseBasicParsing
# Getting all links matched to the pattern (e.g.a=log;h=refs/tags/REL_14)
$TargetReleases = $getPostgreReleases.Links.href | Where-Object { $_ -match "a=log;h=refs/tags/REL_$toolsetVersion" }
[Int32]$OutNumber = $null
[Int32] $OutNumber = $null
$MinorVersions = @()
foreach ($release in $TargetReleases) {
$version = $release.split('/')[-1]
# Checking if the latest symbol of the release version is actually a number. If yes, add to $MinorVersions array
if ([Int32]::TryParse($($version.Split('_')[-1]), [ref]$OutNumber)) {
if ([Int32]::TryParse($($version.Split('_')[-1]), [ref] $OutNumber)) {
$MinorVersions += $OutNumber
}
}
@@ -72,9 +72,9 @@ if ($exitCode -ne 0) {
}
# Added PostgreSQL environment variable
[System.Environment]::SetEnvironmentVariable("PGBIN", $pgBin, "Machine")
[System.Environment]::SetEnvironmentVariable("PGROOT", $pgRoot, "Machine")
[System.Environment]::SetEnvironmentVariable("PGDATA", $pgData, "Machine")
[Environment]::SetEnvironmentVariable("PGBIN", $pgBin, "Machine")
[Environment]::SetEnvironmentVariable("PGROOT", $pgRoot, "Machine")
[Environment]::SetEnvironmentVariable("PGDATA", $pgData, "Machine")
# Stop and disable PostgreSQL service
$pgService = Get-Service -Name postgresql*

View File

@@ -9,22 +9,18 @@
# Install PowerShell modules
$modules = (Get-ToolsetContent).powershellModules
foreach($module in $modules)
{
foreach ($module in $modules) {
$moduleName = $module.name
Write-Host "Installing ${moduleName} module"
if ($module.versions)
{
foreach ($version in $module.versions)
{
if ($module.versions) {
foreach ($version in $module.versions) {
Write-Host " - $version"
Install-Module -Name $moduleName -RequiredVersion $version -Scope AllUsers -SkipPublisherCheck -Force
}
continue
} else {
Install-Module -Name $moduleName -Scope AllUsers -SkipPublisherCheck -Force
}
Install-Module -Name $moduleName -Scope AllUsers -SkipPublisherCheck -Force
}
Import-Module Pester

View File

@@ -16,10 +16,11 @@ try {
$release = $metadata.LTSReleaseTag[0] -replace '^v'
$downloadUrl = "https://github.com/PowerShell/PowerShell/releases/download/v${release}/PowerShell-${release}-win-x64.msi"
$hashUrl = "https://github.com/PowerShell/PowerShell/releases/download/v${release}/hashes.sha256"
$expectedSHA256Sum = (Invoke-RestMethod -Uri $hashURL).ToString().Split("`n").Where({ $_ -ilike "*PowerShell-${Release}-win-x64.msi*" }).Split(' ')[0]
Install-Binary -Url $downloadUrl -ExpectedSHA256Sum $expectedSHA256Sum
$installerName = Split-Path $downloadUrl -Leaf
$externalHash = Get-ChecksumFromUrl -Type "SHA256" `
-Url ($downloadUrl -replace $installerName, "hashes.sha256") `
-FileName $installerName
Install-Binary -Url $downloadUrl -ExpectedSHA256Sum $externalHash
} finally {
# Restore original value
[Net.ServicePointManager]::SecurityProtocol = $originalValue
@@ -30,6 +31,6 @@ try {
# While the update check happens during the first session in a given 24-hour period, for performance reasons,
# the notification will only be shown on the start of subsequent sessions.
# Also for performance reasons, the check will not start until at least 3 seconds after the session begins.
[System.Environment]::SetEnvironmentVariable("POWERSHELL_UPDATECHECK", "Off", [System.EnvironmentVariableTarget]::Machine)
[Environment]::SetEnvironmentVariable("POWERSHELL_UPDATECHECK", "Off", "Machine")
Invoke-PesterTests -TestFile "Tools" -TestName "PowerShell Core"

View File

@@ -33,7 +33,7 @@ function Get-CertificatesWithoutPropId {
$certs | ForEach-Object -Process {
$certHandle = $_.Handle
$isPropertySet = [PKI.Cert]::CertGetCertificateContextProperty(
$certHandle, $CERT_NOT_BEFORE_FILETIME_PROP_ID, $null, [ref]$null
$certHandle, $CERT_NOT_BEFORE_FILETIME_PROP_ID, $null, [ref] $null
)
if (-not $isPropertySet) {
Write-Host "Subject: $($_.Subject)"
@@ -43,31 +43,17 @@ function Get-CertificatesWithoutPropId {
$certsWithoutPropId
}
function Invoke-WithRetry {
<#
.SYNOPSIS
Runs $command block until $BreakCondition or $RetryCount is reached.
#>
param([ScriptBlock]$Command, [ScriptBlock] $BreakCondition, [int] $RetryCount=5, [int] $Sleep=10)
$c = 0
while($c -lt $RetryCount){
$result = & $Command
if(& $BreakCondition){
break
}
Start-Sleep $Sleep
$c++
}
$result
}
function Import-SSTFromWU {
# Serialized Certificate Store File
$sstFile = "$env:TEMP\roots.sst"
# Generate SST from Windows Update
$result = Invoke-WithRetry { certutil.exe -generateSSTFromWU $sstFile } {$LASTEXITCODE -eq 0}
$result = Invoke-ScriptBlockWithRetry -RetryCount 5 -RetryIntervalSeconds 10 -Command {
$r = certutil.exe -generateSSTFromWU $sstFile
if ($LASTEXITCODE -ne 0) {
throw "failed to generate $sstFile sst file`n$o"
}
return $r
}
if ($LASTEXITCODE -ne 0) {
Write-Host "[Error]: failed to generate $sstFile sst file`n$result"
exit $LASTEXITCODE
@@ -88,7 +74,9 @@ function Import-SSTFromWU {
}
function Clear-CertificatesPropId {
param([hashtable]$CertsWithoutPropId)
param(
[hashtable] $CertsWithoutPropId
)
# List installed certificates
$certs = Get-ChildItem -Path Cert:\LocalMachine\Root

View File

@@ -3,39 +3,12 @@
## Desc: Install Ruby using the RubyInstaller2 package and set the default Ruby version
################################################################################
function Get-RubyVersions {
param (
[System.String] $Arch = "x64",
[System.String] $Extension = "7z",
[System.String] $ReleasesAmount = "50"
)
$uri = "https://api.github.com/repos/oneclick/rubyinstaller2/releases?per_page=$ReleasesAmount"
try {
$versionLists = @{}
$assets = (Invoke-RestMethod -Uri $uri).Where{ -not $_.prerelease }.assets
$7zArchives = $assets.Where{ $_.name.EndsWith("$Arch.$Extension") }
$majorMinorGroups = $7zArchives | Group-Object { $_.name.Replace("rubyinstaller-", "").Substring(0, 3) }
foreach ($majorMinorGroup in $majorMinorGroups) {
$group = $majorMinorGroup.Group
$sortVersions = $group | Sort-Object { [Version]$_.name.Replace("rubyinstaller-", "").Replace("-$Arch.$Extension", "").Replace("-", ".") }
$latestVersion = $sortVersions | Select-Object -Last 1
$versionLists[$majorMinorGroup.Name] = $latestVersion.browser_download_url
}
return $versionLists
} catch {
Write-Host "Unable to send request to the '$uri'. Error: '$_'"
exit 1
}
}
# Most of this logic is from
# https://github.com/ruby/setup-ruby/blob/master/windows.js
function Install-Ruby {
param(
[String]$PackagePath,
[String]$Architecture = "x64"
[String] $PackagePath,
[String] $Architecture = "x64"
)
# Create Ruby toolcache folder
@@ -44,47 +17,46 @@ function Install-Ruby {
Write-Host "Creating Ruby toolcache folder"
New-Item -ItemType Directory -Path $rubyToolcachePath | Out-Null
}
# Expand archive with binaries
$packageName = [IO.Path]::GetFileNameWithoutExtension((Split-Path -Path $PackagePath -Leaf))
Write-Host "Expanding Ruby archive $packageName"
$tempFolder = Join-Path -Path $rubyToolcachePath -ChildPath $packageName
Expand-7ZipArchive -Path $PackagePath -DestinationPath $rubyToolcachePath
# Get Ruby version from binaries
$rubyVersion = & "$tempFolder\bin\ruby.exe" -e "print RUBY_VERSION"
if ($rubyVersion) {
Write-Host "Installing Ruby $rubyVersion"
$rubyVersionPath = Join-Path -Path $rubyToolcachePath -ChildPath $rubyVersion
$rubyArchPath = Join-Path -Path $rubyVersionPath -ChildPath $Architecture
Write-Host "Creating Ruby '${rubyVersion}' folder in '${rubyVersionPath}'"
New-Item -ItemType Directory -Path $rubyVersionPath -Force | Out-Null
Write-Host "Moving Ruby '${rubyVersion}' files to '${rubyArchPath}'"
Invoke-ScriptBlockWithRetry -Command {
Move-Item -Path $tempFolder -Destination $rubyArchPath -ErrorAction Stop | Out-Null
}
Write-Host "Removing Ruby '${rubyVersion}' documentation '${rubyArchPath}\share\doc' folder"
Remove-Item -Path "${rubyArchPath}\share\doc" -Force -Recurse -ErrorAction Ignore
Write-Host "Creating complete file"
New-Item -ItemType File -Path $rubyVersionPath -Name "$Architecture.complete" | Out-Null
} else {
Write-Host "Ruby application is not found. Failed to expand '$PackagePath' archive"
exit 1
if (($LASTEXITCODE -ne 0) -or (-not $rubyVersion)) {
throw "Unable to determine Ruby version. Exit code: $LASTEXITCODE, output: '$rubyVersion'"
}
Write-Host "Ruby version is $rubyVersion"
$rubyVersionPath = Join-Path -Path $rubyToolcachePath -ChildPath $rubyVersion
$rubyArchPath = Join-Path -Path $rubyVersionPath -ChildPath $Architecture
Write-Host "Creating Ruby '${rubyVersion}' folder in '${rubyVersionPath}'"
New-Item -ItemType Directory -Path $rubyVersionPath -Force | Out-Null
Write-Host "Moving Ruby '${rubyVersion}' files to '${rubyArchPath}'"
Invoke-ScriptBlockWithRetry -Command {
Move-Item -Path $tempFolder -Destination $rubyArchPath -ErrorAction Stop | Out-Null
}
Write-Host "Removing Ruby '${rubyVersion}' documentation '${rubyArchPath}\share\doc' folder"
Remove-Item -Path "${rubyArchPath}\share\doc" -Force -Recurse -ErrorAction Ignore
Write-Host "Creating complete file for Ruby $rubyVersion $Architecture"
New-Item -ItemType File -Path $rubyVersionPath -Name "$Architecture.complete" | Out-Null
}
function Set-DefaultRubyVersion {
param(
[Parameter(Mandatory = $true)]
[System.Version] $Version,
[System.String] $Arch = "x64"
[version] $Version,
[Alias("Arch")]
[string] $Architecture = "x64"
)
$rubyPath = Join-Path $env:AGENT_TOOLSDIRECTORY "/Ruby/${Version}*/${Arch}/bin"
$rubyPath = Join-Path $env:AGENT_TOOLSDIRECTORY "/Ruby/${Version}*/${Architecture}/bin"
$rubyDir = (Get-Item -Path $rubyPath).FullName
Write-Host "Use Ruby ${Version} as a system Ruby"
@@ -95,21 +67,15 @@ function Set-DefaultRubyVersion {
$rubyTools = (Get-ToolsetContent).toolcache | Where-Object { $_.name -eq "Ruby" }
$rubyToolVersions = $rubyTools.versions
# Get Ruby versions from the repo
$rubyLatestMajorVersions = Get-RubyVersions
Write-Host "Starting installation Ruby..."
foreach ($rubyVersion in $rubyToolVersions) {
Write-Host "Starting Ruby $rubyVersion installation"
# Get url for the latest major Ruby version
$url = $rubyLatestMajorVersions[$rubyVersion]
if ($url) {
$tempRubyPackagePath = Invoke-DownloadWithRetry $url
Install-Ruby -PackagePath $tempRubyPackagePath
} else {
Write-Host "Url not found for the '$rubyVersion' version"
exit 1
}
$downloadUrl = Resolve-GithubReleaseAssetUrl `
-Repo "oneclick/rubyinstaller2" `
-Version "$rubyVersion*" `
-UrlMatchPattern "*-x64.7z"
$packagePath = Invoke-DownloadWithRetry $downloadUrl
Install-Ruby -PackagePath $packagePath
}
Set-DefaultRubyVersion -Version $rubyTools.default -Arch $rubyTools.arch

View File

@@ -5,10 +5,11 @@
################################################################################
Write-Host "Download latest Runner for GitHub Actions"
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/actions/runner/releases/latest"
$version = $release.tag_name.Trim("v")
$downloadUrl = ($release.assets.browser_download_url -ilike "*actions-runner-win-x64-${version}.zip*") | Select-Object -First 1
$fileName = [System.IO.Path]::GetFileName($downloadUrl)
$downloadUrl = Resolve-GithubReleaseAssetUrl `
-Repo "actions/runner" `
-Version "latest" `
-UrlMatchPattern "actions-runner-win-x64-*[0-9.].zip"
$fileName = Split-Path $downloadUrl -Leaf
New-Item -Path "C:\ProgramData\runner" -ItemType Directory
Invoke-DownloadWithRetry -Url $downloadUrl -Path "C:\ProgramData\runner\$fileName"

View File

@@ -14,7 +14,7 @@ $rustupPath = Invoke-DownloadWithRetry "https://static.rust-lang.org/rustup/dist
#region Supply chain security
$distributorFileHash = (Invoke-RestMethod -Uri 'https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe.sha256').Trim()
Test-FileChecksum (Join-Path ${env:TEMP} 'rustup-init.exe') -ExpectedSHA256Sum $distributorFileHash
Test-FileChecksum $rustupPath -ExpectedSHA256Sum $distributorFileHash
#endregion
# Install Rust by running rustup-init.exe (disabling the confirmation prompt with -y)

View File

@@ -8,13 +8,13 @@ $signatureThumbrint = "9ACA9419E53D3C9E56396DD2335FF683A8B0B8F3"
# install required MSIs
Install-Binary `
-Url "${baseUrl}/SQLSysClrTypes.msi" `
-ExpectedSignature $signatureThumbrint
-Url "${baseUrl}/SQLSysClrTypes.msi" `
-ExpectedSignature $signatureThumbrint
Install-Binary `
-Url "${baseUrl}/SharedManagementObjects.msi" `
-ExpectedSignature $signatureThumbrint
-Url "${baseUrl}/SharedManagementObjects.msi" `
-ExpectedSignature $signatureThumbrint
Install-Binary `
-Url "${baseUrl}/PowerShellTools.msi" `
-ExpectedSignature $signatureThumbrint
-Url "${baseUrl}/PowerShellTools.msi" `
-ExpectedSignature $signatureThumbrint

View File

@@ -14,13 +14,13 @@ $urlBase = "https://download.microsoft.com/download/b/8/a/b8a2fb98-0ec1-41e5-be9
# Install Service Fabric Runtime for Windows
Install-Binary `
-Url "${urlBase}/MicrosoftServiceFabric.${runtimeVersion}.exe" `
-InstallArgs @("/accepteula ", "/quiet", "/force") `
-ExpectedSignature (Get-ToolsetContent).serviceFabric.runtime.signature
-Url "${urlBase}/MicrosoftServiceFabric.${runtimeVersion}.exe" `
-InstallArgs @("/accepteula ", "/quiet", "/force") `
-ExpectedSignature (Get-ToolsetContent).serviceFabric.runtime.signature
# Install Service Fabric SDK
Install-Binary `
-Url "${urlBase}/MicrosoftServiceFabricSDK.${sdkVersion}.msi" `
-ExpectedSignature (Get-ToolsetContent).serviceFabric.sdk.signature
-Url "${urlBase}/MicrosoftServiceFabricSDK.${sdkVersion}.msi" `
-ExpectedSignature (Get-ToolsetContent).serviceFabric.sdk.signature
Invoke-PesterTests -TestFile "Tools" -TestName "ServiceFabricSDK"

View File

@@ -5,19 +5,23 @@
################################################################################
Write-Host "Get the latest Stack version..."
$StackReleasesJson = Invoke-RestMethod "https://api.github.com/repos/commercialhaskell/stack/releases/latest"
$Version = $StackReleasesJson.name.TrimStart("v")
$DownloadFilePattern = "windows-x86_64.zip"
$DownloadUrl = $StackReleasesJson.assets | Where-Object { $_.name.EndsWith($DownloadFilePattern) } | Select-Object -ExpandProperty "browser_download_url" -First 1
$version = (Get-GithubReleasesByVersion -Repo "commercialhaskell/stack" -Version "latest" -WithAssetsOnly).version
$downloadUrl = Resolve-GithubReleaseAssetUrl `
-Repo "commercialhaskell/stack" `
-Version $version `
-UrlMatchPattern "stack-*-windows-x86_64.zip"
Write-Host "Download stack archive"
$StackToolcachePath = Join-Path $Env:AGENT_TOOLSDIRECTORY "stack\$Version"
$StackToolcachePath = Join-Path $Env:AGENT_TOOLSDIRECTORY "stack\$version"
$DestinationPath = Join-Path $StackToolcachePath "x64"
$StackArchivePath = Invoke-DownloadWithRetry $DownloadUrl
$StackArchivePath = Invoke-DownloadWithRetry $downloadUrl
#region Supply chain security - Stack
$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]
$externalHash = Get-ChecksumFromUrl -Type "SHA256" `
-Url "$downloadUrl.sha256" `
-FileName (Split-Path $downloadUrl -Leaf)
Test-FileChecksum $StackArchivePath -ExpectedSHA256Sum $externalHash
#endregion

View File

@@ -51,12 +51,11 @@ foreach ($tool in $tools) {
| Where-Object { ($_.platform -eq $tool.platform) -and ($_.arch -eq $tool.arch) -and ($_.toolset -eq $tool.toolset) } `
| Select-Object -First 1
Write-Host "Installing $($tool.name) $toolVersion $($tool.arch)..."
if ($null -ne $asset) {
Install-Asset -ReleaseAsset $asset
} else {
Write-Host "Asset was not found in versions manifest"
exit 1
if (-not $asset) {
throw "Asset for $($tool.name) $toolVersion $($tool.arch) not found in versions manifest"
}
Write-Host "Installing $($tool.name) $toolVersion $($tool.arch)..."
Install-Asset -ReleaseAsset $asset
}
}

View File

@@ -8,13 +8,13 @@ $argumentList = ("/install", "/quiet", "/norestart")
$signatureThumbrint = "ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B"
Install-Binary `
-Url "${baseUrl}/vcredist_x86.exe" `
-InstallArgs $argumentList `
-ExpectedSignature $signatureThumbrint
-Url "${baseUrl}/vcredist_x86.exe" `
-InstallArgs $argumentList `
-ExpectedSignature $signatureThumbrint
Install-Binary `
-Url "${baseUrl}/vcredist_x64.exe" `
-InstallArgs $argumentList `
-ExpectedSignature $signatureThumbrint
-Url "${baseUrl}/vcredist_x64.exe" `
-InstallArgs $argumentList `
-ExpectedSignature $signatureThumbrint
Invoke-PesterTests -TestFile "Tools" -TestName "VCRedist"

View File

@@ -3,16 +3,16 @@
## Desc: Install Visual Studio
################################################################################
$toolset = Get-ToolsetContent
$vsToolset = (Get-ToolsetContent).visualStudio
# Install VS
Install-VisualStudio `
-Version $toolset.visualStudio.subversion `
-Edition $toolset.visualStudio.edition `
-Channel $toolset.visualStudio.channel `
-RequiredComponents $toolset.visualStudio.workloads `
-Version $vsToolset.subversion `
-Edition $vsToolset.edition `
-Channel $vsToolset.channel `
-RequiredComponents $vsToolset.workloads `
-ExtraArgs "--allWorkloads --includeRecommended --remove Component.CPython3.x64" `
-SignatureThumbprint $toolset.visualStudio.signature
-SignatureThumbprint $vsToolset.signature
# Find the version of VS installed for this instance
# Only supports a single instance
@@ -20,8 +20,7 @@ $vsProgramData = Get-Item -Path "C:\ProgramData\Microsoft\VisualStudio\Packages\
$instanceFolders = Get-ChildItem -Path $vsProgramData.FullName
if ($instanceFolders -is [array]) {
Write-Host "More than one instance installed"
exit 1
throw "More than one instance installed"
}
# Updating content of MachineState.json file to disable autoupdate of VSIX extensions
@@ -35,7 +34,7 @@ if (Test-IsWin19) {
-Url 'https://go.microsoft.com/fwlink/p/?LinkId=838916' `
-InstallArgs @("/q", "/norestart", "/ceip off", "/features OptionId.WindowsSoftwareDevelopmentKit") `
-ExpectedSignature 'C91545B333C52C4465DE8B90A3FAF4E1D9C58DFA'
# Install Windows 11 SDK version 10.0.22621.0
Install-Binary -Type EXE `
-Url 'https://go.microsoft.com/fwlink/p/?linkid=2196241' `

View File

@@ -4,7 +4,7 @@
################################################################################
Install-Binary -Type MSI `
-Url 'http://go.microsoft.com/fwlink/?LinkId=287166' `
-ExpectedSignature 'C3A3D43788E7ABCD287CB4F5B6583043774F99D2'
-Url 'http://go.microsoft.com/fwlink/?LinkId=287166' `
-ExpectedSignature 'C3A3D43788E7ABCD287CB4F5B6583043774F99D2'
Invoke-PesterTests -TestFile "Tools" -TestName "WebPlatformInstaller"

View File

@@ -4,12 +4,13 @@
####################################################################################
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$latestReleaseUrl = 'https://api.github.com/repos/microsoft/WinAppDriver/releases/latest'
$installerUrl = (Invoke-RestMethod -Uri $latestReleaseUrl).assets.browser_download_url
$downloadUrl = Resolve-GithubReleaseAssetUrl `
-Repo "microsoft/WinAppDriver" `
-Version "latest" `
-UrlMatchPattern "WindowsApplicationDriver_*.msi"
Install-Binary `
-Url $installerUrl `
-ExpectedSignature '2485A7AFA98E178CB8F30C9838346B514AEA4769'
-Url $downloadUrl `
-ExpectedSignature '2485A7AFA98E178CB8F30C9838346B514AEA4769'
Invoke-PesterTests -TestFile "WinAppDriver" -TestName "WinAppDriver"

View File

@@ -1,3 +1,8 @@
####################################################################################
## File: Install-WindowsFeatures.ps1
## Desc: Install Windows Features
####################################################################################
$windowsFeatures = (Get-ToolsetContent).windowsFeatures
foreach ($feature in $windowsFeatures) {

View File

@@ -28,8 +28,7 @@ function Install-WindowsUpdates {
$failedUpdates = $updates[0] | Where-Object Title -notmatch "Microsoft Defender Antivirus" | Where-Object { -not ($notFailedUpdateNames -match $_.KB) }
if ( $failedUpdates ) {
Write-Host "Windows updates failed to install: $($failedUpdates.KB)"
exit 1
throw "Windows updates failed to install: $($failedUpdates.KB)"
}
}

View File

@@ -3,17 +3,18 @@
## Desc: Install zstd
################################################################################
$url = "https://api.github.com/repos/facebook/zstd/releases/latest"
# Explicitly set type to string since match returns array by default
[System.String] $zstdLatest = (Invoke-RestMethod -Uri $url).assets.browser_download_url -match "zstd-.+-win64.zip$"
$zstdArchivePath = Invoke-DownloadWithRetry $zstdLatest
$downloadUrl = Resolve-GithubReleaseAssetUrl `
-Repo "facebook/zstd" `
-Version "latest" `
-UrlMatchPattern "zstd-*-win64.zip"
$zstdArchivePath = Invoke-DownloadWithRetry $downloadUrl
$zstdName = [IO.Path]::GetFileNameWithoutExtension($zstdArchivePath)
$toolPath = "C:\tools"
$zstdPath = Join-Path $toolPath zstd
$zstdParentName = [IO.Path]::GetFileNameWithoutExtension($zstdLatest)
$filesInArchive = 7z l $zstdArchivePath | Out-String
if ($filesInArchive.Contains($zstdParentName)) {
if ($filesInArchive.Contains($zstdName)) {
Expand-7ZipArchive -Path $zstdArchivePath -DestinationPath $toolPath
Invoke-ScriptBlockWithRetry -Command {
Move-Item -Path "${zstdPath}*" -Destination $zstdPath -ErrorAction Stop