# Catenary installer for Windows # https://thecatenary.app/install.ps1 # # irm https://thecatenary.app/install.ps1 | iex # # What this script does, and nothing else: # # 1. Asks GitHub for the latest public release of Catenary # (https://github.com/GioNicolas/catenary-releases). # 2. Downloads Catenary-Setup-.exe and the .sha256 file published # next to it in the same release. # 3. Stops, without running anything, if the SHA-256 of the download does not # match the published one. # 4. Runs the installer. It installs for your user only and never asks for # administrator rights. # 5. Deletes the downloaded files. # # The only network requests are to api.github.com and github.com. No account, # no telemetry, nothing sent anywhere else. # # Because the file is downloaded by PowerShell rather than a browser, Windows # does not attach the "downloaded from the internet" mark to it, so the # SmartScreen prompt for the unsigned installer does not appear. The checksum in # step 3 is what stands in for it. # # You are reading the whole script: this URL serves it as plain text. & { $ErrorActionPreference = 'Stop' # The progress bar makes Invoke-WebRequest many times slower on # Windows PowerShell 5.1. $ProgressPreference = 'SilentlyContinue' [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 $repo = 'GioNicolas/catenary-releases' $headers = @{ 'User-Agent' = 'catenary-install.ps1'; 'Accept' = 'application/vnd.github+json' } Write-Host 'Catenary: looking up the latest release...' $release = Invoke-RestMethod -Uri "https://api.github.com/repos/$repo/releases/latest" -Headers $headers $exe = $release.assets | Where-Object { $_.name -match '^Catenary-Setup-.*\.exe$' } | Select-Object -First 1 if (-not $exe) { throw "No Windows installer found in release $($release.tag_name)." } $sum = $release.assets | Where-Object { $_.name -eq "$($exe.name).sha256" } | Select-Object -First 1 if (-not $sum) { throw "Release $($release.tag_name) publishes no checksum for $($exe.name). Nothing was installed." } $dir = Join-Path ([IO.Path]::GetTempPath()) ('catenary-' + [Guid]::NewGuid().ToString('N')) New-Item -ItemType Directory -Path $dir | Out-Null try { $file = Join-Path $dir $exe.name $sumFile = "$file.sha256" $mb = [Math]::Round($exe.size / 1MB) Write-Host "Catenary: downloading $($exe.name) ($mb MB)..." Invoke-WebRequest -Uri $exe.browser_download_url -OutFile $file -UseBasicParsing Invoke-WebRequest -Uri $sum.browser_download_url -OutFile $sumFile -UseBasicParsing # sha256sum format: " " $expected = ((Get-Content -Path $sumFile -Raw).Trim() -split '\s+')[0].ToLowerInvariant() $actual = (Get-FileHash -Path $file -Algorithm SHA256).Hash.ToLowerInvariant() if ($expected -notmatch '^[0-9a-f]{64}$' -or $actual -ne $expected) { throw "Checksum mismatch for $($exe.name) (expected $expected, got $actual). Nothing was installed." } Write-Host 'Catenary: checksum verified. Running the installer...' $process = Start-Process -FilePath $file -Wait -PassThru if ($process.ExitCode -ne 0) { throw "The installer exited with code $($process.ExitCode)." } Write-Host "Catenary $($release.tag_name) is installed. Find it in the Start menu." } finally { Remove-Item -Path $dir -Recurse -Force -ErrorAction SilentlyContinue } }