$ErrorActionPreference = "Stop" $InstallDir = Join-Path $env:ProgramData "cs2clip-worker" $BaseUrl = "https://cli.n1cetry.com" function Read-InstallPassword { $secure = Read-Host "Install password" -AsSecureString $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure) try { return [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr) } finally { if ($ptr -ne [IntPtr]::Zero) { [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ptr) } } } function Get-StatusCode { param($ErrorRecord) try { return [int]$ErrorRecord.Exception.Response.StatusCode } catch { return $null } } function Invoke-InstallApi { param( [string]$Path, [string]$Password, [string]$Method = "GET", [string]$OutFile ) $headers = @{ "X-Install-Password" = $Password "User-Agent" = "cs2clip-worker-installer" } try { if ($OutFile) { Invoke-WebRequest -Method $Method -Headers $headers -Uri ($BaseUrl + $Path) -OutFile $OutFile | Out-Null return } return Invoke-RestMethod -Method $Method -Headers $headers -Uri ($BaseUrl + $Path) } catch { $status = Get-StatusCode $_ if ($status -eq 401) { throw "Install password rejected." } throw } } $password = Read-InstallPassword $meta = Invoke-InstallApi -Path "/api/latest" -Password $password Write-Host ("Installing " + $meta.assetName + " (" + $meta.tagName + ") to " + $InstallDir) New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null $existing = Get-Process -Name "cs2clip-worker" -ErrorAction SilentlyContinue if ($existing) { Write-Host "Stopping existing cs2clip-worker process" $existing | Stop-Process -Force Start-Sleep -Seconds 1 } $tmpPath = Join-Path $InstallDir ($meta.assetName + ".download") $assetPath = Join-Path $InstallDir $meta.assetName $exePath = Join-Path $InstallDir "cs2clip-worker.exe" Invoke-InstallApi -Path $meta.downloadPath -Password $password -OutFile $tmpPath if ($meta.sha256) { $actualHash = (Get-FileHash -Path $tmpPath -Algorithm SHA256).Hash.ToLowerInvariant() $expectedHash = [string]$meta.sha256 if ($actualHash -ne $expectedHash.ToLowerInvariant()) { Remove-Item -Path $tmpPath -Force -ErrorAction SilentlyContinue throw ("Downloaded worker checksum mismatch. Expected " + $expectedHash + ", got " + $actualHash) } } if (-not ([string]$meta.assetName -match "\.zip$")) { Remove-Item -Path $tmpPath -Force -ErrorAction SilentlyContinue throw "Install gateway requires a zip worker asset." } $extractDir = Join-Path $InstallDir "extract" Remove-Item -Path $extractDir -Recurse -Force -ErrorAction SilentlyContinue Move-Item -Path $tmpPath -Destination $assetPath -Force Expand-Archive -Path $assetPath -DestinationPath $extractDir -Force $archiveExe = Get-ChildItem -Path $extractDir -Recurse -Filter "cs2clip-worker.exe" | Select-Object -First 1 if (-not $archiveExe) { Remove-Item -Path $assetPath -Force -ErrorAction SilentlyContinue Remove-Item -Path $extractDir -Recurse -Force -ErrorAction SilentlyContinue throw "Downloaded archive did not contain cs2clip-worker.exe." } Remove-Item -Path $exePath -Force -ErrorAction SilentlyContinue Remove-Item -Path (Join-Path $InstallDir "node_modules") -Recurse -Force -ErrorAction SilentlyContinue Get-ChildItem -Path $extractDir -Force | ForEach-Object { Move-Item -Path $_.FullName -Destination (Join-Path $InstallDir $_.Name) -Force } Remove-Item -Path $assetPath -Force -ErrorAction SilentlyContinue Remove-Item -Path $extractDir -Recurse -Force -ErrorAction SilentlyContinue Write-Host "Worker downloaded and installed. It was not started automatically." Write-Host ("Worker path: " + $exePath) Write-Host ("Start it manually in an interactive Windows session:") Write-Host (' Start-Process -FilePath "' + $exePath + '" -WorkingDirectory "' + $InstallDir + '"') Write-Host ("Logs directory: " + (Join-Path $InstallDir "out\observability"))