168 lines
9.5 KiB
Markdown
168 lines
9.5 KiB
Markdown
---
|
|
name: screenconnect
|
|
description: "Manage ACG ConnectWise ScreenConnect via the RESTful API Manager extension: sessions, parameterized self-tagging installers, backstage commands, custom properties; writes gated --confirm. Triggers: screenconnect, connectwise control, sc session, screenconnect installer."
|
|
---
|
|
|
|
# ScreenConnect (ConnectWise Control) Skill
|
|
|
|
Standalone CLI for the ACG ScreenConnect cloud instance
|
|
(`https://computerguru.screenconnect.com`) via the **RESTful API Manager**
|
|
extension. Read-only by default; writes gated behind `--confirm`.
|
|
|
|
## Running the CLI
|
|
|
|
```bash
|
|
SC="bash $CLAUDETOOLS_ROOT/.claude/scripts/py.sh C:/claudetools/.claude/skills/screenconnect/scripts/sc.py"
|
|
$SC status # auth check + fleet counts
|
|
$SC sessions # WHOLE Access fleet (all agents)
|
|
$SC sessions --company "X" # one client's machines (CP1)
|
|
$SC sessions --like DELL # partial-name match
|
|
$SC sessions --name "<hostname>" # exact Name match
|
|
$SC sessions --filter "SessionType = 'Access'" # raw session-filter expression
|
|
$SC sessions --limit 25 # cap printed rows (--json is always full)
|
|
$SC session <sessionID> # full session detail
|
|
$SC build-installer --platform msi --name HOST --company "X" --site "Y" --tag "Z"
|
|
$SC send-command --session <id> --command "..." --confirm
|
|
$SC set-properties --session <id> --props-json '["Company","Site","Tag"]' --confirm
|
|
$SC raw --method GetSessionsByFilter --body '{"sessionFilter":"SessionType = '"'"'Access'"'"'"}'
|
|
```
|
|
|
|
Transport auto-selects httpx, else stdlib urllib (no hard dependency).
|
|
|
|
## Credentials & auth (VERIFIED)
|
|
|
|
API secret is NEVER hardcoded - loaded from the SOPS vault
|
|
`msp-tools/screenconnect.sops.yaml` field `credentials.api_secret` (or the
|
|
`SCREENCONNECT_API_SECRET` env override). Auth is two headers:
|
|
|
|
```
|
|
CTRLAuthHeader: <raw api_secret> (NO "Basic" prefix - Basic auth 401s)
|
|
Origin: https://computerguru.screenconnect.com
|
|
```
|
|
|
|
Endpoints: `POST <base>/App_Extensions/2d558935-686a-4bd0-9991-07539f5fe749/Service.ashx/<Method>`.
|
|
Reads take a JSON object; the write methods take a **positional array**.
|
|
Custom properties on this instance: **CP1=Company, CP2=Site, CP3=Tag** (up to CP8).
|
|
|
|
## The deploy workflow (RMM push -> self-tag -> control)
|
|
|
|
This is the headline use case - set a device for SC and have it land correctly:
|
|
|
|
1. `build-installer` with the device's Company/Site/Tag (+ name) -> a parameterized
|
|
access-installer URL (`?e=Access&y=Guest&t=<name>&c=<Company>&c=<Site>&c=<Tag>`).
|
|
The cloud serves a pre-keyed installer; the `c=` params self-tag the agent.
|
|
2. Push that installer via `/rmm` (download + `msiexec /i ... /qn` as SYSTEM).
|
|
3. The SC agent connects -> a session named `<name>` appears with CP1/CP2/CP3 set.
|
|
4. `sessions --name <name>` -> get the sessionID -> control it (`send-command`, etc.).
|
|
|
|
VERIFIED end-to-end on RMM-TEST-MACHINE 2026-06-22 (installed, self-tagged
|
|
Company/Site/Tag, ran a command, re-tagged via set-properties).
|
|
|
|
### Deploying the GuruRMM agent via SC (verified 2026-07-08)
|
|
|
|
Different from the SC-installer push above: to enroll a box that is in SC but NOT in GuruRMM,
|
|
`send-command` the server's own site-preconfigured one-liner. The site code is baked into the
|
|
downloaded signed binary (GRMM_CFG trailer) so it self-enrolls straight into that site — no
|
|
Staging, no reassign:
|
|
|
|
```bash
|
|
# site_code from GET /api/sites/<id>/install-info (e.g. Main = INNER-BRIDGE-8354)
|
|
CMD='powershell -NoProfile -ExecutionPolicy Bypass -Command "[Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12; iex (irm '\''https://rmm.azcomputerguru.com/install/<SITE_CODE>/windows'\'')"'
|
|
$SC send-command --session <sessionID> --command "$CMD" --confirm
|
|
```
|
|
|
|
The install script auto-relaunches into native 64-bit PowerShell (handles SC's 32-bit command
|
|
runner via Sysnative). Verified: DESKTOP-NFU17AJ enrolled into IMC → Main this way 2026-07-08.
|
|
|
|
- **`send-command` returns `{}`** — SC gives no command output via the API (documented below).
|
|
It is queued, not confirmed. **Verify by enrollment**, not by the send response: poll
|
|
`rmm-search.sh -c <client>` for the new agent (pipe `--json` with `2>/dev/null` — the `[OK]
|
|
Authenticated` banner is on stderr; `2>&1 | jq` breaks jq).
|
|
- **Offline targets:** the one-liner is a single self-contained command, so it queues in the
|
|
session's one event slot and runs on reconnect. It will NOT run until the box is online.
|
|
- **Gotcha:** the install script calls `Get-CimInstance Win32_Processor`; a box with corrupt
|
|
WMI dies there (bit CP-QB). A box that black-holes outbound TLS installs but never connects
|
|
(bit IMC-PRINTSERVER) — SC still works because its relay is not TLS.
|
|
- **CP values are under `.CustomProperties.CustomPropertyN` / `.CustomPropertyValues[]`** on the
|
|
raw session object (CP1=Company, CP2=Site, ...). `--company "X"` matches CP1 **exactly**, so
|
|
pass the full tagged value (IMC's CP1 is `IMC - Instrumental Music Center`, not `Instrumental
|
|
Music Center`) or enumerate with `--like` / a raw `CustomProperty1 = '...'` filter first.
|
|
SC truncates session Name to 15 chars — `IMC-M-EDSERVICE` (SC) is `IMC-M-EdServices1` (RMM).
|
|
|
|
## Method surface (probed live 2026-06-22)
|
|
|
|
**Available (CLI-exposed):**
|
|
- Full-fleet listing: `GetSessionsByFilter` `{"sessionFilter":"<expr>"}` (probed live
|
|
2026-07-06) - THE enumeration path. `SessionType = 'Access'` returns every
|
|
unattended agent (958 on this instance); `SessionType = 'Support'` the on-demand
|
|
sessions (24). Filter language: single-quoted literals, `=`/`LIKE` (with `*`
|
|
wildcards), `AND`/`OR`. Per-client `CustomProperty1 = 'Safesite'`; partial name
|
|
`Name LIKE '*DELL*'`. The CLI `sessions` command wraps this (default = whole fleet).
|
|
- Reads: `GetSessionsByName` (EXACT Name match; "" -> only blank-name sessions, NOT
|
|
the fleet - use the filter for listing), `GetSessionDetailsBySessionID`,
|
|
`GetSessionBySessionID`.
|
|
- Writes (gated): `SendCommandToSession` `[sessionID, command]`,
|
|
`SendMessageToSession` `[sessionID, message]`,
|
|
`UpdateSessionCustomProperties` `[sessionID, [cp1,cp2,cp3,...]]`,
|
|
`CreateSession` (array; not the primary path - the installer creates access sessions).
|
|
|
|
**Absent aliases (not needed):**
|
|
- `GetSessions` / `GetAllSessions` / `GetSessionGroups` -> "web method does not
|
|
exist". No extension update required: `GetSessionsByFilter` covers full-fleet
|
|
inventory. (Earlier notes flagged this as a gap pending Mike; it is resolved.)
|
|
|
|
## Safety gating
|
|
|
|
`send-command`, `send-message`, `set-properties` refuse to run without `--confirm`
|
|
(print what they WOULD do, exit 3). `raw` also refuses state-changing method names
|
|
(sendcommand/updatesession/create/delete/end/transfer/install/...) without
|
|
`--confirm`. NEVER run `send-command` against a production client session casually -
|
|
it executes on the guest. Test against a known test machine.
|
|
|
|
## Error logging
|
|
|
|
On a GENUINE functional error (auth failure, unexpected API response, transport
|
|
failure) the CLI logs it to `errorlog.md` via `log-skill-error.sh` before
|
|
surfacing it. It does NOT log expected/handled conditions - a missing extension
|
|
method ("web method does not exist"), a rate-limit (429), the `raw` probe path, or
|
|
selftest runs (`SC_SUPPRESS_ERRORLOG=1`) are skipped (see `_should_log_error`).
|
|
|
|
## Why this skill exists: the GuruRMM addon integration (the end goal)
|
|
|
|
This skill is the **verified connector prototype** for a GuruRMM addon, not a
|
|
one-off CLI. The end goal is to surface ScreenConnect as a first-class, per-partner
|
|
entry on the GuruRMM **Integrations Center / App Center** ("addons page"), so a
|
|
partner can wire in their OWN paid ScreenConnect instance and the RMM drives it.
|
|
|
|
**Positioning - ScreenConnect is the bring-your-own alternative to GuruConnect.**
|
|
GuruRMM's native remote-access product is **GuruConnect** (consumed via its
|
|
integration contract - see `guru-rmm/docs/GURU_CONNECT_INTEGRATION.md`). A partner
|
|
who is **already paying for ScreenConnect and does NOT want GuruConnect** enables
|
|
the ScreenConnect addon instead and uses their existing licensed instance for
|
|
remote access. Same RMM surface (the "remote control" device action, embedded/
|
|
launched session), different provider behind it - selectable per partner on the
|
|
addons page. It is an alternative remote-access backend, not an addition GuruConnect
|
|
depends on.
|
|
|
|
**What this skill proves / ports into the server:** the parameterized access
|
|
installer build (`build-installer` -> a pre-keyed URL whose repeated `c=` params
|
|
self-tag the device into the right Company/Site/Tag with no SC-console step), the
|
|
silent RMM push, and post-install control (`send-command`, `send-message`,
|
|
`set-properties` to keep SC custom properties in sync as the RMM record changes).
|
|
`sc_client.build_installer_url` + the control methods are what move server-side.
|
|
|
|
**Where the plan is mapped (all GuruRMM-side, needs Mike's go - status Raw):**
|
|
- `docs/specs/SPEC-024-screenconnect-auto-deploy.md` - the auto-deploy mechanics
|
|
(per-partner instance config, `c0..c7` slot mapping, scope toggles, dispatch).
|
|
- `docs/RMM_THOUGHTS.md` **Feature 7** - parameterized deploy + control from the RMM.
|
|
- `docs/RMM_THOUGHTS.md` **Refinement 7a** (Mike) - ScreenConnect as a per-partner
|
|
App Center entry; generalizes to a "Remote Access" category (SC/TeamViewer/AnyDesk).
|
|
- `docs/FEATURE_ROADMAP.md` **Integrations Center** - the unified addons UI surface.
|
|
|
|
Advance via RMM_THOUGHTS -> `/shape-spec`. Do NOT build until Mike gives the go.
|
|
|
|
## Reference
|
|
|
|
Verified method/param spec, auth, installer params, and the session-filter language:
|
|
`references/api-reference.md`.
|