Skip to content

Instantly share code, notes, and snippets.

@JustinGrote
Last active February 29, 2024 02:37
Show Gist options
  • Save JustinGrote/dc432cb4d4410fa0c190613c3e8e4db5 to your computer and use it in GitHub Desktop.
Save JustinGrote/dc432cb4d4410fa0c190613c3e8e4db5 to your computer and use it in GitHub Desktop.
Powershell Bootstrap script for VSCode Server
#require -version 5.1
#Usage: iwr https://tinyurl.com/VSCodeServer | iex
#Parameterized usage: & ([ScriptBlock]::Create((iwr https://tinyurl.com/VSCodeServer))) -Your -Options
param(
#Path to install the vscode binary to. This defaults to a folder in your Local AppData path. Must be writable by your current user without sudo
[ValidateNotNullOrEmpty()]
[string]$InstallPath = $(Join-Path -Path ([System.Environment]::GetFolderPath('LocalApplicationData')) -ChildPath 'vscode-cli'),
#Installation architecture. This is normally autodetected.
$Arch,
$OS,
[ValidateSet('stable', 'insider')]
[ValidateNotNullOrEmpty()]
$Build = 'stable',
#Path to find the vscode server launcher. You normally dont need to change.
[ValidateNotNullOrEmpty()]
$InstallUri = 'https://code.visualstudio.com/sha/download',
#Normally this script will use the existing detected code server or vscode instance. Specify to force a new install.
[Switch]$Force,
#This script typically starts code-server automatically upon run. Specify to prevent that behavior
[switch]$InstallOnly,
#This script updates the path to include code-server so it can be specified again. Specify to prevent that behavior
[switch]$NoUpdatePath,
#Additional arguments to pass to code --tunnel, such as if you want to customize the name of the tunnel
[string[]]$ArgumentList,
#By default this uses GitHub for auth, specify this to use MS
[switch]$UseMicrosoftLogin
)
$ErrorActionPreference = 'Stop'
if (-not $OS) {
#Polyfill for 5.1
if ($null -eq $IsWindows) {
$IsWindows = $true
}
$OS = switch ($true) {
$IsWindows { 'win32' }
$IsLinux { 'alpine' }
$IsMacOS { 'darwin' }
default { throw [NotSupportedException]'This platform is not supported by this script.' }
}
}
if (-not $Arch) {
if ($OS -eq 'win32') {
if (-not $Arch) {
$Arch = switch ($ENV:PROCESSOR_ARCHITECTURE) {
'AMD64' { 'x64' }
'ARM64' { 'arm64' }
default { throw [NotSupportedException]'Unknown Windows Architecture, this is either a bug or you are trying to install on an x86 machine' }
}
}
} elseif ($isLinux -or $isMacOS) {
$arch = switch (uname -m) {
'x86_64' { 'x64' }
'aarch64' { 'arm64' }
'armv7l' { 'arm32' }
default { throw [NotSupportedException]'Unknown Linux Architecture, please specify x64, arm32, or arm64 for the Arch parameter of this command' }
}
} else {
throw [NotSupportedException]'This platform is not supported by this script.'
}
}
$Body = @{
'build' = $Build
'os' = "cli-$OS-$Arch"
}
$OutBin = if ($IsWindows) { 'code-cli.exe' } else { 'code-cli' }
$CodeCliPath = Join-Path -Path $InstallPath -ChildPath $OutBin
if ((Test-Path $CodeCliPath) -and -not $Force) {
Write-Verbose "Found existing vscode CLI at $CodeCliPath"
$LocalInstallFound = $true
$OutBinPath = $CodeCliPath
} else {
Write-Verbose 'No vscode CLI install found or -Force specified, checking for existing vscode installations'
if ($Force) {
Write-Verbose '-Force Specified, skipping vscode binary detection'
} else {
$VSCodePath = foreach ($command in 'code-insiders', 'code') {
$candidatePath = (Get-Command $command -CommandType Application -ErrorAction Ignore) |
Select-Object -First 1 |
ForEach-Object Source
if ($candidatePath) {
Write-Verbose "Found existing vscode binary at $candidatePath"
$candidatePath
break
}
}
if ($VSCodePath) {
Write-Verbose "VSCode detected at $VSCodePath"
$OutBinPath = $VSCodePath
$LocalInstallFound = $true
} else {
Write-Verbose 'No existing vscode installation found'
}
}
Write-Host -Fore Magenta "Local Install Found: $LocalInstallFound"
if (-not $LocalInstallFound) {
$OutBinPath = $CodeCliPath
Write-Verbose "Downloading vscode $OS $Arch from $BaseUri"
#Prep the target folder if it doesn't exist and download the binary
New-Item -ItemType Directory -Force -Path $InstallPath | Out-Null
if ($IsWindows) {
#Improves download performance on 5.1
$lastProgressPreference = $ProgressPreference
$ProgressPreference = 'SilentlyContinue'
}
$zipTempPath = [System.IO.Path]::GetTempPath() + [System.IO.Path]::GetRandomFileName() + '.zip'
try {
Invoke-WebRequest -Method GET -UseBasicParsing -Body $Body -Uri $InstallUri -OutFile $zipTempPath
Expand-Archive -Path $zipTempPath -DestinationPath $InstallPath -Force
$cliFileName = if ($IsWindows) { 'code.exe' } else { 'code' }
Move-Item (Join-Path $InstallPath $cliFileName) $OutBinPath -Force
} finally {
Remove-Item $zipTempPath -ErrorAction Ignore
}
if (-not $isWindows) {
& chmod +x $OutBinPath
}
if ($IsWindows) {
$ProgressPreference = $lastProgressPreference
}
Write-Verbose "Downloaded code server to $OutBinPath"
if (-not $NoUpdatePath) {
$Paths = [Environment]::GetEnvironmentVariable('Path', 'User') -split [io.path]::PathSeparator
if ($InstallPath -notin $Paths) {
Write-Verbose "PATH variable already contains $InstallPath, skipping..."
} else {
Write-Verbose "Updating PATH to include $InstallPath"
}
[string]$newPathVar = "$InstallPath" + [io.path]::PathSeparator + [Environment]::GetEnvironmentVariable('Path', 'User')
[Environment]::SetEnvironmentVariable('Path', $newPathVar, 'User')
}
}
if (-not (Test-Path $OutBinPath)) {
throw [InvalidOperationException]'Failed to find or install vscode binary'
}
}
if (-not $InstallOnly) {
Write-Verbose "Starting $OutBinPath in current path $PWD"
if ($UseMicrosoftLogin) {
Write-Verbose "-UseMicrosoftLogin specified, starting $OutBinPath with --auth-provider=Microsoft"
$codeCliParams = @(
'tunnel'
'login'
'--provider'
'microsoft'
)
& $OutBinPath @codeCliParams
if ((& $OutBinPath tunnel user show) -ne 'logged in') {
throw [InvalidOperationException]'Failed to log in to Microsoft'
}
}
$codeCliParams = @(
'tunnel'
'--accept-server-license-terms'
)
& $OutBinPath @codeCliParams @ArgumentList
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment