Files
claudetools/session-logs/2026-07/2026-07-06-howard-screenconnect-fleet-listing.md
Howard Enos 7264840da6 sync: auto-sync from HOWARD-HOME at 2026-07-06 16:51:24
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-07-06 16:51:24
2026-07-06 16:51:53 -07:00

8.3 KiB

2026-07-06 — ScreenConnect skill: full-fleet listing fix

User

  • User: Howard Enos (howard)
  • Machine: Howard-Home
  • Role: tech

Session Summary

Fixed the screenconnect skill's reported inability to list the full agent fleet. The prior state believed the RESTful API Manager extension on the ACG instance (computerguru.screenconnect.com) exposed no full-fleet enumeration method — only GetSessionsByName, an exact-name lookup — and the SKILL.md/reference docs framed this as a gap needing Mike to update the extension.

That premise was wrong about the cause. Empirical probing of the live extension found that GetSessionsByFilter does exist; earlier probing had simply never tried it. It was distinguishable because it returned a different error (InvalidOperationException: "Session filter cannot be null") than the "web method does not exist" every other candidate returned. Discovery of its signature followed: the parameter is named sessionFilter (not filter), it takes a ScreenConnect session-filter expression, and string literals are single-quoted. SessionType = 'Access' returns all 958 unattended agents; SessionType = 'Support' returns the 24 on-demand sessions; CustomProperty1 = '<Company>' does per-client listing; Name LIKE '*<substr>*' does partial-name search; AND/OR compose.

Implemented the fix across the client (get_sessions_by_filter, a build_session_filter builder, list_sessions convenience), the CLI (sessions now defaults to the whole Access fleet, with new --like, --company, --site, --tag, --type, --filter, --limit flags; status reports real fleet counts), the self-test (added coverage), and both doc files (documented the filter language, removed the stale "MISSING / needs extension update" framing).

Ran /code-review at high effort via the workflow backend. It caught three real regressions I had introduced plus four robustness/quality issues. All seven were fixed and re-verified live. The self-test grew from the original set to 19 checks, all passing against the live instance. The repo's background auto-sync committed and pushed the changes (commits 7dc5198 then 12c3d83); main is level with origin/main.

Key Decisions

  • Probe the live extension rather than trust the documented gap. The "GetSessions unavailable" note was a conclusion from incomplete probing; treating the API surface as empirically discoverable (not fixed) surfaced GetSessionsByFilter.
  • Route full-fleet listing through a filter builder, not ad-hoc strings. A build_session_filter(**parts) keeps CLI flags declarative and centralizes literal escaping.
  • sessions defaults to the whole Access fleet. The headline use case is "show me every agent"; a bare sessions now does that (958), with --company/--like/etc. narrowing.
  • A targeted selector defaults --type to all, a bare listing defaults to access. This restores the old type-agnostic by-name behavior (Support/Meeting sessions resolve) while keeping the fleet default meaningful.
  • status auth check stays on the cheap GetSessionsByName(''); fleet counts are best-effort. Keeps status fast and functional even on an extension version lacking GetSessionsByFilter.
  • Kept SQL-style '' quote-doubling for escaping after verifying it round-trips live (matched "Andy's Mobile Fuel").

Problems Encountered

  • Full-fleet listing believed impossible. Root cause: GetSessionsByFilter never probed. Resolved by discovering the method, its sessionFilter param name, and the SessionType = 'Access' match-all form.
  • GetSessionsByName('') returns only blank-name sessions (3), not the fleet. Confirmed it is an exact Name == match, so it cannot be coaxed into listing — hence the filter method is required.
  • Three regressions from the first-pass rewrite (caught by /code-review): (1) --limit truncated --json, breaking the "json is always full" contract — fixed so --limit only caps the human-readable print; (2) --type all fell through to the Access-only default — fixed with an (SessionType = 'Access' OR SessionType = 'Support') clause (verified 982 = 958 + 24); (3) --name lost type-agnostic lookup — fixed via context-aware --type defaulting. All re-verified live.
  • status was downloading the full fleet twice just to count, and would fail if the filter method were absent. Decoupled the auth check (cheap GetSessionsByName) from best-effort fleet counting wrapped in try/except.
  • /tmp write blocked by the harness hook during a shell sanity check (expected Windows /tmp rule); switched to a repo-relative scratch path.

