Last active
June 12, 2026 21:38
-
-
Save joegasper/4b7fa95cf445b2a01dcf275ea9d15dc9 to your computer and use it in GitHub Desktop.
OpenCode installation on Windows without local administrator rights
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| Bootstraps a fully user-scoped (non-admin) Node.js + npm environment and installs OpenCode. | |
| .DESCRIPTION | |
| This script downloads the latest Node.js LTS Windows x64 ZIP and extracts it into a | |
| shortened version-based directory (e.g., node_v24) under the user's LOCALAPPDATA. | |
| It then: | |
| - Configures user-level PATH to include Node.js and npm global binaries | |
| - Redirects npm global installs to a user-writable AppData path | |
| - Installs the OpenCode CLI globally via npm (without requiring admin rights) | |
| - Leaves the system in a clean, portable, non-admin configuration | |
| KEY POINTS | |
| - No administrator privileges required at any step | |
| - Uses ZIP distribution instead of MSI to avoid Program Files | |
| - Keeps Node install path short and version-based (e.g., node_v24) | |
| - Ensures npm global installs are isolated to user profile | |
| POST-SETUP | |
| User must restart their terminal session for PATH updates to take effect. | |
| #> | |
| # --- CONFIG --- | |
| $baseDir = "$env:LOCALAPPDATA\nodejs" | |
| $tmpZip = "$env:TEMP\node-lts.zip" | |
| $nodeApi = "https://nodejs.org/dist/index.json" | |
| Write-Output '==> Getting latest Node.js LTS version...' | |
| # Fetch Node release list and pick latest LTS | |
| $nodeIndex = Invoke-RestMethod $nodeApi | |
| $ltsVersion = ($nodeIndex | Where-Object { $_.lts -ne $false } | Select-Object -First 1).version | |
| # Normalize names | |
| $versionClean = $ltsVersion.TrimStart("v") | |
| $majorVersion = $versionClean.Split(".")[0] | |
| $shortFolder = "node_v$majorVersion" | |
| $installDir = Join-Path $baseDir $shortFolder | |
| # Build download URL | |
| $zipName = "node-$ltsVersion-win-x64.zip" | |
| $downloadUrl = "https://nodejs.org/dist/$ltsVersion/$zipName" | |
| Write-Output "==> Latest LTS: $ltsVersion" | |
| Write-Output "==> Downloading: $downloadUrl" | |
| # Prepare dirs | |
| New-Item -ItemType Directory -Force -Path $baseDir | Out-Null | |
| # Download ZIP | |
| Invoke-WebRequest -Uri $downloadUrl -OutFile $tmpZip | |
| Unblock-File $tmpZip | |
| Write-Output '==> Extracting...' | |
| # Extract | |
| Expand-Archive $tmpZip -DestinationPath $baseDir -Force | |
| # Rename extracted folder to short name | |
| $extractedPath = Join-Path $baseDir ("node-$ltsVersion-win-x64") | |
| if (Test-Path $installDir) { | |
| Remove-Item -Recurse -Force $installDir | |
| } | |
| Rename-Item -Path $extractedPath -NewName $shortFolder | |
| # Cleanup zip | |
| Remove-Item $tmpZip -Force | |
| Write-Output '==> Setting user PATH...' | |
| # Add Node + npm global bin to PATH | |
| $npmDir = "$env:LOCALAPPDATA\npm" | |
| $newPath = "$installDir;$npmDir;$env:PATH" | |
| setx PATH $newPath | Out-Null | |
| Write-Output '==> Configuring npm prefix...' | |
| # Use full path to npm (since PATH not active yet) | |
| $npmExe = Join-Path $installDir "npm.cmd" | |
| & $npmExe config set prefix $npmDir | |
| Write-Output '==> Installing OpenCode...' | |
| & $npmExe install -g opencode-ai | |
| Write-Output '' | |
| Write-Output '✅ DONE' | |
| Write-Output '' | |
| Write-Output 'IMPORTANT: Restart your terminal before using opencode.' | |
| Write-Output '' | |
| Write-Output 'After terminal restart, test with:' | |
| Write-Output ' node -v' | |
| Write-Output ' npm -v' | |
| Write-Output ' opencode --version' | |
| Write-Output '' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment