private/远程安装脚本.ps1
|
$ErrorActionPreference = 'Stop' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 function 取-系统架构标识 { $原始架构 = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } elseif ($env:PROCESSOR_ARCHITECTURE) { $env:PROCESSOR_ARCHITECTURE } else { $null } if ([string]::IsNullOrWhiteSpace($原始架构)) { throw '未能自动检测远程系统架构。' } switch ($原始架构.ToUpperInvariant()) { 'AMD64' { return 'win32-x64' } 'X64' { return 'win32-x64' } 'ARM64' { return 'win32-arm64' } default { throw ('暂不支持的远程系统架构: {0}' -f $原始架构) } } } function 取-安装目录 { param( [string]$通道, [string]$版本提交号 ) $安装根目录 = if ($通道 -eq 'insider') { Join-Path $HOME '.vscode-server-insiders\bin' } else { Join-Path $HOME '.vscode-server\bin' } return Join-Path $安装根目录 $版本提交号 } function 取-下载地址 { param( [string]$通道, [string]$版本提交号, [string]$架构 ) $文件名 = 'vscode-server-{0}.zip' -f $架构 return 'https://vscode.download.prss.microsoft.com/dbazure/download/{0}/{1}/{2}' -f $通道, $版本提交号, $文件名 } function 停止-占用安装目录的进程 { param( [string]$安装目录, [string]$版本提交号 ) $进程列表 = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object { ($_.ExecutablePath -and $_.ExecutablePath.StartsWith($安装目录, [System.StringComparison]::OrdinalIgnoreCase)) -or ($_.CommandLine -and $_.CommandLine -like ('*' + $版本提交号 + '*')) } foreach ($进程 in $进程列表) { try { Stop-Process -Id $进程.ProcessId -Force -ErrorAction SilentlyContinue } catch { } } } function 取-BITS任务 { param( [string]$任务名称, [string]$目标路径 ) return Get-BitsTransfer -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -eq $任务名称 -or $_.Destination -eq $目标路径 } | Select-Object -First 1 } function 等待-BITS任务完成 { param( [string]$任务名称, [string]$目标路径, [int]$等待秒数 ) $已恢复次数 = 0 while ($true) { $当前任务 = 取-BITS任务 -任务名称 $任务名称 -目标路径 $目标路径 if ($null -eq $当前任务) { if (Test-Path $目标路径) { return } throw '未找到正在执行的 BITS 下载任务。' } $当前状态 = [string]$当前任务.JobState $总字节数 = [uint64]$当前任务.BytesTotal $已传字节数 = [uint64]$当前任务.BytesTransferred $总大小未知 = ($总字节数 -eq [uint64]::MaxValue) $当前进度 = if ((-not $总大小未知) -and $总字节数 -gt 0) { [math]::Round(($已传字节数 * 100.0) / $总字节数, 1) } else { 0 } $总字节显示 = if ($总大小未知) { '未知' } else { [string]$总字节数 } Write-Host ('状态: {0} | 进度: {1}% | {2} / {3} 字节' -f $当前状态, $当前进度, $已传字节数, $总字节显示) if ($当前状态 -eq 'Transferred') { Complete-BitsTransfer -BitsJob $当前任务 return } if ($当前状态 -eq 'TransientError' -or $当前状态 -eq 'Error') { $已恢复次数++ Write-Host ('检测到传输中断,开始第 {0} 次恢复。' -f $已恢复次数) Resume-BitsTransfer -BitsJob $当前任务 -Asynchronous } Start-Sleep -Seconds $等待秒数 } } function 展开-服务器压缩包 { param( [string]$压缩包路径, [string]$目标目录 ) Expand-Archive -Path $压缩包路径 -DestinationPath $目标目录 -Force $目录项列表 = @(Get-ChildItem -Force $目标目录) if ($目录项列表.Count -eq 1 -and $目录项列表[0].PSIsContainer) { $内层目录 = $目录项列表[0] Get-ChildItem -Force $内层目录.FullName | Move-Item -Destination $目标目录 -Force Remove-Item $内层目录.FullName -Recurse -Force } $包装目录 = Get-ChildItem -Force $目标目录 -Directory | Where-Object { $_.Name -like 'vscode-server-*' } | Select-Object -First 1 if ($null -ne $包装目录) { foreach ($包装目录项 in (Get-ChildItem -Force $包装目录.FullName)) { $目标路径 = Join-Path $目标目录 $包装目录项.Name if (-not (Test-Path $目标路径)) { Move-Item $包装目录项.FullName -Destination $目标目录 -Force } } Remove-Item $包装目录.FullName -Recurse -Force } Remove-Item $压缩包路径 -Force -ErrorAction SilentlyContinue } $提交号 = '__提交号__' $发布通道 = '__发布通道__' $轮询秒数 = [int]'__轮询秒数__' $系统架构 = 取-系统架构标识 $最终安装目录 = 取-安装目录 -通道 $发布通道 -版本提交号 $提交号 $压缩包路径 = Join-Path $最终安装目录 'vscode-server.zip' $下载地址 = 取-下载地址 -通道 $发布通道 -版本提交号 $提交号 -架构 $系统架构 $任务名称 = 'VSCode远程服务-' + $提交号 Write-Host ('准备安装 VS Code 远程服务,提交号: {0}' -f $提交号) Write-Host ('发布通道: {0}' -f $发布通道) Write-Host ('自动检测到的系统架构: {0}' -f $系统架构) Write-Host ('自动检测到的安装目录: {0}' -f $最终安装目录) Write-Host ('下载地址: {0}' -f $下载地址) 停止-占用安装目录的进程 -安装目录 $最终安装目录 -版本提交号 $提交号 if (Test-Path $最终安装目录) { Remove-Item $最终安装目录 -Recurse -Force -ErrorAction SilentlyContinue } New-Item -ItemType Directory -Force $最终安装目录 | Out-Null Start-Service BITS -ErrorAction SilentlyContinue $旧任务 = 取-BITS任务 -任务名称 $任务名称 -目标路径 $压缩包路径 if ($null -ne $旧任务) { Remove-BitsTransfer -BitsJob $旧任务 -Confirm:$false -ErrorAction SilentlyContinue } Write-Host '开始通过 BITS 下载压缩包。' Start-BitsTransfer -Source $下载地址 -Destination $压缩包路径 -DisplayName $任务名称 -Asynchronous | Out-Null $新任务 = $null for ($序号 = 0; $序号 -lt 10; $序号++) { $新任务 = 取-BITS任务 -任务名称 $任务名称 -目标路径 $压缩包路径 if ($null -ne $新任务) { break } Start-Sleep -Seconds 1 } if ($null -eq $新任务) { throw '已发起下载,但未找到新建的 BITS 任务。' } 等待-BITS任务完成 -任务名称 $任务名称 -目标路径 $压缩包路径 -等待秒数 $轮询秒数 if (-not (Test-Path $压缩包路径)) { throw ('下载完成后未找到压缩包: {0}' -f $压缩包路径) } Write-Host '下载完成,开始解压。' 展开-服务器压缩包 -压缩包路径 $压缩包路径 -目标目录 $最终安装目录 Write-Host '安装完成,当前目录内容如下。' Get-ChildItem -Force $最终安装目录 | Select-Object Name, Length, Mode | Format-Table -AutoSize |