PC set-up: one line per PC (/setup/<name>.ps1), the admin laptop always let in, and the admin check no longer breaks the script

- the inserted administrator check split the header comment, leaving '} for ... run ONCE' as code: WS and SC
  join.ps1 failed to parse (Windows' parser: Missing opening '(' after keyword 'for'); now after the whole line
- site.admin_ips / admin_keys (laptop 10.6.7.38, fixed in UniFi) go into every PC script's firewall rule and key
  files, and into the Mac join line, so running a set-up again never shuts the laptop out
- scripts verified by Windows' own PowerShell parser on the NA Lighting PC

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 16:29:36 -04:00
co-authored by Claude Opus 5.5
parent 0813734e78
commit afd2758d87
11 changed files with 117 additions and 11 deletions
+4 -5
View File
@@ -555,6 +555,7 @@ if [ "$(id -u)" = 0 ]; then
fi
mkdir -p "$H/.ssh" && touch "$H/.ssh/authorized_keys" && chmod 700 "$H/.ssh" && chmod 600 "$H/.ssh/authorized_keys"
grep -qF "$KEY" "$H/.ssh/authorized_keys" || echo "$KEY" >> "$H/.ssh/authorized_keys"
for A in %(admin)s; do grep -qF "$A" "$H/.ssh/authorized_keys" || echo "$A" >> "$H/.ssh/authorized_keys"; done
[ "$(id -u)" = 0 ] && chown -R "$U:staff" "$H/.ssh"
[ "$(id -u)" = 0 ] && { /usr/sbin/systemsetup -setremotelogin on >/dev/null 2>&1 || /bin/launchctl load -w /System/Library/LaunchDaemons/ssh.plist >/dev/null 2>&1; }
if ! /usr/bin/nc -z -G 2 127.0.0.1 22 >/dev/null 2>&1; then
@@ -574,7 +575,8 @@ else
echo "Could not reach %(ingest)s at %(base)s - is this Mac on the wired network?"
exit 1
fi
""" % {"ingest": ingest, "key": shq(key), "hello": shq(base + "/api/hello"), "base": base}
""" % {"ingest": ingest, "key": shq(key), "hello": shq(base + "/api/hello"), "base": base,
"admin": " ".join(shq(k) for k in scripts.admin_keys(cfg))}
def join_windows(cfg, base):
@@ -591,10 +593,7 @@ def join_windows(cfg, base):
raise RuntimeError("the Windows template changed: cannot put the program finder in")
text = text.replace("# Status panel remote access", "# Run in PowerShell as administrator: irm %s/join.ps1 | iex\n# Status panel remote access" % base, 1)
# Not elevated: say how, before anything runs (SC's Lighting PC got a DISM error instead, 2026-10-21).
text = text.replace("# Status panel remote access", """# Status panel remote access
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
throw 'Run this as administrator: close this window, right-click Windows PowerShell > Run as administrator, then paste the line again. Nothing was changed.'
}""", 1)
text = scripts.with_admin_check(text)
text += """
# 5. Tell %(ingest)s this PC is here: it sets it up within a minute.
$hello = @{ user = $env:USERNAME; name = $env:COMPUTERNAME; os = 'windows'
+29 -1
View File
@@ -44,15 +44,43 @@ def ps_quote(value, what):
return "'" + value + "'"
def admin_keys(cfg):
"""The admin laptop's SSH keys (site.admin_keys), checked: one line each, no quotes."""
out = []
for k in (cfg.get("site") or {}).get("admin_keys") or []:
k = str(k).strip()
if not re.fullmatch(r"ssh-(ed25519|rsa) [A-Za-z0-9+/=]+( [A-Za-z0-9@._-]+)?", k):
raise ValueError("site.admin_keys: %r is not one public SSH key line" % k[:40])
out.append(k)
return out
def site_values(cfg):
site = cfg.get("site") or {}
key, mark = public_key(cfg)
# The admin laptop (site.admin_ips / admin_keys) gets in everywhere this Mac does, so running a set-up script
# again never shuts it out (2026-10-21, the user: "keep SSH on at all times for windows pc, just like the macs").
ips = list(dict.fromkeys(list(site.get("ingest_ips") or []) + list(site.get("admin_ips") or [])))
return {"INGEST_NAME": site.get("ingest_name") or "the Ingest Mac",
"INGEST_IPS": ", ".join("'%s'" % ip for ip in site.get("ingest_ips") or []) or "'127.0.0.1'",
"INGEST_IPS": ", ".join("'%s'" % ip for ip in ips if re.fullmatch(r"[0-9a-fA-F.:]+", str(ip))) or "'127.0.0.1'",
"ADMIN_KEYS": ", ".join("'%s'" % k for k in admin_keys(cfg)),
"KEY": key or "<< this Mac has no login key yet: run install.sh, then come back >>",
"KEY_COMMENT": mark or "status-panel", "DVS_HELPER": site.get("dvs_helper") or "/usr/local/sbin/status-panel-dvs-start"}
ADMIN_CHECK = """if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
throw 'Run this as administrator: close this window, right-click Windows PowerShell > Run as administrator, then paste the line again. Nothing was changed.'
}"""
def with_admin_check(text):
"""The script stops with plain words unless PowerShell runs as administrator: the check goes after the
whole header comment line (inserting it mid-line left "} for ... - run ONCE" as code, 2026-10-21)."""
lines = text.split("\n")
at = next((i for i, ln in enumerate(lines) if ln.startswith("# Status panel remote access")), 0)
return "\n".join(lines[:at + 1] + [ADMIN_CHECK] + lines[at + 1:])
def windows_setup(cfg, alias):
host = cfg["hosts"][alias]
tasks = [r for r in host.get("runs") or [] if r.get("kind") == "task"]
+11
View File
@@ -716,6 +716,17 @@ class Handler(http.server.BaseHTTPRequestHandler):
return
if path == "/join":
return self.send(200, campus.join_mac(site.load(), self.base_url()), "text/plain; charset=utf-8")
m = re.fullmatch(r"/setup/([A-Za-z0-9_]+)\.ps1", path)
if m:
# One computer's set-up script, for "irm http://<this Mac>:8020/setup/<name>.ps1 | iex" in an
# administrator PowerShell on that PC (2026-10-21: the Bible TV PC's SSH had stopped).
cfg = site.load()
h = (cfg.get("hosts") or {}).get(m.group(1))
if not h or h.get("os") != "windows":
return self.send(404, {"error": "no Windows computer called %s here" % m.group(1)})
text = "# Run in PowerShell as administrator: irm %s/setup/%s.ps1 | iex\n%s" % (
self.base_url(), m.group(1), scripts.with_admin_check(scripts.windows_setup(cfg, m.group(1))))
return self.send(200, text, "text/plain; charset=utf-8")
if path == "/join.ps1":
return self.send(200, campus.join_windows(site.load(), self.base_url()), "text/plain; charset=utf-8")
if path == "/api/state":