|
#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, |
|
#Customize the name of the tunnel. 20 characters max |
|
$Name |
|
) |
|
$ErrorActionPreference = 'Stop' |
|
|
|
function Get-CodeTunnelName { |
|
#Just use the machine name if this is not cloudshell |
|
if (-not $env:ACC_TID) { |
|
return [environment]::MachineName |
|
} |
|
|
|
[string]$tenant = Get-AzTenantDomain | Get-SubString 10 |
|
[string]$user = $ENV:USER | Get-SubString (15 - $tenant.length) |
|
return "csh-{0}-{1}" -f $tenant, $user |
|
} |
|
|
|
function Get-AzTenantDomain { |
|
#Get the tenant ID name for the cloudshell |
|
#This is wrapped in a scriptblock as Get-AzTenant may not be present in the environment and will cause a parse error |
|
[string]((Get-AzTenant -TenantId $env:ACC_TID).Domains | Select-String '^([^\.]+?).onmicrosoft.com$').Matches[0].Groups[1] |
|
} |
|
|
|
filter Get-SubString ($length) { |
|
$PSItem.Substring(0, [Math]::Min($length, $PSItem.Length)) |
|
} |
|
if (-not $Name) {$Name = Get-CodeTunnelName} |
|
|
|
if (-not $OS) { |
|
#Polyfill for 5.1. This will be $false and not $null in non-Windows versions and won't apply. |
|
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) { |
|
#This is just a shim in cloud shell so we ignore it |
|
if ($env:ACC_CLOUD -and $candidatePath -eq '/usr/bin/code') { |
|
continue |
|
} |
|
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' |
|
} |
|
} |
|
|
|
if (-not $LocalInstallFound) { |
|
$OutBinPath = $CodeCliPath |
|
Write-Verbose "Downloading vscode $OS $Arch from $InstallUri" |
|
#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' |
|
} |
|
|
|
$outExtension = if ($IsWindows) {'.zip'} else {'.tgz'} |
|
$archiveTempPath = [System.IO.Path]::GetTempPath() + [System.IO.Path]::GetRandomFileName() + $outExtension |
|
|
|
try { |
|
Invoke-WebRequest -Method GET -UseBasicParsing -Body $Body -Uri $InstallUri -OutFile $archiveTempPath |
|
if (-not (Test-Path $archiveTempPath)) { |
|
throw "Archive did not download successfully to $archiveTempPath from $InstallUri" |
|
} |
|
$codeFileName = if ($isWindows) { |
|
#5.1 Windows won't tell us the outfile so we have to guess |
|
Expand-Archive -Path $archiveTempPath -DestinationPath $InstallPath -Force |
|
'code.exe' |
|
} else { |
|
& tar -xzvf $archiveTempPath -C $InstallPath |
|
} |
|
|
|
$codeFilePath = Join-Path $InstallPath $CodeFileName |
|
if (-not (Test-Path $codeFilePath)) {throw 'Was not able to extract the code file correctly'} |
|
|
|
Move-Item $codeFilePath $OutBinPath -Force |
|
} finally { |
|
Remove-Item $archiveTempPath -ErrorAction Ignore |
|
} |
|
|
|
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' |
|
'--name' |
|
|
|
) |
|
& $OutBinPath @codeCliParams |
|
if ((& $OutBinPath tunnel user show) -ne 'logged in') { |
|
throw [InvalidOperationException]'Failed to log in to Microsoft' |
|
} |
|
} |
|
$codeCliParams = @( |
|
'tunnel' |
|
'--accept-server-license-terms' |
|
'--name' |
|
$Name |
|
) |
|
& $OutBinPath @codeCliParams @ArgumentList |
|
} |
|
|
|
|