feature: initial commit for all new image changes

This commit is contained in:
Subir Ghosh
2024-11-13 17:16:01 -07:00
parent de6aa9e70e
commit fcf3d0ac96
1042 changed files with 45086 additions and 1 deletions
@@ -0,0 +1,163 @@
function Get-AndroidPackages {
<#
.SYNOPSIS
This function returns a list of available Android packages.
.DESCRIPTION
The Get-AndroidPackages function checks if a list of packages is already available in a file.
If not, it uses the sdkmanager.bat script to generate a list of available packages and saves it to a file.
It then returns the content of this file.
.PARAMETER SDKRootPath
The root path of the Android SDK installation.
If not specified, the function uses the ANDROID_HOME environment variable.
.EXAMPLE
Get-AndroidPackages -SDKRootPath "C:\Android\SDK"
This command returns a list of available Android packages for the specified SDK root path.
.NOTES
This function requires the Android SDK to be installed and the sdkmanager.bat script to be accessible.
#>
Param
(
[string] $SDKRootPath
)
if (-not $SDKRootPath) {
$SDKRootPath = $env:ANDROID_HOME
}
$packagesListFile = "$SDKRootPath\packages-list.txt"
$sdkManager = "$SDKRootPath\cmdline-tools\latest\bin\sdkmanager.bat"
if (-Not (Test-Path -Path $packagesListFile -PathType Leaf)) {
(cmd /c "$sdkManager --list --verbose 2>&1") |
Where-Object { $_ -Match "^[^\s]" } |
Where-Object { $_ -NotMatch "^(Loading |Info: Parsing |---|\[=+|Installed |Available )" } |
Where-Object { $_ -NotMatch "^[^;]*$" } |
Out-File -FilePath $packagesListFile
}
return Get-Content $packagesListFile
}
function Get-AndroidPlatformPackages {
<#
.SYNOPSIS
This function returns a list of available Android platform packages.
.DESCRIPTION
The Get-AndroidPlatformPackages function uses the Get-AndroidPackages function to get a list of available packages
and filters it to return only platform packages.
.PARAMETER SDKRootPath
The root path of the Android SDK installation.
If not specified, the function uses the ANDROID_HOME environment variable.
.PARAMETER minimumVersion
The minimum version of the platform packages to include in the result. Default is 0.
.EXAMPLE
Get-AndroidPlatformPackages -SDKRootPath "C:\Android\SDK" -minimumVersion 29
This command returns a list of available Android platform packages for the specified SDK root path with a minimum version of 29.
.NOTES
This function requires the Android SDK to be installed and the sdkmanager.bat script to be accessible.
#>
Param
(
[string] $SDKRootPath,
[Alias("minVersion")]
[int] $minimumVersion = 0
)
if (-not $SDKRootPath) {
$SDKRootPath = $env:ANDROID_HOME
}
return (Get-AndroidPackages -SDKRootPath $SDKRootPath) `
| Where-Object { "$_".StartsWith("platforms;") } `
| Where-Object { ($_.Split("-")[1] -as [int]) -ge $minimumVersion } `
| Sort-Object -Unique
}
function Get-AndroidBuildToolPackages {
<#
.SYNOPSIS
This function returns a list of available Android build tool packages.
.DESCRIPTION
The Get-AndroidBuildToolPackages function uses the Get-AndroidPackages function to get a list of available packages
and filters it to return only build tool packages.
.PARAMETER SDKRootPath
The root path of the Android SDK installation.
If not specified, the function uses the ANDROID_HOME environment variable.
.PARAMETER minimumVersion
The minimum version of the build tool packages to include in the result. Default is 0.0.0.
.EXAMPLE
Get-AndroidBuildToolPackages -SDKRootPath "C:\Android\SDK" -minimumVersion "30.0.2"
This command returns a list of available Android build tool packages for the specified SDK root path with a minimum version of 30.0.2.
.NOTES
This function requires the Android SDK to be installed and the sdkmanager.bat script to be accessible.
#>
Param
(
[string] $SDKRootPath,
[Alias("minVersion")]
[version] $minimumVersion = "0.0.0"
)
if (-not $SDKRootPath) {
$SDKRootPath = $env:ANDROID_HOME
}
return (Get-AndroidPackages -SDKRootPath $SDKRootPath) `
| Where-Object { "$_".StartsWith("build-tools;") } `
| Where-Object { ($_.Split(";")[1] -as [version]) -ge $minimumVersion } `
| Sort-Object -Unique
}
function Get-AndroidInstalledPackages {
<#
.SYNOPSIS
Retrieves a list of installed Android packages.
.DESCRIPTION
This function retrieves a list of installed Android packages using the specified SDK root path.
.PARAMETER SDKRootPath
The root path of the Android SDK.
If not specified, the function uses the ANDROID_HOME environment variable.
.EXAMPLE
Get-AndroidInstalledPackages -SDKRootPath "C:\Android\SDK"
Retrieves a list of installed Android packages using the specified SDK root path.
.NOTES
This function requires the Android SDK to be installed and the SDK root path to be provided.
#>
Param
(
[string] $SDKRootPath
)
if (-not $SDKRootPath) {
$SDKRootPath = $env:ANDROID_HOME
}
$sdkManager = "$SDKRootPath\cmdline-tools\latest\bin\sdkmanager.bat"
return (cmd /c "$sdkManager --list_installed 2>&1") -notmatch "Warning"
}
@@ -0,0 +1,89 @@
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)]
[string] $PackageName,
[string[]] $ArgumentList,
[int] $RetryCount = 5
)
process {
$count = 1
while ($true) {
Write-Host "Running [#$count]: choco install $packageName -y $argumentList"
choco install $packageName -y @argumentList --no-progress --require-checksums
$pkg = choco list --localonly $packageName --exact --all --limitoutput
if ($pkg) {
Write-Host "Package installed: $pkg"
break
} else {
$count++
if ($count -ge $retryCount) {
Write-Host "Could not install $packageName after $count attempts"
exit 1
}
Start-Sleep -Seconds 30
}
}
}
}
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,
[Parameter(Mandatory)]
[string] $TargetVersion
)
$searchResult = choco search $PackageName --exact --all-versions --approved-only --limit-output |
ConvertFrom-CSV -Delimiter '|' -Header 'Name', 'Version'
$latestVersion = $searchResult.Version |
Where-Object { $_ -Like "$TargetVersion.*" -or $_ -eq $TargetVersion } |
Sort-Object { [version] $_ } |
Select-Object -Last 1
return $latestVersion
}
@@ -0,0 +1,107 @@
@{
# Script module or binary module file associated with this manifest.
RootModule = 'ImageHelpers.psm1'
# Version number of this module.
ModuleVersion = '0.0.1'
# Supported PSEditions
# CompatiblePSEditions = @()
# ID used to uniquely identify this module
GUID = 'c9334909-16a1-48f1-a94a-c7baf1b961d9'
# Description of the functionality provided by this module
Description = 'Helper functions for creating vsts images'
# Minimum version of the Windows PowerShell engine required by this module
# PowerShellVersion = ''
# Name of the Windows PowerShell host required by this module
# PowerShellHostName = ''
# Minimum version of the Windows PowerShell host required by this module
# PowerShellHostVersion = ''
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# DotNetFrameworkVersion = ''
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# CLRVersion = ''
# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''
# Modules that must be imported into the global environment prior to importing this module
# RequiredModules = @()
# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
# ScriptsToProcess = @()
# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()
# Format files (.ps1xml) to be loaded when importing this module
# FormatsToProcess = @()
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
# NestedModules = @()
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = '*'
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = '*'
# Variables to export from this module
VariablesToExport = '*'
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = '*'
# DSC resources to export from this module
# DscResourcesToExport = @()
# List of all modules packaged with this module
# ModuleList = @()
# List of all files packaged with this module
# FileList = @()
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{
PSData = @{
# Tags applied to this module. These help with module discovery in online galleries.
# Tags = @()
# A URL to the license for this module.
# LicenseUri = ''
# A URL to the main website for this project.
# ProjectUri = ''
# A URL to an icon representing this module.
# IconUri = ''
# ReleaseNotes of this module
# ReleaseNotes = ''
} # End of PSData hashtable
} # End of PrivateData hashtable
# HelpInfo URI of this module
# HelpInfoURI = ''
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''
}
@@ -0,0 +1,57 @@
[CmdletBinding()]
param()
. $PSScriptRoot\AndroidHelpers.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-IsWin25'
'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'
)
. $PSScriptRoot\VisualStudioHelpers.ps1
Export-ModuleMember -Function @(
'Install-VisualStudio'
'Get-VisualStudioInstance'
'Get-VisualStudioComponents'
'Get-VsixInfoFromMarketplace'
'Install-VSIXFromFile'
'Install-VSIXFromUrl'
'Get-VSExtensionVersion'
)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,137 @@
function Mount-RegistryHive {
<#
.SYNOPSIS
Mounts a registry hive from a file.
.DESCRIPTION
The Mount-RegistryHive function loads a registry hive from a specified file into a specified subkey.
.PARAMETER FileName
The path to the file from which to load the registry hive.
.PARAMETER SubKey
The registry subkey into which to load the hive.
.EXAMPLE
Mount-RegistryHive -FileName "C:\Path\To\HiveFile.hiv" -SubKey "HKLM\SubKey"
#>
param(
[Parameter(Mandatory = $true)]
[string] $FileName,
[Parameter(Mandatory = $true)]
[string] $SubKey
)
Write-Host "Loading the file $FileName to the Key $SubKey"
if (Test-Path $SubKey.Replace("\", ":")) {
Write-Warning "The key $SubKey is already loaded"
return
}
$result = reg load $SubKey $FileName *>&1
if ($LASTEXITCODE -ne 0) {
throw "Failed to load file $FileName to the key ${SubKey}: $result"
}
}
function Dismount-RegistryHive {
<#
.SYNOPSIS
Dismounts a registry hive.
.DESCRIPTION
The Dismount-RegistryHive function unloads a registry hive from a specified subkey.
.PARAMETER SubKey
The registry subkey from which to unload the hive.
.EXAMPLE
Dismount-RegistryHive -SubKey "HKLM\SubKey"
#>
param(
[Parameter(Mandatory = $true)]
[string] $SubKey
)
Write-Host "Unloading the hive $SubKey"
if (-not (Test-Path $SubKey.Replace("\", ":"))) {
return
}
$result = reg unload $SubKey *>&1
if ($LASTEXITCODE -ne 0) {
Write-Host "Failed to unload hive: $result"
exit 1
}
}
function Add-MachinePathItem {
<#
.SYNOPSIS
Adds a new item to the machine-level PATH environment variable.
.DESCRIPTION
The Add-MachinePathItem function adds a new item to the machine-level PATH environment variable.
It takes a string parameter, $PathItem, which represents the new item to be added to the PATH.
.PARAMETER PathItem
Specifies the new item to be added to the machine-level PATH environment variable.
.EXAMPLE
Add-MachinePathItem -PathItem "C:\Program Files\MyApp"
This example adds "C:\Program Files\MyApp" to the machine-level PATH environment variable.
#>
param(
[Parameter(Mandatory = $true)]
[string] $PathItem
)
$currentPath = [System.Environment]::GetEnvironmentVariable("PATH", "Machine")
$newPath = $PathItem + ';' + $currentPath
[Environment]::SetEnvironmentVariable("PATH", $newPath, "Machine")
}
function Add-DefaultPathItem {
<#
.SYNOPSIS
Adds a path item to the default user profile path.
.DESCRIPTION
This function adds a specified path item to the default user profile path.
It mounts the NTUSER.DAT file of the default user to the registry,
retrieves the current value of the "Path" environment variable,
appends the new path item to it, and updates the registry with the modified value.
.PARAMETER PathItem
The path item to be added to the default user profile path.
.EXAMPLE
Add-DefaultPathItem -PathItem "C:\Program Files\MyApp"
This example adds "C:\Program Files\MyApp" to the default user profile path.
.NOTES
This function requires administrative privileges to modify the Windows registry.
#>
param(
[Parameter(Mandatory = $true)]
[string] $PathItem
)
Mount-RegistryHive `
-FileName "C:\Users\Default\NTUSER.DAT" `
-SubKey "HKLM\DEFAULT"
$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("DEFAULT\Environment", $true)
$currentValue = $key.GetValue("Path", "", "DoNotExpandEnvironmentNames")
$updatedValue = $PathItem + ';' + $currentValue
$key.SetValue("Path", $updatedValue, "ExpandString")
$key.Handle.Close()
[System.GC]::Collect()
Dismount-RegistryHive "HKLM\DEFAULT"
}
@@ -0,0 +1,360 @@
Function Install-VisualStudio {
<#
.SYNOPSIS
A helper function to install Visual Studio.
.DESCRIPTION
Prepare system environment, and install Visual Studio bootstrapper with selected workloads.
.PARAMETER Version
The version of Visual Studio that will be installed. Required parameter.
.PARAMETER Edition
The edition of Visual Studio that will be installed. Required parameter.
.PARAMETER Channel
The channel of Visual Studio that will be installed. Required parameter.
.PARAMETER RequiredComponents
The list of required components. Required parameter.
.PARAMETER ExtraArgs
The extra arguments to pass to the bootstrapper. Optional parameter.
#>
Param
(
[Parameter(Mandatory)] [String] $Version,
[Parameter(Mandatory)] [String] $Edition,
[Parameter(Mandatory)] [String] $Channel,
[Parameter(Mandatory)] [String[]] $RequiredComponents,
[String] $ExtraArgs = "",
[Parameter(Mandatory)] [String[]] $SignatureThumbprint
)
$bootstrapperUrl = "https://aka.ms/vs/${Version}/${Channel}/vs_${Edition}.exe"
$channelUri = "https://aka.ms/vs/${Version}/${Channel}/channel"
$channelId = "VisualStudio.${Version}.Release"
$productId = "Microsoft.VisualStudio.Product.${Edition}"
Write-Host "Downloading Bootstrapper ..."
$bootstrapperFilePath = Invoke-DownloadWithRetry $BootstrapperUrl
# Verify that the bootstrapper is signed by Microsoft
Test-FileSignature -Path $bootstrapperFilePath -ExpectedThumbprint $SignatureThumbprint
try {
$responseData = @{
"channelUri" = $channelUri
"channelId" = $channelId
"productId" = $productId
"arch" = "x64"
"add" = $RequiredComponents | ForEach-Object { "$_;includeRecommended" }
}
# Create json file with response data
$responseDataPath = "$env:TEMP\vs_install_response.json"
$responseData | ConvertTo-Json | Out-File -FilePath $responseDataPath
$installStartTime = Get-Date
Write-Host "Starting Install ..."
$bootstrapperArgumentList = ('/c', $bootstrapperFilePath, '--in', $responseDataPath, $ExtraArgs, '--quiet', '--norestart', '--wait', '--nocache' )
Write-Host "Bootstrapper arguments: $bootstrapperArgumentList"
$process = Start-Process -FilePath cmd.exe -ArgumentList $bootstrapperArgumentList -Wait -PassThru
$exitCode = $process.ExitCode
$installCompleteTime = [math]::Round(($(Get-Date) - $installStartTime).TotalSeconds, 2)
if ($exitCode -eq 0) {
Write-Host "Installation successful in $installCompleteTime seconds"
return $exitCode
} elseif ($exitCode -eq 3010) {
Write-Host "Installation successful in $installCompleteTime seconds. Reboot is required."
return $exitCode
} else {
Write-Host "Non zero exit code returned by the installation process : $exitCode"
# Try to download tool to collect logs
$collectExeUrl = "https://aka.ms/vscollect.exe"
$collectExePath = Invoke-DownloadWithRetry -Url $collectExeUrl
# Collect installation logs using the collect.exe tool and check if it is successful
& "$collectExePath"
if ($LastExitCode -ne 0) {
Write-Host "Failed to collect logs using collect.exe tool. Exit code : $LastExitCode"
exit $exitCode
}
# Expand the zip file
Expand-Archive -Path "$env:TEMP\vslogs.zip" -DestinationPath "$env:TEMP\vslogs"
# Print logs
$vsLogsPath = "$env:TEMP\vslogs"
$vsLogs = Get-ChildItem -Path $vsLogsPath -Recurse | Where-Object { -not $_.PSIsContainer } | Select-Object -ExpandProperty FullName
foreach ($log in $vsLogs) {
Write-Host "============================"
Write-Host "== Log file : $log "
Write-Host "============================"
Get-Content -Path $log -ErrorAction Continue
}
exit $exitCode
}
}
catch
{
Write-Host "Failed to install Visual Studio; $($_.Exception.Message)"
exit -1
}
}
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 {
<#
.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)]
[Alias("ExtensionMarketPlaceName")]
[string] $Name,
[string] $MarketplaceUri = "https://marketplace.visualstudio.com/items?itemName="
)
# Invoke-WebRequest doesn't support retry in PowerShell 5.1
$webResponse = Invoke-ScriptBlockWithRetry -RetryCount 20 -RetryIntervalSeconds 30 -Command {
Invoke-WebRequest -Uri "${MarketplaceUri}${Name}" -UseBasicParsing
}
$webResponse -match 'UniqueIdentifierValue":"(?<extensionname>[^"]*)' | Out-Null
$extensionName = $Matches.extensionname
$webResponse -match 'VsixId":"(?<vsixid>[^"]*)' | Out-Null
$vsixId = $Matches.vsixid
$webResponse -match 'AssetUri":"(?<uri>[^"]*)' | Out-Null
$assetUri = $Matches.uri
$webResponse -match 'Microsoft\.VisualStudio\.Services\.Payload\.FileName":"(?<filename>[^"]*)' | Out-Null
$fileName = $Matches.filename
switch ($Name) {
# ProBITools.MicrosoftReportProjectsforVisualStudio2022 has different URL
# https://github.com/actions/runner-images/issues/5340
"ProBITools.MicrosoftReportProjectsforVisualStudio2022" {
$assetUri = "https://download.microsoft.com/download/b/b/5/bb57be7e-ae72-4fc0-b528-d0ec224997bd"
$fileName = "Microsoft.DataTools.ReportingServices.vsix"
}
"ProBITools.MicrosoftAnalysisServicesModelingProjects2022" {
$assetUri = "https://download.microsoft.com/download/c/8/9/c896a7f2-d0fd-45ac-90e6-ff61f67523cb"
$fileName = "Microsoft.DataTools.AnalysisServices.vsix"
}
# Starting from version 4.1 SqlServerIntegrationServicesProjects extension is distributed as exe file
"SSIS.SqlServerIntegrationServicesProjects" {
$fileName = "Microsoft.DataTools.IntegrationServices.exe"
}
}
$downloadUri = $assetUri + "/" + $fileName
return [PSCustomObject] @{
"ExtensionName" = $extensionName
"VsixId" = $vsixId
"FileName" = $fileName
"DownloadUri" = $downloadUri
}
}
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)]
[string] $FilePath,
[int] $Retries = 20
)
Write-Host "Installing VSIX from $FilePath..."
while ($True) {
$installerPath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\resources\app\ServiceHub\Services\Microsoft.VisualStudio.Setup.Service\VSIXInstaller.exe"
try {
$process = Start-Process `
-FilePath $installerPath `
-ArgumentList @('/quiet', "`"$FilePath`"") `
-Wait -PassThru
} catch {
Write-Host "Failed to start VSIXInstaller.exe with error:"
$_
exit 1
}
$exitCode = $process.ExitCode
if ($exitCode -eq 0) {
Write-Host "VSIX installed successfully."
break
} elseif ($exitCode -eq 1001) {
Write-Host "VSIX is already installed."
break
}
Write-Host "VSIX installation failed with exit code $exitCode."
$Retries--
if ($Retries -eq 0) {
Write-Host "VSIX installation failed after $Retries retries."
exit 1
}
Write-Host "Waiting 10 seconds before retrying. Retries left: $Retries"
Start-Sleep -Seconds 10
}
}
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)]
[string] $Url,
[int] $Retries = 20
)
$filePath = Invoke-DownloadWithRetry $Url
Install-VSIXFromFile -FilePath $filePath -Retries $Retries
Remove-Item -Force -Confirm:$false $filePath
}
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)]
[string] $packageName
)
$instanceFolders = Get-ChildItem -Path "C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances"
if ($instanceFolders -is [array]) {
Write-Host ($instanceFolders | Out-String)
Write-Host ($instanceFolders | Get-ChildItem | Out-String)
Write-Host "More than one instance installed"
exit 1
}
$stateContent = Get-Content -Path (Join-Path $instanceFolders.FullName '\state.packages.json')
$state = $stateContent | ConvertFrom-Json
$packageVersion = ($state.packages | Where-Object { $_.id -eq $packageName }).version
if (-not $packageVersion) {
Write-Host "Installed package $packageName for Visual Studio was not found"
exit 1
}
return $packageVersion
}
@@ -0,0 +1,13 @@
$ModuleManifestName = 'ImageHelpers.psd1'
$ModuleManifestPath = "$PSScriptRoot\..\$ModuleManifestName"
Describe 'Module Manifest Tests' {
It 'Passes Test-ModuleManifest' {
Test-ModuleManifest -Path $ModuleManifestPath | Should Not BeNullOrEmpty
$? | Should Be $true
}
}