sync: auto-sync from GURU-5070 at 2026-07-01 15:49:56

Author: Mike Swanson
Machine: GURU-5070
Timestamp: 2026-07-01 15:49:56
This commit is contained in:
2026-07-01 15:50:48 -07:00
parent 1775571abb
commit 2937b00ebf
15 changed files with 1217 additions and 67 deletions

View File

@@ -0,0 +1,141 @@
#!/usr/bin/env bash
# ps-encoded.sh — dispatch PowerShell through quote-mangling layers safely.
#
# THE point of this helper: a PS payload that traverses CommandLineToArgvW
# (curl.exe args, plink, ScreenConnect's command box, RMM->cmd.exe) gets its
# embedded double-quotes stripped and its UNC backslashes halved — the single
# most-repeated friction class in errorlog.md (ref=feedback_windows_quote_stripping,
# 9+ hits). -EncodedCommand (UTF-16LE base64) has NO quotes, backslashes, or
# dollar signs to mangle, so the script arrives byte-exact. Write the script
# to a FILE (or stdin), let this helper encode + deliver it.
#
# Usage:
# ps-encoded.sh encode <script.ps1|-> print the one-liner for
# ScreenConnect / plink / any paste
# ps-encoded.sh rmm <agent-uuid> <script.ps1|-> dispatch via GuruRMM + poll
# [--timeout <sec>] agent-side timeout_seconds (default 120)
# [--user-session] context: user_session (WTS-impersonated desktop user)
# [--no-wait] dispatch only; print command id, skip polling
# [--force] override the size refusal (see below)
#
# Size guards (agent chokes on ~7KB command bodies; encoding inflates ~2.67x):
# encoded > 4000 chars -> [WARNING]; encoded > 6000 chars -> refuse unless
# --force (split the script, or stage it on the endpoint and run the file).
#
# Exit codes: 0 ok; 1 usage/encode error; 2 size refusal; 3 dispatch/poll failure.
set -u
ROOT="${CLAUDETOOLS_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
_logerr() { bash "$ROOT/.claude/scripts/log-skill-error.sh" "ps-encoded" "$@" >/dev/null 2>&1 || true; }
usage() { sed -n '2,26p' "$0"; exit 1; }
read_script() { # $1 = file path or "-"
if [ "$1" = "-" ]; then cat
elif [ -f "$1" ]; then cat "$1"
else echo "[ERROR] script file not found: $1" >&2; exit 1
fi
}
encode_b64() { # stdin: UTF-8 script -> stdout: UTF-16LE base64 (no BOM, no wraps)
iconv -f UTF-8 -t UTF-16LE | base64 -w0
}
size_gate() { # $1 = encoded string, $2 = force flag (0/1)
local n=${#1}
if [ "$n" -gt 6000 ] && [ "${2:-0}" != "1" ]; then
echo "[ERROR] encoded payload is ${n} chars (>6000); the agent fails on bodies this large." >&2
echo " Split the script into sections, or stage it as a file on the endpoint" >&2
echo " and dispatch 'powershell -File <path>'. Override with --force." >&2
return 1
elif [ "$n" -gt 4000 ]; then
echo "[WARNING] encoded payload is ${n} chars — near the agent's body-size failure zone (~7KB)." >&2
fi
return 0
}
cmd_encode() {
local src="${1:-}"; [ -z "$src" ] && usage
local b64
b64="$(read_script "$src" | encode_b64)"
[ -z "$b64" ] && { echo "[ERROR] encoding produced nothing" >&2; _logerr "encode produced empty output" --context "src=$src"; exit 1; }
size_gate "$b64" 1 || true # encode mode: warn only, the paste target may cope
printf 'powershell -NoProfile -ExecutionPolicy Bypass -EncodedCommand %s\n' "$b64"
}
cmd_rmm() {
local agent="${1:-}"; shift || true
local src="${1:-}"; shift || true
[ -z "$agent" ] || [ -z "$src" ] && usage
local timeout=120 context="" wait=1 force=0
while [ $# -gt 0 ]; do
case "$1" in
--timeout) timeout="${2:?}"; shift 2 ;;
--user-session) context="user_session"; shift ;;
--no-wait) wait=0; shift ;;
--force) force=1; shift ;;
*) echo "[ERROR] unknown option: $1" >&2; usage ;;
esac
done
local b64
b64="$(read_script "$src" | encode_b64)"
[ -z "$b64" ] && { echo "[ERROR] encoding produced nothing" >&2; _logerr "encode produced empty output" --context "src=$src"; exit 1; }
size_gate "$b64" "$force" || exit 2
eval "$(bash "$ROOT/.claude/scripts/rmm-auth.sh")"
if [ -z "${TOKEN:-}" ] || [ -z "${RMM:-}" ]; then
echo "[ERROR] RMM auth failed (no TOKEN/RMM)" >&2
_logerr "RMM auth failed via rmm-auth.sh" --context "agent=$agent"
exit 3
fi
# command_type=shell (cmd.exe): the base64 blob is a single quote-free token,
# so no layer between here and powershell.exe can mangle it. timeout_seconds
# is the field the agent honors — 'timeout' is silently ignored (errorlog).
local oneliner payload resp cmd_id status
oneliner="powershell -NoProfile -ExecutionPolicy Bypass -EncodedCommand ${b64}"
payload="$(jq -nc --arg ct shell --arg cmd "$oneliner" --argjson to "$timeout" \
--arg cx "$context" \
'{command_type:$ct, command:$cmd, timeout_seconds:$to}
+ (if $cx != "" then {context:$cx} else {} end)')"
resp="$(printf '%s' "$payload" | curl -s -m 20 -X POST "$RMM/api/agents/$agent/command" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
--data-binary @-)"
cmd_id="$(printf '%s' "$resp" | jq -r '.command_id // empty' 2>/dev/null)"
status="$(printf '%s' "$resp" | jq -r '.status // empty' 2>/dev/null)"
if [ -z "$cmd_id" ]; then
echo "[ERROR] dispatch failed: $resp" >&2
_logerr "EncodedCommand dispatch failed" --context "agent=$agent resp=${resp:0:80}"
exit 3
fi
echo "[OK] dispatched command_id=$cmd_id (initial status: ${status:-unknown}, timeout_seconds=$timeout)"
[ "$wait" = "0" ] && exit 0
local max_polls=$(( (timeout + 30) / 5 )) count=0 result
while [ $count -lt $max_polls ]; do
result="$(curl -s -m 15 "$RMM/api/commands/$cmd_id" -H "Authorization: Bearer $TOKEN")"
status="$(printf '%s' "$result" | jq -r '.status // empty' 2>/dev/null)"
case "$status" in
completed|failed|cancelled|interrupted)
echo "--- status: $status ---"
printf '%s' "$result" | jq -r '
"exit_code: \(.exit_code // "n/a")",
"--- stdout ---", (.stdout // .output // ""),
"--- stderr ---", (.stderr // "")' 2>/dev/null || printf '%s\n' "$result"
[ "$status" = "completed" ] && exit 0 || exit 3 ;;
running|pending) count=$((count+1)); sleep 5 ;;
*) echo "[ERROR] empty/unknown status — response: $result" >&2
_logerr "poll returned empty status" --context "cmd=$cmd_id agent=$agent"
exit 3 ;;
esac
done
echo "[WARNING] poll timeout after $((max_polls*5))s — command $cmd_id may still be running (last: $status)"
exit 3
}
case "${1:-}" in
encode) shift; cmd_encode "$@" ;;
rmm) shift; cmd_rmm "$@" ;;
*) usage ;;
esac