Skip to content

Instantly share code, notes, and snippets.

@PanosGreg
Created September 11, 2025 00:47
Show Gist options
  • Save PanosGreg/fade3c041cfd8093fda1ff03b41fcc45 to your computer and use it in GitHub Desktop.
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 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