Skip to content

Instantly share code, notes, and snippets.

@mlajtos
Created July 29, 2026 07:12
Show Gist options
  • Select an option

  • Save mlajtos/138886341335ad4ddbfb034039e39a28 to your computer and use it in GitHub Desktop.

Select an option

Save mlajtos/138886341335ad4ddbfb034039e39a28 to your computer and use it in GitHub Desktop.
Claude Portable
@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