mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
fix: handle PowerShell execution policy on Windows install (#24794)
* fix: add Arch Linux support to install.sh (GH#8051) * fix: handle PowerShell execution policy on Windows install (GH#24784)
This commit is contained in:
329
scripts/install.ps1
Normal file
329
scripts/install.ps1
Normal file
@@ -0,0 +1,329 @@
|
||||
# OpenClaw Installer for Windows (PowerShell)
|
||||
# Usage: iwr -useb https://openclaw.ai/install.ps1 | iex
|
||||
# Or: & ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard
|
||||
|
||||
param(
|
||||
[string]$InstallMethod = "npm",
|
||||
[string]$Tag = "latest",
|
||||
[string]$GitDir = "$env:USERPROFILE\openclaw",
|
||||
[switch]$NoOnboard,
|
||||
[switch]$NoGitUpdate,
|
||||
[switch]$DryRun
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Colors
|
||||
$ACCENT = "`e[38;2;255;77;77m" # coral-bright
|
||||
$SUCCESS = "`e[38;2;0;229;204m" # cyan-bright
|
||||
$WARN = "`e[38;2;255;176;32m" # amber
|
||||
$ERROR = "`e[38;2;230;57;70m" # coral-mid
|
||||
$MUTED = "`e[38;2;90;100;128m" # text-muted
|
||||
$NC = "`e[0m" # No Color
|
||||
|
||||
function Write-Host {
|
||||
param([string]$Message, [string]$Level = "info")
|
||||
$msg = switch ($Level) {
|
||||
"success" { "$SUCCESS✓$NC $Message" }
|
||||
"warn" { "$WARN!$NC $Message" }
|
||||
"error" { "$ERROR✗$NC $Message" }
|
||||
default { "$MUTED·$NC $Message" }
|
||||
}
|
||||
Microsoft.PowerShell.Host\Write-Host $msg
|
||||
}
|
||||
|
||||
function Write-Banner {
|
||||
Write-Host ""
|
||||
Write-Host "${ACCENT} 🦞 OpenClaw Installer$NC" -Level info
|
||||
Write-Host "${MUTED} All your chats, one OpenClaw.$NC" -Level info
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
function Get-ExecutionPolicyStatus {
|
||||
$policy = Get-ExecutionPolicy
|
||||
if ($policy -eq "Restricted" -or $policy -eq "AllSigned") {
|
||||
return @{ Blocked = $true; Policy = $policy }
|
||||
}
|
||||
return @{ Blocked = $false; Policy = $policy }
|
||||
}
|
||||
|
||||
function Test-Admin {
|
||||
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
|
||||
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
}
|
||||
|
||||
function Ensure-ExecutionPolicy {
|
||||
$status = Get-ExecutionPolicyStatus
|
||||
if ($status.Blocked) {
|
||||
Write-Host "PowerShell execution policy is set to: $($status.Policy)" -Level warn
|
||||
Write-Host "This prevents scripts like npm.ps1 from running." -Level warn
|
||||
Write-Host ""
|
||||
|
||||
# Try to set execution policy for current process
|
||||
try {
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -ErrorAction Stop
|
||||
Write-Host "Set execution policy to RemoteSigned for current process" -Level success
|
||||
return $true
|
||||
} catch {
|
||||
Write-Host "Could not automatically set execution policy" -Level error
|
||||
Write-Host ""
|
||||
Write-Host "To fix this, run:" -Level info
|
||||
Write-Host " Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process" -Level info
|
||||
Write-Host ""
|
||||
Write-Host "Or run PowerShell as Administrator and execute:" -Level info
|
||||
Write-Host " Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine" -Level info
|
||||
return $false
|
||||
}
|
||||
}
|
||||
return $true
|
||||
}
|
||||
|
||||
function Get-NodeVersion {
|
||||
try {
|
||||
$version = node --version 2>$null
|
||||
if ($version) {
|
||||
return $version -replace '^v', ''
|
||||
}
|
||||
} catch { }
|
||||
return $null
|
||||
}
|
||||
|
||||
function Get-NpmVersion {
|
||||
try {
|
||||
$version = npm --version 2>$null
|
||||
if ($version) {
|
||||
return $version
|
||||
}
|
||||
} catch { }
|
||||
return $null
|
||||
}
|
||||
|
||||
function Install-Node {
|
||||
Write-Host "Node.js not found" -Level info
|
||||
Write-Host "Installing Node.js..." -Level info
|
||||
|
||||
# Try winget first
|
||||
if (Get-Command winget -ErrorAction SilentlyContinue) {
|
||||
Write-Host " Using winget..." -Level info
|
||||
try {
|
||||
winget install OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreements 2>&1 | Out-Null
|
||||
# Refresh PATH
|
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
||||
Write-Host " Node.js installed via winget" -Level success
|
||||
return $true
|
||||
} catch {
|
||||
Write-Host " Winget install failed: $_" -Level warn
|
||||
}
|
||||
}
|
||||
|
||||
# Try chocolatey
|
||||
if (Get-Command choco -ErrorAction SilentlyContinue) {
|
||||
Write-Host " Using chocolatey..." -Level info
|
||||
try {
|
||||
choco install nodejs-lts -y 2>&1 | Out-Null
|
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
||||
Write-Host " Node.js installed via chocolatey" -Level success
|
||||
return $true
|
||||
} catch {
|
||||
Write-Host " Chocolatey install failed: $_" -Level warn
|
||||
}
|
||||
}
|
||||
|
||||
# Try scoop
|
||||
if (Get-Command scoop -ErrorAction SilentlyContinue) {
|
||||
Write-Host " Using scoop..." -Level info
|
||||
try {
|
||||
scoop install nodejs-lts 2>&1 | Out-Null
|
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
||||
Write-Host " Node.js installed via scoop" -Level success
|
||||
return $true
|
||||
} catch {
|
||||
Write-Host " Scoop install failed: $_" -Level warn
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Could not install Node.js automatically" -Level error
|
||||
Write-Host "Please install Node.js 22+ manually from: https://nodejs.org" -Level info
|
||||
return $false
|
||||
}
|
||||
|
||||
function Ensure-Node {
|
||||
$nodeVersion = Get-NodeVersion
|
||||
if ($nodeVersion) {
|
||||
$major = [int]($nodeVersion -split '\.')[0]
|
||||
if ($major -ge 22) {
|
||||
Write-Host "Node.js v$nodeVersion found" -Level success
|
||||
return $true
|
||||
}
|
||||
Write-Host "Node.js v$nodeVersion found, but need v22+" -Level warn
|
||||
}
|
||||
return Install-Node
|
||||
}
|
||||
|
||||
function Get-GitVersion {
|
||||
try {
|
||||
$version = git --version 2>$null
|
||||
if ($version) {
|
||||
return $version
|
||||
}
|
||||
} catch { }
|
||||
return $null
|
||||
}
|
||||
|
||||
function Install-Git {
|
||||
Write-Host "Git not found" -Level info
|
||||
|
||||
if (Get-Command winget -ErrorAction SilentlyContinue) {
|
||||
Write-Host " Installing Git via winget..." -Level info
|
||||
try {
|
||||
winget install Git.Git --accept-package-agreements --accept-source-agreements 2>&1 | Out-Null
|
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
||||
Write-Host " Git installed" -Level success
|
||||
return $true
|
||||
} catch {
|
||||
Write-Host " Winget install failed" -Level warn
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Please install Git for Windows from: https://git-scm.com" -Level error
|
||||
return $false
|
||||
}
|
||||
|
||||
function Ensure-Git {
|
||||
$gitVersion = Get-GitVersion
|
||||
if ($gitVersion) {
|
||||
Write-Host "$gitVersion found" -Level success
|
||||
return $true
|
||||
}
|
||||
return Install-Git
|
||||
}
|
||||
|
||||
function Install-OpenClawNpm {
|
||||
param([string]$Version = "latest")
|
||||
|
||||
Write-Host "Installing OpenClaw (openclaw@$Version)..." -Level info
|
||||
|
||||
try {
|
||||
# Use -ExecutionPolicy Bypass to handle restricted execution policy
|
||||
npm install -g openclaw@$Version --no-fund --no-audit 2>&1
|
||||
Write-Host "OpenClaw installed" -Level success
|
||||
return $true
|
||||
} catch {
|
||||
Write-Host "npm install failed: $_" -Level error
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Install-OpenClawGit {
|
||||
param([string]$RepoDir, [switch]$Update)
|
||||
|
||||
Write-Host "Installing OpenClaw from git..." -Level info
|
||||
|
||||
if (!(Test-Path $RepoDir)) {
|
||||
Write-Host " Cloning repository..." -Level info
|
||||
git clone https://github.com/openclaw/openclaw.git $RepoDir 2>&1
|
||||
} elseif ($Update) {
|
||||
Write-Host " Updating repository..." -Level info
|
||||
git -C $RepoDir pull --rebase 2>&1
|
||||
}
|
||||
|
||||
# Install pnpm if not present
|
||||
if (!(Get-Command pnpm -ErrorAction SilentlyContinue)) {
|
||||
Write-Host " Installing pnpm..." -Level info
|
||||
npm install -g pnpm 2>&1
|
||||
}
|
||||
|
||||
# Install dependencies
|
||||
Write-Host " Installing dependencies..." -Level info
|
||||
pnpm install --dir $RepoDir 2>&1
|
||||
|
||||
# Build
|
||||
Write-Host " Building..." -Level info
|
||||
pnpm --dir $RepoDir build 2>&1
|
||||
|
||||
# Create wrapper
|
||||
$wrapperDir = "$env:USERPROFILE\.local\bin"
|
||||
if (!(Test-Path $wrapperDir)) {
|
||||
New-Item -ItemType Directory -Path $wrapperDir -Force | Out-Null
|
||||
}
|
||||
|
||||
@"
|
||||
@echo off
|
||||
node "%~dp0..\openclaw\dist\entry.js" %*
|
||||
"@ | Out-File -FilePath "$wrapperDir\openclaw.cmd" -Encoding ASCII -Force
|
||||
|
||||
Write-Host "OpenClaw installed" -Level success
|
||||
return $true
|
||||
}
|
||||
|
||||
function Add-ToPath {
|
||||
param([string]$Path)
|
||||
|
||||
$currentPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
||||
if ($currentPath -notlike "*$Path*") {
|
||||
[Environment]::SetEnvironmentVariable("Path", "$currentPath;$Path", "User")
|
||||
Write-Host "Added $Path to user PATH" -Level info
|
||||
}
|
||||
}
|
||||
|
||||
# Main
|
||||
function Main {
|
||||
Write-Banner
|
||||
|
||||
Write-Host "Windows detected" -Level success
|
||||
|
||||
# Check and handle execution policy FIRST, before any npm calls
|
||||
if (!(Ensure-ExecutionPolicy)) {
|
||||
Write-Host ""
|
||||
Write-Host "Installation cannot continue due to execution policy restrictions" -Level error
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (!(Ensure-Node)) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($InstallMethod -eq "git") {
|
||||
if (!(Ensure-Git)) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($DryRun) {
|
||||
Write-Host "[DRY RUN] Would install OpenClaw from git to $GitDir" -Level info
|
||||
} else {
|
||||
Install-OpenClawGit -RepoDir $GitDir -Update:(-not $NoGitUpdate)
|
||||
}
|
||||
} else {
|
||||
# npm method
|
||||
if (!(Ensure-Git)) {
|
||||
Write-Host "Git is required for npm installs. Please install Git and try again." -Level warn
|
||||
}
|
||||
|
||||
if ($DryRun) {
|
||||
Write-Host "[DRY RUN] Would install OpenClaw via npm (tag: $Tag)" -Level info
|
||||
} else {
|
||||
if (!(Install-OpenClawNpm -Version $Tag)) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Try to add npm global bin to PATH
|
||||
try {
|
||||
$npmPrefix = npm config get prefix 2>$null
|
||||
if ($npmPrefix) {
|
||||
Add-ToPath -Path "$npmPrefix"
|
||||
}
|
||||
} catch { }
|
||||
|
||||
if (!$NoOnboard -and !$DryRun) {
|
||||
Write-Host ""
|
||||
Write-Host "Run 'openclaw onboard' to complete setup" -Level info
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "🦞 OpenClaw installed successfully!" -Level success
|
||||
}
|
||||
|
||||
Main
|
||||
2385
scripts/install.sh
Executable file
2385
scripts/install.sh
Executable file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user