Configuration Changes

Modified (all under .claude/skills/screenconnect/):

  • scripts/sc_client.py — added get_sessions_by_filter(), _filter_literal(), build_session_filter(), list_sessions(); added SESSION_TYPE_LITERALS; updated module/method docstrings.
  • scripts/sc.pycmd_status decoupled (cheap auth + best-effort counts); cmd_sessions reworked with _effective_type(), limit-only-on-print; added --like/--company/--site/--tag/--type/--filter/--limit flags; updated usage docstring.
  • scripts/selftest.py — restored Authenticated assertion, added --type all, --like, --filter, --company, --limit, and a "limit does not truncate json" check (out_json_min_len). Now 19 checks.
  • SKILL.md — documented GetSessionsByFilter as the enumeration path + CLI examples; replaced the "MISSING, needs Mike" framing with "absent aliases, not needed".
  • references/api-reference.md — added GetSessionsByFilter row + a session-filter language section.

Credentials & Secrets

No new credentials. API secret unchanged: SOPS vault msp-tools/screenconnect.sops.yaml field credentials.api_secret (env override SCREENCONNECT_API_SECRET). Auth remains two headers — CTRLAuthHeader: <raw api_secret> (no "Basic" prefix) and Origin: https://computerguru.screenconnect.com.

Infrastructure & Servers

  • Instance: https://computerguru.screenconnect.com
  • Extension GUID: 2d558935-686a-4bd0-9991-07539f5fe749 (RESTful API Manager)
  • Endpoint: POST <instance>/App_Extensions/<guid>/Service.ashx/<Method>
  • Fleet snapshot (2026-07-06): 958 Access (unattended agents) + 24 Support = 982.
  • Custom properties: CP1=Company, CP2=Site, CP3=Tag (up to CP8; CP4 seen holding a role like Server/Desktop, CP5 "Syncro-Matched" on some records).
  • SessionType literals: Access = 2, Support = 0, Meeting = none present.

Commands & Outputs

SC="bash .claude/scripts/py.sh C:/claudetools/.claude/skills/screenconnect/scripts/sc.py"

# full fleet (958), per-client, partial name, all types
$SC sessions
$SC sessions --company "Ridgetop Group"          # 14
$SC sessions --like DELL --limit 3
$SC sessions --type all --json | ...              # 982

# the discovery: filter method exists, param is sessionFilter
$SC raw --method GetSessionsByFilter --body '{"sessionFilter":"SessionType = '"'"'Access'"'"'"}'

Key probe results:

  • GetSessionsByFilter {} -> InvalidOperationException: "Session filter cannot be null" (method EXISTS).
  • {"filter":""} -> "Unknown parameter: filter"; {"sessionFilter":"x"} -> [] (valid, matched none).
  • SessionType = 'Access' -> 958; 'Support' -> 24; 'Access' OR 'Support' -> 982.
  • CustomProperty1 = 'Safesite' -> 62; Name LIKE '*DELL*' -> 26.
  • Escaping verified: CustomProperty1 LIKE '*Andy''s*' -> 1 (matched "Andy's Mobile Fuel").

Self-test: 19/19 passed, 0 failed against the live instance.

Pending / Incomplete Tasks

  • None for the skill itself. The GuruRMM addon plan it prototypes is unchanged and still gated on Mike's go (SPEC-024, RMM_THOUGHTS Feature 7 / Refinement 7a).
  • Unrelated working-tree drift left untouched: projects/dataforth-dos, projects/discord-bot, projects/msp-tools/guru-rmm, projects/msp-tools/security-assessment (submodule pointers), projects/radio-show (untracked). Not part of this work.

Reference Information

  • Commits: 7dc5198 (initial fix) and 12c3d83 (review fixes) — both auto-sync commits from HOWARD-HOME; main == origin/main.
  • Skill dir: .claude/skills/screenconnect/
  • Filter language ref: .claude/skills/screenconnect/references/api-reference.md (session-filter section).