Files
claudetools/projects/gps-rmm-audit/tools/needs-sc.py
Howard Enos f61088dac4 sync: auto-sync from HOWARD-HOME at 2026-07-03 19:57:06
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-07-03 19:57:06
2026-07-03 19:57:32 -07:00

40 lines
2.2 KiB
Python

import json, urllib.request, ssl, os
from collections import Counter
BASE="https://computerguru.syncromsp.com/api/v1"
SK=os.environ["SK"]; RMM=os.environ["RMM"]; TOK=os.environ["TOK"]
ctx=ssl.create_default_context()
def get(url,hdr=None):
return urllib.request.urlopen(urllib.request.Request(url,headers=hdr or {}),context=ctx,timeout=30).read()
def clean(b): return bytes(c for c in b if c>=32 or c in (9,10,13))
agents=json.loads(clean(get(f"{RMM}/api/agents",{"Authorization":f"Bearer {TOK}"})))
by_client={}
for a in agents:
by_client.setdefault(a.get("client_name") or "",set()).add((a.get("hostname") or "").lower())
tgts=json.load(open("projects/gps-rmm-audit/targets.json"))["clients"]
folder_ctr=Counter(); body=[]; total=0
for t in tgts:
c=t["client"]; cid=t["cid"]
try: data=json.loads(clean(get(f"{BASE}/customer_assets?customer_id={cid}&per_page=100&api_key={SK}")))
except Exception as e:
body.append(f"**{c}** - ERROR: {e}\n"); continue
dev=[a for a in data.get("assets",[]) if a.get("asset_type")=="Syncro Device" and a.get("name")]
rmm=by_client.get(c,set())
gap=sorted([a for a in dev if a["name"].lower() not in rmm], key=lambda a:a["name"].lower())
if not gap: continue
total+=len(gap)
body.append(f"**{c}** - {len(dev)} managed / {len(rmm)} in RMM / {len(gap)} need install")
for a in gap:
f=a.get("policy_folder_id") or "-"
folder_ctr[str(f)]+=1
body.append(f" - {a['name']} (folder {f})")
body.append("")
out=["# GPS clients - Syncro-managed machines NOT in GuruRMM","",
"Install ScreenConnect / push agent. Syncro assets (authoritative) vs live GuruRMM, 2026-07-03.",
"`folder N` = Syncro policy_folder_id (the ScreenConnect-install policy is tied to a folder - devices in the wrong folder don't get SC).","",
"## Folder distribution across the gap machines (spot the SC-install folder vs outliers)"]
for f,n in folder_ctr.most_common():
out.append(f"- folder {f}: {n} machines")
out+=["",f"## TOTAL needing install: {total}",""]+body
open("projects/gps-rmm-audit/needs-screenconnect.md","w",encoding="utf-8").write("\n".join(out))
print(f"total={total}, folders={dict(folder_ctr)}")