# Install or update CST-Agent on Windows from a Gitea release. # # irm https://git.whcself.xyz/WHC/CST-agent/raw/branch/main/scripts/install_windows.ps1 | iex # powershell -ExecutionPolicy Bypass -File install_windows.ps1 [-Version 0.6.0] [-Prefix DIR] [-Zip FILE] [-NoPath] # # Installs into %LOCALAPPDATA%\Programs\cst-agent (no admin rights needed), # adds it to the user PATH and leaves cst-agent-update.cmd beside the exe, # which reruns this script for that folder. Environment overrides: # CST_VERSION, CST_PREFIX, CST_GITEA (server URL), CST_REPO (owner/name). # Needs Windows 10 1903+ / Server 2022+ (UTF-8 process code page). # Keep this file ASCII: Windows PowerShell 5.1 reads BOM-less scripts in the # ANSI code page. param( [string]$Version = $env:CST_VERSION, [string]$Prefix = $env:CST_PREFIX, [string]$Zip = "", [switch]$NoPath ) $ErrorActionPreference = "Stop" $ProgressPreference = "SilentlyContinue" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $Server = if ($env:CST_GITEA) { $env:CST_GITEA.TrimEnd("/") } else { "https://git.whcself.xyz" } $Repo = if ($env:CST_REPO) { $env:CST_REPO } else { "WHC/CST-agent" } if (-not $Prefix) { $Prefix = Join-Path $env:LOCALAPPDATA "Programs\cst-agent" } $Prefix = [IO.Path]::GetFullPath($Prefix) $build = [Environment]::OSVersion.Version.Build if ($build -lt 18362) { throw "CST-Agent needs Windows 10 1903 (build 18362) or newer; this is build $build." } $work = Join-Path ([IO.Path]::GetTempPath()) ("cst-agent-install-" + [Guid]::NewGuid().ToString("N")) New-Item -ItemType Directory -Force $work | Out-Null try { if (-not $Zip) { $api = "$Server/api/v1/repos/$Repo/releases" $url = if (-not $Version -or $Version -eq "latest") { "$api/latest" } else { "$api/tags/v$($Version.TrimStart('v'))" } Write-Host "==> $url" try { $rel = Invoke-RestMethod -Uri $url -UseBasicParsing } catch { throw "no release found at $url ($($_.Exception.Message))" } $asset = $rel.assets | Where-Object { $_.name -like "*-windows-x86_64.zip" } | Select-Object -First 1 if (-not $asset) { throw "release $($rel.tag_name) has no *-windows-x86_64.zip" } $Zip = Join-Path $work $asset.name Write-Host "==> download $($asset.name) ($($rel.tag_name))" Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $Zip -UseBasicParsing $sum = $rel.assets | Where-Object { $_.name -eq "$($asset.name).sha256" } | Select-Object -First 1 if ($sum) { $sumFile = Join-Path $work $sum.name Invoke-WebRequest -Uri $sum.browser_download_url -OutFile $sumFile -UseBasicParsing $want = ((Get-Content $sumFile -Raw).Trim() -split "\s+")[0].ToLower() $got = (Get-FileHash -Algorithm SHA256 $Zip).Hash.ToLower() if ($want -ne $got) { throw "sha256 mismatch for $($asset.name): expected $want, got $got" } Write-Host "==> sha256 ok" } } Expand-Archive -Path $Zip -DestinationPath $work -Force $src = Join-Path $work "windows-x86_64" if (-not (Test-Path (Join-Path $src "cst-agent.exe"))) { throw "$Zip has no windows-x86_64\cst-agent.exe" } New-Item -ItemType Directory -Force $Prefix | Out-Null # A running exe cannot be overwritten but can be renamed out of the way. foreach ($name in @("cst-agent.exe", "busybox.exe")) { $dst = Join-Path $Prefix $name $old = "$dst.old" if (Test-Path $old) { Remove-Item -Force $old -ErrorAction SilentlyContinue } if (Test-Path $dst) { try { Remove-Item -Force $dst } catch { Rename-Item -Force $dst "$name.old" } } } Copy-Item -Force -Recurse (Join-Path $src "*") $Prefix $update = Join-Path $Prefix "cst-agent-update.cmd" if (-not (Test-Path $update)) { Set-Content -Encoding Ascii -Path $update -Value @( "@echo off", "rem Update CST-Agent in this folder from the latest release.", "powershell -NoProfile -ExecutionPolicy Bypass -File `"%~dp0install_windows.ps1`" -Prefix `"%~dp0.`" %*" ) } if (-not (Test-Path (Join-Path $Prefix "install_windows.ps1")) -and $PSCommandPath) { Copy-Item -Force $PSCommandPath (Join-Path $Prefix "install_windows.ps1") } if (-not $NoPath) { $userPath = [Environment]::GetEnvironmentVariable("Path", "User") $parts = @($userPath -split ";" | Where-Object { $_ }) if (-not ($parts | Where-Object { $_.TrimEnd("\") -ieq $Prefix.TrimEnd("\") })) { [Environment]::SetEnvironmentVariable("Path", (($parts + $Prefix) -join ";"), "User") Write-Host "==> added $Prefix to the user PATH (open a new terminal to use it)" } if (-not (($env:Path -split ";") | Where-Object { $_.TrimEnd("\") -ieq $Prefix.TrimEnd("\") })) { $env:Path = "$env:Path;$Prefix" } } $ver = (& (Join-Path $Prefix "cst-agent.exe") --version) 2>&1 | Select-Object -First 1 Write-Host "==> installed $ver in $Prefix" Write-Host "Run 'cst-agent' inside a project folder; update later with 'cst-agent-update'." } finally { Remove-Item -Recurse -Force $work -ErrorAction SilentlyContinue }