Skip to content

Instantly share code, notes, and snippets.

@davidvasandani
Created January 9, 2026 20:47
Show Gist options
  • Select an option

  • Save davidvasandani/382fe536f85cb7e874ed143b24883c6d to your computer and use it in GitHub Desktop.

Select an option

Save davidvasandani/382fe536f85cb7e874ed143b24883c6d to your computer and use it in GitHub Desktop.
#Requires -RunAsAdministrator
<#
.SYNOPSIS
Complete Development Environment Setup for Windows
.DESCRIPTION
Installs and configures all development tools needed for Claude Code development:
- Scoop package manager
- Node.js LTS
- Git with git-bash
- VS Code
- Claude Code CLI
All tools are installed to user space and configured automatically.
.PARAMETER TargetUser
Username for installation (default: Administrator)
Useful when running remotely via incus exec where env vars aren't set
.NOTES
Author: Generated with Claude Code
Version: 2.0
- Fixed Unicode encoding issues for remote execution
- Added -RunAsAdmin support for elevated sessions
- Handles missing USERNAME/USERPROFILE environment variables
#>
param(
[string]$TargetUser = "Administrator",
[switch]$SkipVSCode,
[switch]$SkipContextMenu
)
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
# Color output functions
function Write-Success { param($Message) Write-Host "[OK] $Message" -ForegroundColor Green }
function Write-Info { param($Message) Write-Host "[INFO] $Message" -ForegroundColor Cyan }
function Write-ScriptWarning { param($Message) Write-Host "[WARN] $Message" -ForegroundColor Yellow }
function Write-ScriptError { param($Message) Write-Host "[ERROR] $Message" -ForegroundColor Red }
# Banner
Write-Host ""
Write-Host "=======================================================" -ForegroundColor Magenta
Write-Host " Development Environment Setup for Windows" -ForegroundColor Magenta
Write-Host "=======================================================" -ForegroundColor Magenta
Write-Host ""
# Check if running as admin
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-ScriptWarning "This script should be run as Administrator for best results"
Write-Info "Continuing anyway, but some features may not work..."
}
# Set up working directory
# When running via incus exec, env vars may not be set, so use TargetUser parameter
$WorkDir = "C:\Users\$TargetUser\code"
Write-Info "Setting up working directory for user: $TargetUser"
Write-Info "Working directory: $WorkDir"
if (-not (Test-Path $WorkDir)) {
New-Item -ItemType Directory -Path $WorkDir -Force | Out-Null
Write-Success "Created working directory"
} else {
Write-Success "Working directory exists"
}
Set-Location $WorkDir
# Fix PATH permanently for Scoop prerequisites (Robocopy)
Write-Info "Configuring system PATH for development tools..."
$currentUserPath = [Environment]::GetEnvironmentVariable('Path', 'User')
$systemPaths = "C:\Windows\System32;C:\Windows\System32\WindowsPowerShell\v1.0"
# Only add System32 to User PATH if not already present
if ($currentUserPath -notlike "*Windows\System32*") {
[Environment]::SetEnvironmentVariable('Path', "$systemPaths;$currentUserPath", 'User')
Write-Success "Added Windows System32 to PATH"
}
# Reload PATH for current session
$env:PATH = [Environment]::GetEnvironmentVariable('Path', 'User') + ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine')
Write-Host ""
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
Write-Host "STEP 1: Installing Scoop Package Manager" -ForegroundColor Yellow
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
if (Get-Command scoop -ErrorAction SilentlyContinue) {
Write-Success "Scoop is already installed"
scoop update
} else {
Write-Info "Setting PowerShell execution policy..."
try {
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force -ErrorAction Stop
Write-Success "Execution policy set"
} catch {
Write-Info "Execution policy already configured (this is fine)"
}
Write-Info "Downloading Scoop installer..."
try {
# Download installer as recommended by Scoop docs
# https://github.com/ScoopInstaller/Install#for-admin
Invoke-RestMethod get.scoop.sh -outfile "$WorkDir\install.ps1"
Write-Info "Installing Scoop..."
# Use -RunAsAdmin flag if running as Administrator
if ($isAdmin) {
Write-Info "Running as Administrator - using -RunAsAdmin flag"
& "$WorkDir\install.ps1" -RunAsAdmin
} else {
Write-Info "Running as regular user"
& "$WorkDir\install.ps1"
}
# Reload PATH after installation
$env:PATH = [Environment]::GetEnvironmentVariable('Path', 'User') + ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine')
# Verify Scoop installed
if (Get-Command scoop -ErrorAction SilentlyContinue) {
Write-Success "Scoop installed successfully"
} else {
Write-ScriptError "Scoop installation failed - command not found"
Write-Info "Check the Scoop installation log above for details"
exit 1
}
} catch {
Write-ScriptError "Failed to install Scoop: $_"
exit 1
}
}
# Reload PATH to include Scoop
$env:PATH = [Environment]::GetEnvironmentVariable('Path', 'User') + ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine')
Write-Host ""
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
Write-Host "STEP 2: Installing Node.js LTS" -ForegroundColor Yellow
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
if (Get-Command node -ErrorAction SilentlyContinue) {
$nodeVersion = node --version
Write-Success "Node.js is already installed: $nodeVersion"
} else {
Write-Info "Installing Node.js via Scoop..."
scoop install nodejs-lts
Write-Success "Node.js installed successfully"
}
# Reload PATH
$env:PATH = [Environment]::GetEnvironmentVariable('Path', 'User') + ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine')
Write-Host ""
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
Write-Host "STEP 3: Installing Git with git-bash" -ForegroundColor Yellow
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
if (Get-Command git -ErrorAction SilentlyContinue) {
$gitVersion = git --version
Write-Success "Git is already installed: $gitVersion"
} else {
Write-Info "Installing Git via Scoop..."
scoop install git
Write-Success "Git installed successfully"
}
# Reload PATH
$env:PATH = [Environment]::GetEnvironmentVariable('Path', 'User') + ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine')
Write-Host ""
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
Write-Host "STEP 4: Installing Claude Code CLI" -ForegroundColor Yellow
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
if (Get-Command claude -ErrorAction SilentlyContinue) {
Write-Success "Claude Code is already installed"
} else {
Write-Info "Installing Claude Code via npm..."
npm install -g @anthropic-ai/claude-code
Write-Success "Claude Code installed successfully"
}
# Set Claude Code Git Bash path
Write-Info "Configuring Claude Code environment..."
# Detect git-bash location dynamically (supports both user and admin Scoop installations)
$userProfilePath = "C:\Users\$TargetUser"
$possiblePaths = @(
"$userProfilePath\scoop\apps\git\current\bin\bash.exe",
"$userProfilePath\scoop\apps\git\current\usr\bin\bash.exe",
"C:\scoop\apps\git\current\bin\bash.exe",
"C:\scoop\apps\git\current\usr\bin\bash.exe"
)
$gitBashPath = $possiblePaths | Where-Object { Test-Path $_ } | Select-Object -First 1
if ($gitBashPath) {
[Environment]::SetEnvironmentVariable('CLAUDE_CODE_GIT_BASH_PATH', $gitBashPath, 'User')
$env:CLAUDE_CODE_GIT_BASH_PATH = $gitBashPath
Write-Success "CLAUDE_CODE_GIT_BASH_PATH configured: $gitBashPath"
} else {
Write-ScriptWarning "Could not find git-bash. Claude Code may not work correctly."
Write-Info "You can manually set CLAUDE_CODE_GIT_BASH_PATH environment variable later"
}
if (-not $SkipVSCode) {
Write-Host ""
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
Write-Host "STEP 5: Installing VS Code" -ForegroundColor Yellow
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
if (Get-Command code -ErrorAction SilentlyContinue) {
Write-Success "VS Code is already installed"
} else {
Write-Info "Adding extras bucket..."
try {
scoop bucket add extras 2>&1 | Out-Null
Write-Success "Extras bucket added"
} catch {
# Bucket already exists, continue
Write-Info "Extras bucket already exists"
}
Write-Info "Installing VS Code via Scoop..."
scoop install vscode
Write-Success "VS Code installed successfully"
}
# Reload PATH
$env:PATH = [Environment]::GetEnvironmentVariable('Path', 'User') + ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine')
if (-not $SkipContextMenu) {
Write-Info "Adding VS Code context menu integration..."
# Detect VS Code installation path (user or system scope)
$vscodeRegPaths = @(
"$userProfilePath\scoop\apps\vscode\current",
"C:\scoop\apps\vscode\current"
)
$vscodeRegPath = $vscodeRegPaths | Where-Object { Test-Path $_ } | Select-Object -First 1
if ($vscodeRegPath) {
try {
reg import "$vscodeRegPath\install-context.reg" 2>&1 | Out-Null
Write-Success "Context menu integration added"
reg import "$vscodeRegPath\install-associations.reg" 2>&1 | Out-Null
Write-Success "File associations added"
reg import "$vscodeRegPath\install-github-integration.reg" 2>&1 | Out-Null
Write-Success "GitHub integration added"
} catch {
Write-ScriptWarning "Could not add VS Code integrations: $_"
}
} else {
Write-ScriptWarning "VS Code registry files not found, skipping context menu integration"
}
}
}
Write-Host ""
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
Write-Host "STEP 6: Creating PowerShell Profile" -ForegroundColor Yellow
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
# Construct target user's PowerShell profile path
$targetProfilePath = "$userProfilePath\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"
$profileDir = Split-Path $targetProfilePath -Parent
if (-not (Test-Path $profileDir)) {
New-Item -ItemType Directory -Path $profileDir -Force | Out-Null
}
$profileContent = @'
# PowerShell Profile - Auto-generated by setup-dev-environment.ps1
# Load Scoop environment
$env:PATH = [Environment]::GetEnvironmentVariable('Path', 'User') + ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine')
# Load Claude Code Git Bash path
$env:CLAUDE_CODE_GIT_BASH_PATH = [Environment]::GetEnvironmentVariable('CLAUDE_CODE_GIT_BASH_PATH', 'User')
Write-Host "Development environment loaded!" -ForegroundColor Green
Write-Host ""
Write-Host "Available tools:" -ForegroundColor Cyan
Write-Host " scoop - package manager"
Write-Host " node - $(node --version 2>$null)"
Write-Host " npm - v$(npm --version 2>$null)"
Write-Host " git - $(git --version 2>$null)"
Write-Host " claude - $(claude --version 2>$null | Select-Object -First 1)"
if (Get-Command code -ErrorAction SilentlyContinue) {
Write-Host " code - VS Code $(code --version 2>$null | Select-Object -First 1)"
}
Write-Host ""
'@
Set-Content -Path $targetProfilePath -Value $profileContent -Force
Write-Success "PowerShell profile created at: $targetProfilePath"
Write-Host ""
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
Write-Host "STEP 7: Creating Desktop Shortcut" -ForegroundColor Yellow
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
$desktopShortcut = @"
@echo off
echo ============================================
echo Starting Development Environment
echo ============================================
echo.
cd $WorkDir
powershell.exe -NoExit -ExecutionPolicy Bypass -File "$targetProfilePath"
"@
# Construct target user's desktop path
$desktopPath = "$userProfilePath\Desktop"
Set-Content -Path "$desktopPath\Start-DevTools.bat" -Value $desktopShortcut -Force
Write-Success "Desktop shortcut created at: $desktopPath\Start-DevTools.bat"
Write-Host ""
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
Write-Host "STEP 8: Verification" -ForegroundColor Yellow
Write-Host "-------------------------------------------------------" -ForegroundColor Gray
# Reload environment one more time
$env:PATH = [Environment]::GetEnvironmentVariable('Path', 'User') + ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine')
$env:CLAUDE_CODE_GIT_BASH_PATH = [Environment]::GetEnvironmentVariable('CLAUDE_CODE_GIT_BASH_PATH', 'User')
Write-Host ""
Write-Host "Installed Versions:" -ForegroundColor Cyan
try {
$scoopVer = (scoop --version | Select-Object -First 1)
Write-Host " Scoop: $scoopVer" -ForegroundColor White
} catch { Write-ScriptWarning " Scoop: Not found" }
try {
$nodeVer = node --version
Write-Host " Node: $nodeVer" -ForegroundColor White
} catch { Write-ScriptWarning " Node: Not found" }
try {
$npmVer = npm --version
Write-Host " npm: v$npmVer" -ForegroundColor White
} catch { Write-ScriptWarning " npm: Not found" }
try {
$gitVer = git --version
Write-Host " Git: $gitVer" -ForegroundColor White
} catch { Write-ScriptWarning " Git: Not found" }
try {
$claudeVer = claude --version 2>&1 | Select-Object -First 1
Write-Host " Claude: $claudeVer" -ForegroundColor White
} catch { Write-ScriptWarning " Claude: Not found" }
if (-not $SkipVSCode) {
try {
$codeVer = code --version | Select-Object -First 1
Write-Host " VS Code: $codeVer" -ForegroundColor White
} catch { Write-ScriptWarning " VS Code: Not found" }
}
Write-Host ""
Write-Host "=======================================================" -ForegroundColor Green
Write-Host " Installation Complete!" -ForegroundColor Green
Write-Host "=======================================================" -ForegroundColor Green
Write-Host ""
Write-Host "Next steps:" -ForegroundColor Yellow
Write-Host " 1. Close and reopen PowerShell (or use the Desktop shortcut)"
Write-Host " 2. Run 'claude' to configure your Anthropic API key"
Write-Host " 3. Start coding with AI assistance!"
Write-Host ""
Write-Host "Documentation: $WorkDir\README.md" -ForegroundColor Cyan
Write-Host ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment