[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

@@ -1,4 +1,25 @@
function Install-ChocoPackage {
<#
.SYNOPSIS
A function to install a Chocolatey package with retries.
.DESCRIPTION
This function attempts to install a specified Chocolatey package. If the
installation fails, it retries a specified number of times.
.PARAMETER PackageName
The name of the Chocolatey package to install.
.PARAMETER ArgumentList
An array of arguments to pass to the choco install command.
.PARAMETER RetryCount
The number of times to retry the installation if it fails. Default is 5.
.EXAMPLE
Install-ChocoPackage -PackageName "git" -RetryCount 3
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
@@ -30,6 +51,25 @@ function Install-ChocoPackage {
}
function Resolve-ChocoPackageVersion {
<#
.SYNOPSIS
Resolves the latest version of a Chocolatey package.
.DESCRIPTION
This function takes a package name and a target version as input and returns the latest
version of the package that is greater than or equal to the target version.
.PARAMETER PackageName
The name of the Chocolatey package.
.PARAMETER TargetVersion
The target version of the package.
.EXAMPLE
Resolve-ChocoPackageVersion -PackageName "example-package" -TargetVersion "1.0.0"
Returns the latest version of the "example-package" that is greater than or equal to "1.0.0".
#>
param(
[Parameter(Mandatory)]
[string] $PackageName,
@@ -38,12 +78,12 @@ function Resolve-ChocoPackageVersion {
)
$versionNumbers = $TargetVersion.Split(".")
[int]$versionNumbers[-1] += 1
[int] $versionNumbers[-1] += 1
$incrementedVersion = $versionNumbers -join "."
$filterQuery = "`$filter=(Id eq '$PackageName') and (IsPrerelease eq false) and (Version ge '$TargetVersion') and (Version lt '$incrementedVersion')"
$latestVersion = (Invoke-RestMethod "https://community.chocolatey.org/api/v2/Packages()?$filterQuery").properties.Version |
Where-Object { $_ -Like "$TargetVersion.*" -or $_ -eq $TargetVersion } |
Sort-Object { [version]$_ } |
Sort-Object { [version] $_ } |
Select-Object -Last 1
return $latestVersion

View File

@@ -2,43 +2,55 @@
param()
. $PSScriptRoot\AndroidHelpers.ps1
. $PSScriptRoot\ChocoHelpers.ps1
. $PSScriptRoot\InstallHelpers.ps1
. $PSScriptRoot\PathHelpers.ps1
. $PSScriptRoot\VisualStudioHelpers.ps1
Export-ModuleMember -Function @(
'Get-AndroidPackages'
'Get-AndroidPlatformPackages'
'Get-AndroidBuildToolPackages'
'Get-AndroidInstalledPackages'
)
. $PSScriptRoot\ChocoHelpers.ps1
Export-ModuleMember -Function @(
'Install-ChocoPackage'
'Resolve-ChocoPackageVersion'
)
. $PSScriptRoot\InstallHelpers.ps1
Export-ModuleMember -Function @(
'Install-Binary'
'Invoke-DownloadWithRetry'
'Get-ToolsetContent'
'Get-TCToolPath'
'Get-TCToolVersionPath'
'Test-IsWin22'
'Test-IsWin19'
'Expand-7ZipArchive'
'Get-WindowsUpdateStates'
'Invoke-ScriptBlockWithRetry'
'Get-GithubReleasesByVersion'
'Resolve-GithubReleaseAssetUrl'
'Get-ChecksumFromGithubRelease'
'Get-ChecksumFromUrl'
'Test-FileChecksum'
'Test-FileSignature'
'Update-Environment'
)
. $PSScriptRoot\PathHelpers.ps1
Export-ModuleMember -Function @(
'Mount-RegistryHive'
'Dismount-RegistryHive'
'Add-MachinePathItem'
'Add-DefaultPathItem'
'Install-Binary'
)
. $PSScriptRoot\VisualStudioHelpers.ps1
Export-ModuleMember -Function @(
'Install-VisualStudio'
'Get-ToolsetContent'
'Get-TCToolVersionPath'
'Get-TCToolPath'
'Invoke-DownloadWithRetry'
'Get-VisualStudioInstance'
'Get-VisualStudioComponents'
'Get-VsixInfoFromMarketplace'
'Install-VSIXFromFile'
'Install-VSIXFromUrl'
'Get-VSExtensionVersion'
'Test-IsWin22'
'Test-IsWin19'
'Install-ChocoPackage'
'Resolve-ChocoPackageVersion'
'Resolve-GithubReleaseAssetUrl'
'Expand-7ZipArchive'
'Invoke-ScriptBlockWithRetry'
'Get-VsCatalogJsonPath'
'Get-AndroidPackages'
'Get-AndroidPlatformPackages'
'Get-AndroidBuildToolPackages'
'Get-AndroidInstalledPackages'
'Get-VisualStudioInstance'
'Get-VisualStudioComponents'
'Get-WindowsUpdateStates'
'Get-GithubReleaseAssetHash'
'Test-FileChecksum'
'Test-FileSignature'
'Update-Environment'
)

View File

@@ -131,6 +131,33 @@ function Install-Binary {
}
function Invoke-DownloadWithRetry {
<#
.SYNOPSIS
Downloads a file from a given URL with retry functionality.
.DESCRIPTION
The Invoke-DownloadWithRetry function downloads a file from the specified URL
to the specified path. It includes retry functionality in case the download fails.
.PARAMETER Url
The URL of the file to download.
.PARAMETER Path
The path where the downloaded file will be saved. If not provided, a temporary path
will be used.
.EXAMPLE
Invoke-DownloadWithRetry -Url "https://example.com/file.zip" -Path "C:\Downloads\file.zip"
Downloads the file from the specified URL and saves it to the specified path.
.EXAMPLE
Invoke-DownloadWithRetry -Url "https://example.com/file.zip"
Downloads the file from the specified URL and saves it to a temporary path.
.OUTPUTS
The path where the downloaded file is saved.
#>
Param
(
[Parameter(Mandatory)]
@@ -165,6 +192,11 @@ function Invoke-DownloadWithRetry {
$attemptSeconds = [math]::Round(($(Get-Date) - $attemptStartTime).TotalSeconds, 2)
Write-Warning "Package download failed in $attemptSeconds seconds"
Write-Warning $_.Exception.Message
if ($_.Exception.InnerException.Response.StatusCode -eq [System.Net.HttpStatusCode]::NotFound) {
Write-Warning "Request returned 404 Not Found. Aborting download."
$retries = 0
}
}
if ($retries -eq 0) {
@@ -180,6 +212,15 @@ function Invoke-DownloadWithRetry {
}
function Get-ToolsetContent {
<#
.SYNOPSIS
Retrieves the content of the toolset.json file.
.DESCRIPTION
This function reads the toolset.json file located at "C:\image\toolset.json"
and returns the content as a PowerShell object.
#>
$toolsetPath = Join-Path "C:\\image" "toolset.json"
$toolsetJson = Get-Content -Path $toolsetPath -Raw
ConvertFrom-Json -InputObject $toolsetJson
@@ -478,6 +519,10 @@ function Get-GithubReleasesByVersion {
.PARAMETER AllowPrerelease
Specifies whether to include prerelease versions in the results. By default,
prerelease versions are excluded.
.PARAMETER WithAssetsOnly
Specifies whether to exclude releases without assets. By default, releases without
assets are included.
.EXAMPLE
Get-GithubReleasesByVersion -Repository "Microsoft/PowerShell" -Version "7.2.0"
@@ -500,7 +545,8 @@ function Get-GithubReleasesByVersion {
[Alias("Repo")]
[string] $Repository,
[string] $Version = "*",
[switch] $AllowPrerelease
[switch] $AllowPrerelease,
[switch] $WithAssetsOnly
)
$localCacheFile = Join-Path ${env:TEMP} "github-releases_$($Repository -replace "/", "_").json"
@@ -528,7 +574,9 @@ function Get-GithubReleasesByVersion {
throw "Failed to get releases from ${Repository}"
}
$releases = $releases.Where{ $_.assets }
if ($WithAssetsOnly) {
$releases = $releases.Where{ $_.assets }
}
if (-not $AllowPrerelease) {
$releases = $releases.Where{ $_.prerelease -eq $false }
}
@@ -608,7 +656,8 @@ function Resolve-GithubReleaseAssetUrl {
$matchingReleases = Get-GithubReleasesByVersion `
-Repository $Repository `
-AllowPrerelease:$AllowPrerelease `
-Version $Version
-Version $Version `
-WithAssetsOnly
# Add wildcard to the beginning of the pattern if it's not there
if ($UrlMatchPattern.Substring(0, 2) -ne "*/") {
@@ -618,7 +667,7 @@ function Resolve-GithubReleaseAssetUrl {
# Loop over releases until we find a download url matching the pattern
foreach ($release in $matchingReleases) {
$matchedVersion = $release.version
$matchedUrl = $release.assets.browser_download_url -like $UrlMatchPattern
$matchedUrl = ([string[]] $release.assets.browser_download_url) -like $UrlMatchPattern
if ($matchedUrl) {
break
}
@@ -638,13 +687,13 @@ function Resolve-GithubReleaseAssetUrl {
return ($matchedUrl -as [string])
}
function Get-GithubReleaseAssetHash {
function Get-ChecksumFromGithubRelease {
<#
.SYNOPSIS
Retrieves the hash value of a specific file from a GitHub release body.
.DESCRIPTION
The Get-GithubReleaseAssetHash function retrieves the hash value (SHA256 or SHA512)
The Get-ChecksumFromGithubRelease function retrieves the hash value (SHA256 or SHA512)
of a specific file from a GitHub release. It searches for the file in the release body
and returns the hash value if found.
@@ -666,12 +715,12 @@ function Get-GithubReleaseAssetHash {
The type of hash value to retrieve. Valid values are "SHA256" and "SHA512".
.EXAMPLE
Get-GithubReleaseAssetHash -Repository "MyRepo" -FileName "myfile.txt" -HashType "SHA256"
Get-ChecksumFromGithubRelease -Repository "MyRepo" -FileName "myfile.txt" -HashType "SHA256"
Retrieves the SHA256 hash value of "myfile.txt" from the latest release of the "MyRepo" repository.
.EXAMPLE
Get-GithubReleaseAssetHash -Repository "MyRepo" -Version "1.0" -FileName "myfile.txt" -HashType "SHA512"
Get-ChecksumFromGithubRelease -Repository "MyRepo" -Version "1.0" -FileName "myfile.txt" -HashType "SHA512"
Retrieves the SHA512 hash value of "myfile.txt" from the release version "1.0" of the "MyRepo" repository.
#>
@@ -693,7 +742,8 @@ function Get-GithubReleaseAssetHash {
$matchingReleases = Get-GithubReleasesByVersion `
-Repository $Repository `
-AllowPrerelease:$AllowPrerelease `
-Version $Version
-Version $Version `
-WithAssetsOnly
foreach ($release in $matchingReleases) {
$matchedVersion = $release.version
@@ -728,6 +778,70 @@ function Get-GithubReleaseAssetHash {
return $hash
}
function Get-ChecksumFromUrl {
<#
.SYNOPSIS
Retrieves the checksum hash for a file from a given URL.
.DESCRIPTION
The Get-ChecksumFromUrl function retrieves the checksum hash for a specified file
from a given URL. It supports SHA256 and SHA512 hash types.
.PARAMETER Url
The URL of the checksum file.
.PARAMETER FileName
The name of the file to retrieve the checksum hash for.
.PARAMETER HashType
The type of hash to retrieve. Valid values are "SHA256" and "SHA512".
.EXAMPLE
Get-ChecksumFromUrl -Url "https://example.com/checksums.txt" -FileName "file.txt" -HashType "SHA256"
Retrieves the SHA256 checksum hash for the file "file.txt" from the URL "https://example.com/checksums.txt".
#>
param (
[Parameter(Mandatory = $true)]
[string] $Url,
[Parameter(Mandatory = $true)]
[Alias("File", "Asset")]
[string] $FileName,
[Parameter(Mandatory = $true)]
[ValidateSet("SHA256", "SHA512")]
[Alias("Type")]
[string] $HashType
)
$tempFile = Join-Path -Path $env:TEMP -ChildPath ([System.IO.Path]::GetRandomFileName())
$checksums = (Invoke-DownloadWithRetry -Url $Url -Path $tempFile | Get-Item | Get-Content) -as [string[]]
Remove-Item -Path $tempFile
$matchedLine = $checksums | Where-Object { $_ -like "*$FileName*" }
if ($matchedLine.Count -gt 1) {
throw "Found multiple lines matching file name '${FileName}' in checksum file."
} elseif ($matchedLine.Count -eq 0) {
throw "File name '${FileName}' not found in checksum file."
}
if ($HashType -eq "SHA256") {
$pattern = "[A-Fa-f0-9]{64}"
} elseif ($HashType -eq "SHA512") {
$pattern = "[A-Fa-f0-9]{128}"
} else {
throw "Unknown hash type: ${HashType}"
}
Write-Debug "Found line matching file name '${FileName}' in checksum file:`n${matchedLine}"
$hash = $matchedLine | Select-String -Pattern $pattern | ForEach-Object { $_.Matches.Value }
if ([string]::IsNullOrEmpty($hash)) {
throw "Found '${FileName}' in checksum file, but failed to get hash from it.`nLine: ${matchedLine}"
}
Write-Host "Found hash for ${FileName} in checksum file: $hash"
return $hash
}
function Test-FileChecksum {
<#
.SYNOPSIS

View File

@@ -18,9 +18,9 @@ function Mount-RegistryHive {
#>
param(
[Parameter(Mandatory = $true)]
[string]$FileName,
[string] $FileName,
[Parameter(Mandatory = $true)]
[string]$SubKey
[string] $SubKey
)
Write-Host "Loading the file $FileName to the Key $SubKey"
@@ -31,8 +31,7 @@ function Mount-RegistryHive {
$result = reg load $SubKey $FileName *>&1
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to load file $FileName to the key ${SubKey}: $result"
exit 1
throw "Failed to load file $FileName to the key ${SubKey}: $result"
}
}
@@ -52,7 +51,7 @@ function Dismount-RegistryHive {
#>
param(
[Parameter(Mandatory = $true)]
[string]$SubKey
[string] $SubKey
)
Write-Host "Unloading the hive $SubKey"
@@ -87,12 +86,12 @@ function Add-MachinePathItem {
param(
[Parameter(Mandatory = $true)]
[string]$PathItem
[string] $PathItem
)
$currentPath = [System.Environment]::GetEnvironmentVariable("PATH", "Machine")
$newPath = $PathItem + ';' + $currentPath
[System.Environment]::SetEnvironmentVariable("PATH", $newPath, "Machine")
[Environment]::SetEnvironmentVariable("PATH", $newPath, "Machine")
}
function Add-DefaultPathItem {
@@ -120,7 +119,7 @@ function Add-DefaultPathItem {
param(
[Parameter(Mandatory = $true)]
[string]$PathItem
[string] $PathItem
)
Mount-RegistryHive `

View File

@@ -117,18 +117,65 @@ Function Install-VisualStudio {
}
function Get-VisualStudioInstance {
<#
.SYNOPSIS
Retrieves the Visual Studio instance.
.DESCRIPTION
This function retrieves the Visual Studio instance
using the Get-VSSetupInstance cmdlet.
It searches for both regular and preview versions
of Visual Studio and returns the first instance found.
#>
# Use -Prerelease and -All flags to make sure that Preview versions of VS are found correctly
$vsInstance = Get-VSSetupInstance -Prerelease -All | Where-Object { $_.DisplayName -match "Visual Studio" } | Select-Object -First 1
$vsInstance | Select-VSSetupInstance -Product *
}
function Get-VisualStudioComponents {
(Get-VisualStudioInstance).Packages | Where-Object type -in 'Component', 'Workload' |
Sort-Object Id, Version | Select-Object @{n = 'Package'; e = { $_.Id } }, Version |
Where-Object { $_.Package -notmatch "[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}" }
<#
.SYNOPSIS
Retrieves the Visual Studio components.
.DESCRIPTION
This function retrieves the Visual Studio components
by filtering the packages returned by Get-VisualStudioInstance cmdlet.
It filters the packages based on their type, sorts them by Id and Version,
and excludes packages with GUID-like Ids.
#>
(Get-VisualStudioInstance).Packages `
| Where-Object type -in 'Component', 'Workload' `
| Sort-Object Id, Version `
| Select-Object @{n = 'Package'; e = { $_.Id } }, Version `
| Where-Object { $_.Package -notmatch "[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}" }
}
function Get-VsixInfoFromMarketplace {
<#
.SYNOPSIS
Retrieves information about a Visual Studio extension from the Visual Studio Marketplace.
.DESCRIPTION
The Get-VsixInfoFromMarketplace function retrieves information
about a Visual Studio extension from the Visual Studio Marketplace.
It takes the name of the extension as input and returns
the extension's name, VsixId, filename, and download URI.
.PARAMETER Name
The name of the Visual Studio extension.
.PARAMETER MarketplaceUri
The URI of the Visual Studio Marketplace.
Default value is "https://marketplace.visualstudio.com/items?itemName=".
.EXAMPLE
Get-VsixInfoFromMarketplace -Name "ProBITools.MicrosoftReportProjectsforVisualStudio2022"
Retrieves information about the "ProBITools.MicrosoftReportProjectsforVisualStudio2022" extension
from the Visual Studio Marketplace.
#>
Param
(
[Parameter(Mandatory)]
@@ -183,6 +230,25 @@ function Get-VsixInfoFromMarketplace {
}
function Install-VSIXFromFile {
<#
.SYNOPSIS
Installs a Visual Studio Extension (VSIX) from a file.
.DESCRIPTION
This function installs a Visual Studio Extension (VSIX)
from the specified file path. It uses the VSIXInstaller.exe
tool provided by Microsoft Visual Studio.
.PARAMETER FilePath
The path to the VSIX file that needs to be installed.
.PARAMETER Retries
The number of retries to attempt if the installation fails. Default is 20.
.EXAMPLE
Install-VSIXFromFile -FilePath "C:\Extensions\MyExtension.vsix" -Retries 10
Installs the VSIX file located at "C:\Extensions\MyExtension.vsix" with 10 retries in case of failure.
#>
Param
(
[Parameter(Mandatory = $true)]
@@ -228,6 +294,25 @@ function Install-VSIXFromFile {
}
function Install-VSIXFromUrl {
<#
.SYNOPSIS
Installs a Visual Studio extension (VSIX) from a given URL.
.DESCRIPTION
This function downloads a Visual Studio extension (VSIX)
from the specified URL and installs it.
.PARAMETER Url
The URL of the VSIX file to download and install.
.PARAMETER Retries
The number of retries to attempt if the download fails. Default is 20.
.EXAMPLE
Install-VSIXFromUrl -Url "https://example.com/extension.vsix" -Retries 10
Downloads and installs the VSIX file from the specified URL with 10 retries.
#>
Param
(
[Parameter(Mandatory = $true)]
@@ -241,6 +326,22 @@ function Install-VSIXFromUrl {
}
function Get-VSExtensionVersion {
<#
.SYNOPSIS
Retrieves the version of a Visual Studio extension package.
.DESCRIPTION
This function retrieves the version of a specified Visual Studio extension package.
It searches for the package in the installed instances of Visual Studio and
returns the version number.
.PARAMETER packageName
The name of the extension package.
.EXAMPLE
Get-VSExtensionVersion -packageName "MyExtensionPackage"
Retrieves the version of the extension package named "MyExtensionPackage" for Visual Studio.
#>
Param
(
[Parameter(Mandatory = $true)]