Created
July 29, 2026 07:12
-
-
Save mlajtos/138886341335ad4ddbfb034039e39a28 to your computer and use it in GitHub Desktop.
Claude Portable
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
| @echo off | |
| REM ===================================================================== | |
| REM InstallClaude.cmd - run ONCE, on a machine you trust. | |
| REM Downloads + verifies claude.exe, writes an INERT, self-elevating | |
| REM Claude.cmd plus config.txt, a field-IT CLAUDE.md, and a safe-fast | |
| REM settings.json, then opens Claude Code for a one-time login. | |
| REM Everything below the "#PS-PAYLOAD#" line is PowerShell, run by the | |
| REM line just below. cmd never runs it. It is not obfuscated - read it. | |
| REM ===================================================================== | |
| setlocal | |
| set "ROOT=%~dp0" | |
| set "BUCKET=https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases" | |
| md "%ROOT%bin" 2>nul & md "%ROOT%data" 2>nul & md "%ROOT%tmp" 2>nul & md "%ROOT%work" 2>nul | |
| powershell -NoProfile -ExecutionPolicy Bypass -Command "$t=[IO.File]::ReadAllText('%~f0'); iex $t.Substring($t.LastIndexOf([char]10+'#PS-PAYLOAD#'))" || (echo. & echo Install failed - nothing was kept. Run on a trusted machine with internet. & echo. & pause & exit /b 1) | |
| echo. | |
| echo Setup complete. Opening Claude Code so you can log in... | |
| echo After you log in, type /exit , then eject the stick. | |
| echo. | |
| set "CLAUDE_CONFIG_DIR=%ROOT%data" | |
| set "DISABLE_AUTOUPDATER=1" | |
| cd /d "%ROOT%work" | |
| "%ROOT%bin\claude.exe" | |
| exit /b 0 | |
| #PS-PAYLOAD# | |
| $ErrorActionPreference = 'Stop' | |
| $root = $env:ROOT | |
| $bucket = $env:BUCKET | |
| $plat = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { 'win32-arm64' } else { 'win32-x64' } | |
| $exe = Join-Path $root 'bin\claude.exe' | |
| if (-not (Test-Path $exe)) { | |
| Write-Host " Downloading Claude Code ($plat)..." | |
| $ver = (Invoke-WebRequest "$bucket/latest" -UseBasicParsing).Content.Trim() | |
| $want = ((Invoke-WebRequest "$bucket/$ver/manifest.json" -UseBasicParsing).Content | ConvertFrom-Json).platforms.$plat.checksum | |
| Invoke-WebRequest "$bucket/$ver/$plat/claude.exe" -OutFile $exe -UseBasicParsing | |
| if ((Get-FileHash $exe -Algorithm SHA256).Hash.ToLower() -ne $want.ToLower()) { Remove-Item $exe; throw "SHA256 mismatch - aborted." } | |
| $sig = Get-AuthenticodeSignature $exe | |
| if ($sig.Status -ne 'Valid' -or $sig.SignerCertificate.Subject -notlike '*Anthropic*') { Remove-Item $exe; throw "Not signed by Anthropic - aborted." } | |
| Write-Host " Verified claude.exe v$ver - $($sig.SignerCertificate.Subject)" | |
| } else { | |
| Write-Host " claude.exe already present - skipping download." | |
| } | |
| function Write-IfAbsent($path, $text) { | |
| if (Test-Path $path) { Write-Host " kept existing $(Split-Path $path -Leaf)"; return } | |
| [IO.File]::WriteAllText($path, ($text -replace "`r?`n","`r`n"), [Text.Encoding]::ASCII) | |
| Write-Host " wrote $(Split-Path $path -Leaf)" | |
| } | |
| # --- config.txt (optional settings; docs inside the file) --- | |
| Write-IfAbsent (Join-Path $root 'config.txt') @' | |
| # ============================================================ | |
| # Claude Code Portable - config (OPTIONAL) | |
| # ============================================================ | |
| # Read by Claude.cmd at launch. Safe to leave fully commented | |
| # out - browser login needs nothing here. Edit any time. | |
| # Syntax: KEY=value (no spaces around =, no quotes, # = comment) | |
| # ============================================================ | |
| # API-key auth instead of browser login (get one at https://console.anthropic.com/) | |
| #ANTHROPIC_API_KEY=sk-ant-... | |
| # Route through a proxy/gateway. WARNING: sends every request AND your | |
| # credentials to the host you name. Only ever point it somewhere you own. | |
| #ANTHROPIC_BASE_URL=https://your-gateway.example.com | |
| # ------------------------------------------------------------ | |
| # Never run a stick - or a config file - given to you by | |
| # someone else. Both can silently redirect your credentials. | |
| # ------------------------------------------------------------ | |
| '@ | |
| # --- field-IT priming: loaded when Claude.cmd runs from work\ (the default) --- | |
| New-Item -ItemType Directory -Force (Join-Path $root 'work\.claude') | Out-Null | |
| Write-IfAbsent (Join-Path $root 'work\CLAUDE.md') @' | |
| # Windows break-fix technician | |
| You are an on-site Windows repair assistant running from a technician's USB stick. The | |
| technician is at the keyboard and approves actions. Work fast: diagnose, then fix. | |
| ## Rules | |
| - This is Windows. Use PowerShell (and cmd where simpler). Never assume bash / Unix tools. | |
| - Diagnose before you change. State the one-line cause you suspect, then act. | |
| - Prefer reversible fixes. Before disabling or removing anything, say in one line what it is | |
| and what breaks if you are wrong, then let the confirmation prompt do its job. | |
| - Batch read-only checks, then act. Report findings and changes briefly - no essays. | |
| - When done, give a 2-3 line summary of every change, so it can be undone. | |
| ## Do not, without the owner confirming | |
| - Touch business-critical software, its services, licensing, or database. | |
| - Open, copy, or move sensitive data (customer records, databases, personal files). | |
| You fix the machine, not the data on it. | |
| ## Playbooks (run the sequence, stop when fixed, confirm it worked) | |
| ### Printer will not print | |
| 1. Get-Service Spooler -- if stopped, Start-Service Spooler. | |
| 2. Stuck queue: stop Spooler, delete C:\Windows\System32\spool\PRINTERS\*, start Spooler. | |
| 3. Correct default? Get-Printer -- not defaulting to "Microsoft Print to PDF". | |
| 4. Offline flag: check PrinterStatus; clear "Use Printer Offline". | |
| 5. Driver: Get-PrinterDriver -- reinstall with pnputil / Add-PrinterDriver if missing. | |
| 6. Connection: USB replugged, or network printer reachable (Test-Connection <ip>). | |
| 7. Print a Windows test page. | |
| ### "The computer is slow" | |
| 1. Startup bloat: Get-CimInstance Win32_StartupCommand -- disable heavy non-essentials | |
| (confirm each; leave AV and business-critical apps alone). | |
| 2. Disk space: Get-PSDrive C -- if near full: cleanmgr, clear %TEMP%, empty Recycle Bin. | |
| 3. Resource hogs: Get-Process | Sort CPU -Descending | Select -First 10. | |
| 4. Pending reboot or a stuck update thrashing the disk -- reboot if so. | |
| 5. Malware check: Start-MpScan -ScanType QuickScan (Defender); review. | |
| 6. Browser toolbars / excess extensions -- remove with consent. | |
| 7. If it is a spinning HDD and thrashing, note that an SSD is the real fix. | |
| ### No internet | |
| 1. Get-NetAdapter (up?) and ipconfig /all (IP + gateway?). | |
| 2. Test-Connection 1.1.1.1 vs Test-Connection google.com to isolate DNS. | |
| 3. Clear-DnsClientCache; set a working resolver if theirs is dead. | |
| 4. ipconfig /release then /renew. If needed: netsh winsock reset (reboot after). | |
| 5. Adapter driver / Wi-Fi radio / cable as applicable. | |
| ### Unknown error | |
| Read the message verbatim, search the exact text, apply the known fix, verify. | |
| '@ | |
| # --- safe-fast permissions: read-only triage silent, changes still prompt --- | |
| Write-IfAbsent (Join-Path $root 'work\.claude\settings.json') @' | |
| { | |
| "$schema": "https://json.schemastore.org/claude-code-settings.json", | |
| "permissions": { | |
| "defaultMode": "default", | |
| "allow": [ | |
| "Bash(Get-Service:*)", | |
| "Bash(Get-Process:*)", | |
| "Bash(Get-Printer:*)", | |
| "Bash(Get-PrinterDriver:*)", | |
| "Bash(Get-CimInstance:*)", | |
| "Bash(Get-NetAdapter:*)", | |
| "Bash(Get-PSDrive:*)", | |
| "Bash(Test-Connection:*)", | |
| "Bash(systeminfo:*)", | |
| "Bash(ipconfig:*)" | |
| ], | |
| "deny": [ | |
| "Bash(format:*)", | |
| "Bash(diskpart:*)", | |
| "Bash(Clear-Disk:*)", | |
| "Bash(Format-Volume:*)", | |
| "Bash(bcdedit:*)" | |
| ], | |
| "disableBypassPermissionsMode": "disable" | |
| } | |
| } | |
| '@ | |
| # --- write the INERT, self-elevating launcher (no download path; that is the point) --- | |
| $launcher = @' | |
| @echo off | |
| REM Claude Code Portable - launcher (generated by InstallClaude.cmd). | |
| REM Inert by design: no download path. Self-elevates so admin fixes work. | |
| REM If bin\claude.exe is missing, re-run InstallClaude.cmd on a trusted machine. | |
| REM VERIFY=0 skips the publisher check. | |
| setlocal | |
| set "ROOT=%~dp0" | |
| set "VERIFY=1" | |
| REM --- self-elevate so admin fixes (spooler, drivers, services) work --- | |
| net session >nul 2>&1 | |
| if errorlevel 1 ( | |
| powershell -NoProfile -Command "try{Start-Process -FilePath '%~f0' -ArgumentList '%*' -Verb RunAs -ErrorAction Stop}catch{exit 1}" | |
| if not errorlevel 1 exit /b | |
| ) | |
| set "CLAUDE_CONFIG_DIR=%ROOT%data" | |
| set "CLAUDE_CODE_TMPDIR=%ROOT%tmp" | |
| set "DISABLE_AUTOUPDATER=1" | |
| set "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1" | |
| if exist "%ProgramFiles%\Git\bin\bash.exe" set "CLAUDE_CODE_GIT_BASH_PATH=%ProgramFiles%\Git\bin\bash.exe" | |
| if exist "%ROOT%config.txt" for /f "usebackq eol=# tokens=1,* delims==" %%A in ("%ROOT%config.txt") do set "%%A=%%B" | |
| set "BINEXE=%ROOT%bin\claude.exe" | |
| if not exist "%BINEXE%" goto :nobin | |
| md "%CLAUDE_CONFIG_DIR%" 2>nul & md "%CLAUDE_CODE_TMPDIR%" 2>nul & md "%ROOT%work" 2>nul | |
| if "%VERIFY%"=="1" powershell -NoProfile -Command "$s=Get-AuthenticodeSignature \"$env:BINEXE\"; if($s.Status -ne 'Valid' -or $s.SignerCertificate.Subject -notlike '*Anthropic*'){exit 1}" || goto :badsig | |
| REM --- stable virtual drive so sessions resume regardless of the stick's real letter --- | |
| REM Claude keys session history by the working-dir path (drive letter included), so an | |
| REM E: vs F: mount orphans your resumes. Map a fixed letter onto the stick so cwd never | |
| REM changes between machines. Override the letter with PORTABLE_DRIVE=X: in config.txt. | |
| set "VDRIVE=Q:" | |
| if defined PORTABLE_DRIVE set "VDRIVE=%PORTABLE_DRIVE%" | |
| set "MADEVDRIVE=" | |
| if not exist "%VDRIVE%\" ( | |
| subst %VDRIVE% "%ROOT:~0,-1%" >nul 2>&1 | |
| if not errorlevel 1 set "MADEVDRIVE=1" | |
| ) | |
| set "BASE=%ROOT%" | |
| if exist "%VDRIVE%\bin\claude.exe" (set "BASE=%VDRIVE%\") else echo [note] %VDRIVE% unavailable - using %ROOT%; sessions may not resume this time. | |
| set "WORK=%BASE%work" & set "ARGS=%*" | |
| if not "%~1"=="" if exist "%~1\" (set "WORK=%~f1" & set "ARGS=") | |
| cd /d "%WORK%" && "%BINEXE%" %ARGS% | |
| set "RC=%errorlevel%" | |
| if defined MADEVDRIVE subst %VDRIVE% /d >nul 2>&1 | |
| exit /b %RC% | |
| :nobin | |
| echo. | |
| echo bin\claude.exe is not on this stick, and this launcher never downloads. | |
| echo Re-run InstallClaude.cmd once on a machine you trust, then use this. | |
| echo. | |
| pause & exit /b 1 | |
| :badsig | |
| echo. | |
| echo *** PUBLISHER CHECK FAILED *** | |
| echo bin\claude.exe is not validly signed by Anthropic, PBC - or PowerShell is | |
| echo restricted on this host and the check could not run. Either way, stop and | |
| echo re-run InstallClaude.cmd from a clean copy on a machine you trust. | |
| echo. | |
| pause & exit /b 1 | |
| '@ | |
| [IO.File]::WriteAllText((Join-Path $root 'Claude.cmd'), ($launcher -replace "`r?`n","`r`n"), [Text.Encoding]::ASCII) | |
| Write-Host " wrote Claude.cmd (inert, self-elevating)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment