Created
September 11, 2025 00:47
-
-
Save PanosGreg/fade3c041cfd8093fda1ff03b41fcc45 to your computer and use it in GitHub Desktop.
Install VS Code extension. I had an issue due to proxy and certs, this function has a workaround for that.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# this hashtable is used on the extension name validation for the input | |
# it is also used to get the extension id | |
$script:VSCodeExtensions = @{ | |
'vscode-icons' = 'vscode-icons-team.vscode-icons' | |
powershell = 'ms-vscode.powershell' | |
csharp = 'ms-dotnettools.csdevkit' | |
terraform = 'hashicorp.terraform' | |
} | |
# Note: if this was a module, we could have this in a .psd1 file | |
Class ExtensionNames : System.Management.Automation.IValidateSetValuesGenerator { | |
[string[]] GetValidValues() { | |
return [string[]]$script:VSCodeExtensions.Keys | |
} | |
} | |
# Note: this IValidateSetValuesGenerator interface is only available on PS 7 or later | |
function Install-VscodeExtension { | |
<# | |
.SYNOPSIS | |
It will install an extension to VS Code. | |
If it can't do it, it will try download the .vsix extension file | |
and then install the extension onto VS Code. | |
Finally it will clean-up and delete the downloaded .vsix file | |
.DESCRIPTION | |
The reason why we get the .vsix file instead of just install the extension | |
is because when you are behind a corporate VPN network, the you *may* get an error | |
about certificate: | |
self signed certificate in certificate chain | |
Failed Installing Extensions: vscode-icons-team.vscode-icons | |
As such the only workaround that currently works is to download the .vsix extension | |
and then install it. | |
GitHub Issue: https://github.com/microsoft/vscode/issues/144625 | |
MS documentation: https://code.visualstudio.com/docs/setup/network#_legacy-proxy-server-support | |
How to find the download URL of the .vsix file for a vscode extension | |
https://gist.github.com/wanglf/7acc591890dc0d8ceff1e7ec9af32a55?permalink_comment_id=5560596#gistcomment-5560596 | |
ISSUE | |
If you are behind a proxy or VPN or a network that inspects certificates | |
then you cannot install vscode extensions through the CLI. | |
BUT, you can install them fine from the VSCode app itself. | |
There is a setting to disable proxy SSL inspection in the vscode settings.json | |
"http.proxyStrictSSL": false | |
BUT this setting is not respected in the CLI. | |
As per August-2025, VSCode proxy settings are only valid on the VSCode app | |
but they do not work on the vscode cli. | |
So even if you change that proxy setting, you still cannot install an extension | |
from CLI, if you get the error: self signed certificate in certificate chain | |
For even more information in the cli you can use the "--verbose" switch or | |
the "--log trace" parameter. For example: | |
code --install-extension vscode-icons-team.vscode-icons --log trace | |
code --install-extension vscode-icons-team.vscode-icons --verbose | |
.EXAMPLE | |
Install-VscodeExtension -Name powershell -Verbose | |
#> | |
[cmdletbinding()] | |
[OutputType([void],[psobject])] # <-- default is [void], with PassThru switch it returns an object | |
param ( | |
[Parameter(Mandatory)] | |
[ValidateSet([ExtensionNames])] | |
[string]$Name, | |
[switch]$NoFallback, | |
[switch]$PassThru | |
) | |
# let's add some colors to the verbose output (sure why not) | |
$Col = @{} | |
$Col.Def = '{0}[0m' -f [char]27 # Default | |
$Col.Undr = '{0}[4m' -f [char]27 # Underline | |
$Col.NUnd = '{0}[24m' -f [char]27 # No Underline | |
$Col.Blu = '{0}[38;2;{1};{2};{3}m' -f [char]27, 61, 148, 243 # Blue | |
$Col.DBlu = '{0}[38;2;{1};{2};{3}m' -f [char]27, 68, 114, 196 # Dark Blue | |
$Col.LBlu = '{0}[38;2;{1};{2};{3}m' -f [char]27, 153, 204, 255 # Light Blue | |
# helper functions | |
function Write-ColorVerbose { | |
[CmdletBinding()] | |
param ([string]$Msg,[string]$ExtName=$Name) | |
$ExtNameColor = $Col.LBlu + $Col.Undr + $ExtName + $Col.NUnd + $Col.Blu | |
$out = $Col.Blu + $Msg.Replace($ExtName,$ExtNameColor) + $Col.Def | |
Write-Verbose $out | |
} | |
function Get-VscodeExtension([string]$ExtId='*') { | |
$hash = [ordered]@{} | |
code --list-extensions --show-versions | foreach { | |
$rgx = '^(?<FullName>(?<ExtensionId>(?<Publisher>.+)\.(?<Name>.+))@(?<Version>.+))$' | |
$hash.Clear() | |
[regex]::Match($_,$rgx).Groups | select -Skip 1 | foreach {$hash.Add($_.Name,$_.Value)} | |
[pscustomobject]$hash | |
} | where ExtensionId -like $ExtId | |
} | |
# get the vscode extension from the external hashtable (located at the top of this file) | |
$ExtensionId = $script:VSCodeExtensions[$Name] | |
# first check if it's already installed | |
$ThisExtension = Get-VscodeExtension -ExtId $ExtensionId | |
if ($ThisExtension) { | |
Write-ColorVerbose "The extension $Name is already installed in vs code." | |
if ($PassThru) {Write-Output $ThisExtension} | |
return | |
} | |
# then try to install the extension normally | |
Write-ColorVerbose "Install the $Name extension directly from the internet." | |
$Installation = code --install-extension $ExtensionId *>&1 | |
# get any installation errors | |
$err = $Installation | where {$_ -is [System.Management.Automation.ErrorRecord]} | |
$HasCertError = ($err | where {$_.Exception.Message -eq 'self signed certificate in certificate chain'}) -as [bool] | |
$HasFailed = ($err | where {$_.Exception.Message -like 'Failed Installing Extensions:*'}) -as [bool] | |
if ($HasFailed -and $NoFallback) { | |
Write-Warning "Could not install the extension $Name" | |
Write-Warning 'User specified that no fallback method will be used, exiting' | |
return | |
} | |
elseif ($HasFailed -and $HasCertError -and -not $NoFallback) { | |
Write-ColorVerbose 'Could not install the extension from the internet due to a certificate error' | |
Write-Verbose 'Will try to download the .vsix file and install the extension from a local path.' | |
# now try to download the .vsix file first and then install it | |
$Publisher,$ExtensionName = $ExtensionId.Split('.') | |
$DownloadUrl = "https://$Publisher.gallery.vsassets.io/_apis/public/gallery/publisher/$Publisher/extension/$ExtensionName/latest/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage" | |
$VsixFile = Join-Path $env:TEMP "$Name.vsix" | |
# old code that gets the download link from github -- not needed, we get the .vsix from Visual Studio Assets now (vsassets.io) | |
# $repo = 'https://api.github.com/repos/vscode-icons/vscode-icons/releases/latest' | |
# $link = ((Invoke-RestMethod $repo -Verbose:$false).assets | where name -like '*.vsix').browser_download_url | |
try { | |
[System.Net.WebClient]::new().DownloadFile($DownloadUrl,$VsixFile) | |
} | |
catch { | |
Write-Warning "There was an issue while trying to download the $Name extension." | |
throw $_ | |
} | |
# and then install the .vsix onto vscode | |
if (Test-Path $VsixFile) { | |
$Installation = code --install-extension "$VsixFile" *>&1 # <-- I use double-quotes in case there's a space in the path | |
Start-Sleep -Seconds 1 | |
Remove-Item $VsixFile -Force -Verbose:$false | |
} | |
else { | |
Write-Warning 'Could not find the vsix file, maybe the download was interrupted' | |
return | |
} | |
} | |
$Success = ($Installation | where {$_ -like '*was successfully installed.'}) -as [bool] | |
if (-not $Success) { | |
Write-Warning 'Something went wrong during the installation' | |
return $Installation | |
} | |
else { | |
Write-ColorVerbose "The $Name extension was installed successfully" | |
} | |
if ($PassThru) {Get-VscodeExtension -ExtId $ExtensionId} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment