From 99956d54e3b40b6cfc75ab8db687cef2095a0b54 Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Thu, 6 Aug 2026 11:48:13 -0500 Subject: [PATCH] tools: podshell_setup.ps1 -- one-shot remote-shell setup for the pod PC OpenSSH server + a single authorized key + a private/domain-only firewall rule, so bring-up can run over a tailnet instead of by hand through Chrome Remote Desktop (CRD paints a canvas -- unreadable to tooling; text and logs need a real shell). Handles the Windows administrators_authorized_keys ACL quirk, refuses to run on pre-Win10 (the period-pod case, which stays on the clipboard/probe route), never opens the public profile, and prints the exact ssh line including the Tailscale address. Undo steps in the header. Co-Authored-By: Claude Fable 5 --- tools/podshell_setup.ps1 | 113 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 tools/podshell_setup.ps1 diff --git a/tools/podshell_setup.ps1 b/tools/podshell_setup.ps1 new file mode 100644 index 0000000..0e8966a --- /dev/null +++ b/tools/podshell_setup.ps1 @@ -0,0 +1,113 @@ +# podshell_setup.ps1 -- give the pod / crash-cart PC a remote shell for BT411 +# bring-up. Run ON THE POD PC, in an ADMINISTRATOR PowerShell, ONCE: +# +# powershell -ExecutionPolicy Bypass -File podshell_setup.ps1 +# +# What it does (and nothing else): +# 1. installs + starts the Windows OpenSSH SERVER (built into Win10/11) +# 2. authorizes ONE public key (the laptop's bt411 key, below) +# 3. opens SSH on PRIVATE/tailnet profiles only -- never the public internet +# 4. prints the Tailscale address to connect to +# +# It does NOT install Tailscale (do that first, see the header notes) and it +# does NOT enable password logins or touch any other service. +# +# Undo when the pod work is finished: +# Remove-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 +# Remove-Item C:\ProgramData\ssh\administrators_authorized_keys +# (and uninstall / `tailscale logout` if you like) + +$ErrorActionPreference = 'Stop' + +# --- the ONE key that may log in (BT411 bring-up, laptop-held, no passphrase) --- +$PUBKEY = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICmGkinDbZMwQ/UhwqU/oECUIeAN+pBjLgsekj41di7W bt411-claude-code@laptop' + +function Say($m) { Write-Host " $m" } + +Write-Host "=== BT411 pod shell setup ===" + +# 0. admin check -- everything below needs it +$isAdmin = ([Security.Principal.WindowsPrincipal] ` + [Security.Principal.WindowsIdentity]::GetCurrent() + ).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +if (-not $isAdmin) { + Write-Host "!! Run this in an ADMINISTRATOR PowerShell (right-click > Run as administrator)." -ForegroundColor Red + exit 1 +} + +$os = [Version](Get-CimInstance Win32_OperatingSystem).Version +Say ("windows {0}" -f $os) +if ($os.Major -lt 10) { + Write-Host "!! Windows 10+ required for the built-in OpenSSH server." -ForegroundColor Red + Write-Host " (If this is the period pod PC, stop here -- use the clipboard/probe route instead.)" + exit 1 +} + +# 1. OpenSSH server +Say "installing OpenSSH server (if missing) ..." +$cap = Get-WindowsCapability -Online -Name OpenSSH.Server* | Select-Object -First 1 +if ($cap.State -ne 'Installed') { Add-WindowsCapability -Online -Name $cap.Name | Out-Null } +Set-Service -Name sshd -StartupType Automatic +Start-Service sshd +Say ("sshd: {0}" -f (Get-Service sshd).Status) + +# 2. authorize the key. Windows OpenSSH quirk: for accounts in the +# Administrators group the file is administrators_authorized_keys, and sshd +# REFUSES it unless the ACL is exactly SYSTEM + Administrators. +$me = "$env:USERDOMAIN\$env:USERNAME" +$inAdmins = (Get-LocalGroupMember -Group 'Administrators' -ErrorAction SilentlyContinue | + Where-Object { $_.Name -eq $me }) -ne $null +if ($inAdmins) { + $akf = 'C:\ProgramData\ssh\administrators_authorized_keys' + Say "account is an Administrator -> using administrators_authorized_keys" +} else { + $akf = Join-Path $env:USERPROFILE '.ssh\authorized_keys' + New-Item -ItemType Directory -Force -Path (Split-Path $akf) | Out-Null + Say "standard account -> using $akf" +} + +$existing = '' +if (Test-Path $akf) { $existing = Get-Content $akf -Raw } +if ($existing -notlike "*$PUBKEY*") { + Add-Content -Path $akf -Value $PUBKEY -Encoding ASCII + Say "key added" +} else { Say "key already present" } + +if ($inAdmins) { + icacls $akf /inheritance:r /grant 'SYSTEM:F' /grant 'BUILTIN\Administrators:F' | Out-Null + Say "ACL locked to SYSTEM + Administrators (sshd requires this)" +} + +# 3. firewall: private/domain only. Explicitly NOT public -- the tailnet +# interface is what we connect over. +$rule = Get-NetFirewallRule -Name 'BT411-SSH' -ErrorAction SilentlyContinue +if (-not $rule) { + New-NetFirewallRule -Name 'BT411-SSH' -DisplayName 'BT411 SSH (private/tailnet only)' ` + -Enabled True -Direction Inbound -Protocol TCP -LocalPort 22 ` + -Action Allow -Profile Private,Domain | Out-Null + Say "firewall rule added (private/domain profiles only)" +} else { Say "firewall rule already present" } + +# 4. how to reach it +Write-Host "" +Write-Host "=== CONNECT WITH ===" +$ts = 'C:\Program Files\Tailscale\tailscale.exe' +if (Test-Path $ts) { + $ip = (& $ts ip -4 2>$null | Select-Object -First 1) + $st = (& $ts status --json 2>$null | ConvertFrom-Json) + $dns = $null + if ($st -and $st.Self -and $st.Self.DNSName) { $dns = $st.Self.DNSName.TrimEnd('.') } + if ($ip) { Write-Host (" ssh -i ~/.ssh/bt411_pod {0}@{1}" -f $env:USERNAME, $ip) } + if ($dns) { Write-Host (" ssh -i ~/.ssh/bt411_pod {0}@{1}" -f $env:USERNAME, $dns) } + if (-not $ip) { Write-Host " ! Tailscale installed but not connected -- run: tailscale up" } +} else { + Write-Host " ! Tailscale not installed yet." + Write-Host " winget install --id Tailscale.Tailscale -e (then: tailscale up)" + Write-Host " Sign in with the SAME account used on the laptop." + Write-Host (" LAN fallback: ssh -i ~/.ssh/bt411_pod {0}@{1}" -f $env:USERNAME, + ((Get-NetIPAddress -AddressFamily IPv4 | + Where-Object { $_.IPAddress -notlike '127.*' -and $_.IPAddress -notlike '169.254.*' } | + Select-Object -First 1).IPAddress)) +} +Write-Host "" +Say ("user: {0} host: {1}" -f $env:USERNAME, $env:COMPUTERNAME)