Skip to content

Per-Customer RMM Installer Automation — Working Solution

Goal

Generate the correct ConnectWise RMM (ITSupport247) Windows agent installer for each customer automatically, e.g.:

Acme_Electric-Acme_Electric_Windows_OS_ITSPlatform_TKN77d2779b-9a06-4fe9-b3da-0eb29c0e7bb0.msi

Each installer needs: the Company/Site name, the per-site Agent Token (the TKN<GUID>), and a download URL.

What didn't work, and why

  • Legacy Reporting API (api.itsupport247.net/reporting/v1/Sites) returns only name + siteCode. The siteCode (ACE, 1069, ...) is NOT the agent token, and the reporting API has no endpoint that exposes it.
  • New OpenAPI (openapi.service.itsupport247.net) authenticates fine with a Client ID/Secret (snake_case JSON to /v1/token), but /v1/clients returns 403 regardless of scopes, and there is no usable agent-token resource on it for this tenant.

What works: the portal's own GraphQL

The Asio portal UI runs on a GraphQL endpoint:

POST https://control.v2.itsupport247.net/GraphQL/

It authenticates with your logged-in browser session cookie (the sso-token, etc.). Two queries give us everything:

1. List every site (with numeric IDs):

query { Sites { siteDetailList { edges { node { clientId siteId companyName siteName } } } } }

2. Get a site's installer path + url (the token):

query AgentSetupQuery {
  agentSetup(
    ClientID: $ClientID  SiteID: $SiteID  OSType: $OSType
    SetupType: $SetupType  Arch: $Arch  FileName: $FileName  FileType: $FileType
  ) { path url }
}

Quirk: this gateway does literal $var text-substitution, so the operation must NOT declare its variables — keep the bare $ClientID tokens inline and pass a variables object. For Windows MSI use OSType:"windows", SetupType:"MSMA", Arch:"64", FileType:"MSI".

Response, e.g. for Acme (ClientID=SiteID=363177):

path: /windows/MSMA/64/ITSPlatform_TKN77d2779b-9a06-4fe9-b3da-0eb29c0e7bb0/MSI/setup
url:  https://prod.setup.itsupport247.net
  • Token = the GUID after TKN in path.
  • Download URL = url + path.
  • Filename = "<CompanyName>-<SiteName>" (spaces -> underscores) + _Windows_OS_ITSPlatform_TKN<token>.msi.

Key insight: tokens are static

A site's Agent Token is permanent unless someone regenerates it in the portal. So you harvest once into a table, then build installers forever with no authentication. The 12-hour session cookie only matters when refreshing the table.

The deliverables (scripts in engine/rmm/, docs in docs/)

  • RMM_Site_Tokens.csv — all 51 sites: CompanyName, SiteName, ClientId, SiteId, Token, DownloadUrl. Captured live from the portal.
  • Build-RMMInstaller.ps1 — builds/downloads installers from the CSV. No auth.
    • .\Build-RMMInstaller.ps1 -Company "Acme Electric"
    • .\Build-RMMInstaller.ps1 -All
    • .\Build-RMMInstaller.ps1 -All -ListOnly (print names/URLs only)
  • Refresh-RMMTokens.ps1 — rebuilds the CSV by calling the GraphQL endpoint. Run this when you add a customer or rotate a token. Paste a fresh portal cookie into it first.

Refreshing the table

  1. Log into control.itsupport247.net, F12 > Network, filter GraphQL, click the request, copy the full cookie: request-header value.
  2. Paste it into Refresh-RMMTokens.ps1 (-CookieHeader) and run it.
  3. It regenerates RMM_Site_Tokens.csv. The cookie is live credentials — keep the file local and clear the value after.

Superseded files (kept for reference)

Probe-CWRMM-OpenAPI.ps1 and Test-AgentSetup.ps1 were exploration steps for the OpenAPI and single-site GraphQL test. The three files above are the actual solution.