sync: auto-sync from HOWARD-HOME at 2026-07-04 10:45:23

Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-07-04 10:45:23
This commit is contained in:
2026-07-04 10:45:49 -07:00
parent a1f0a3e5e8
commit ac05230cd2
5 changed files with 204 additions and 145 deletions

View File

@@ -19,6 +19,8 @@ Categories (the `[type]` tag): _(none)_ = skill/command execution failure ·
<!-- Append entries below this line -->
2026-07-04 | Howard-Home | context-loading/dataforth | [correction] grepped for 'datforth' (user misspelling), found nothing, then found wiki hits on second grep but didn't read wiki/clients/dataforth.md or projects/dataforth-dos.md; user had to say 'use the wiki'. Correct: on any client-name trigger, fuzzy-match spelling and READ the wiki article before asking the user for infra facts
2026-07-04 | Howard-Home | screenconnect/sc-cleanup | [friction] burned many tokens iterating the SERVER/Accounting remap because each WAN-map rebuild re-queried SERVER-named machines (returning all fleet SERVER sessions), re-contaminating; fix = build WAN map ONLY from unique-named (len==1) machines, never from shared names
2026-07-04 | Howard-Home | screenconnect/sc-cleanup | [correction] assumed GetSessionsByName is client-scoped; it matches by NAME across ALL clients, so writing to shared/generic names (SERVER x11, Accounting x3) cross-contaminated other clients' sessions with the last-processed client's Company. Fixed tool to skip when >1 session returned; remapped contaminated sessions to correct client via WAN IP; 5 unidentifiable sessions left blank for manual console tagging (originals were overwritten, unrecoverable).

View File

@@ -1,146 +1,122 @@
# GPS clients - Syncro-managed machines NOT in GuruRMM (ACTIVE only)
# Machines not in GuruRMM — by ScreenConnect reachability (CORRECTED)
Machines missing from GuruRMM that checked into Syncro within the last 31 days. Excluded: 50 offline >31d, 0 with no check-in data. Snapshot 2026-07-03.
`folder N` = Syncro policy_folder_id.
Online = ActiveConnections ProcessType==2 (guest agent connected). Recency = GuestInfoUpdateTime.
Rebuilt 2026-07-04. Staging installer pushed to all ONLINE machines (land in Staging -> reassign-staging.py).
## Folder distribution (active gap machines)
- folder 3577293: 12
- folder 651577: 5
- folder 4095109: 4
- folder 2948816: 4
- folder 677399: 3
- folder 667252: 3
- folder 3426849: 3
- folder 4086884: 2
- folder 677304: 2
- folder 3638391: 2
- folder 3937024: 2
- folder 4106776: 2
- folder 3204798: 2
- folder 4100925: 2
- folder 651365: 1
- folder 4086890: 1
- folder 3842122: 1
- folder 3996026: 1
- folder 613008: 1
- folder 4088509: 1
- folder 4086846: 1
- folder 3872949: 1
- folder 607593: 1
- folder 4896982: 1
- folder 696512: 1
- folder 4086906: 1
- folder 4095118: 1
- folder 3121109: 1
- folder 4088528: 1
- folder 594524: 1
## ONLINE now (17)
- CP-QB [Curtis Plumbing] (1563d)
- CURTIS-002-W7 [Curtis Plumbing] (0d)
- DESKTOP-EVA4H1A [Gary A Hartman LLC] (0d)
- IMC-PRINTSERVER [Instrumental Music Center] (0d)
- LAPTOP-UBTI0IE3 [Instrumental Music Center] (0d)
- DESKTOP-ERBA22G [Mineralogical Record] (0d)
- PUGET-CW [Mineralogical Record] (0d)
- CNX-LAB-00 [Ridgetop Group] (0d)
- RGI-DC [Ridgetop Group] (0d)
- RTG-HOST01 [Ridgetop Group] (0d)
- DESKTOP-PL2RCGL [Robyn Pittman] (0d)
- DESKTOP-2KKLG2B [Safesite] (0d)
- STAMBACK-NEW05 [Stamback Septic] (0d)
- MEL-PC [The Prairie Schooner] (0d)
- TPS-SVR [The Prairie Schooner] (0d)
- SERVER-OLD [Zeus Nestora] (0d)
- WHITE-PC [Zeus Nestora] (0d)
## TOTAL active needing install: 64
## active <=14d (31)
- BRETTWAREHOUSE [Brett Interiors] (0d)
- DESKTOP-6LL5T6B [Brett Interiors] (0d)
- KAT1 [Business Services of Tucson LLC] (0d)
- HSM-CATHY [Horseshoe Management] (1d)
- DESKTOP-3ST7GFD [Inside Track Productions] (0d)
- IMC-LUIS [Instrumental Music Center] (0d)
- IMC-M-EDSERVICE [Instrumental Music Center] (2d)
- LAPTOP-PNVA9G51 [Instrumental Music Center] (4d)
- REPAIRADMIN [Instrumental Music Center] (1d)
- DESKTOP-OC2PH4I [Marty Ryan] (0d)
- CHRISTIPC2024 [Mineralogical Record] (0d)
- DESKTOP-CLJKB39 [Multicultural Counseling Center] (6d)
- PLS-SERVER [PUTT LAND SURVEYING, INC.] (8d)
- DESKTOP-EKC9PRV [Pro-Tech Services] (0d)
- LAPTOP-73UDDTTK [Pro-Tech Services] (1d)
- RWD-CHRIS [Reliant Well Drilling and Pump Corporate] (1d)
- WILLCOXDOTADMIN [Reliant Well Drilling and Pump Corporate] (1d)
- DESKTOP-8KQIDKH [Safesite] (0d)
- DESKTOP-ARNPE1U [Safesite] (1d)
- DESKTOP-B3ELJF5 [Safesite] (1d)
- DESKTOP-BA45FRS [Safesite] (0d)
- DESKTOP-EJM109L [Safesite] (0d)
- DESKTOP-FUB3PAV [Safesite] (3d)
- DESKTOP-V3H99FC [Safesite] (1d)
- DESKTOP-V9F9L23 [Safesite] (9d)
- LAPTOP-NFB98THE [Safesite] (2d)
- JEREE [Stamback Septic] (1d)
- DESKTOP-6HT5SJ9 [The Marc Group] (0d)
- ZEUS-ACCOUNTING [Zeus Nestora] (0d)
- ZEUS-SHERRI [Zeus Nestora] (0d)
- ZEUS1 [Zeus Nestora] (0d)
**Instrumental Music Center** - 6 need install (of 14 not-in-RMM; rest offline >31d)
- DESKTOP-KRHQ5TS (folder 651365, seen 2026-06-16, 17d ago)
- IMC-LUIS (folder 651577, seen 2026-07-03, 0d ago)
- IMC-M-EDSERVICE (folder 651577, seen 2026-07-01, 2d ago)
- LAPTOP-PNVA9G51 (folder 651577, seen 2026-06-30, 3d ago)
- LAPTOP-UBTI0IE3 (folder 651577, seen 2026-07-03, 0d ago)
- REPAIRADMIN (folder 651577, seen 2026-07-02, 1d ago)
## stale 15-45d (4)
- GND-L-3 [Grabb & Durando Law Office] (20d)
- DESKTOP-KRHQ5TS [Instrumental Music Center] (15d)
- RWD-ALLENDESKTO [Reliant Well Drilling and Pump Corporate] (18d)
- DESKTOP-FMDIK0Q [Safesite] (42d)
**Safesite** - 12 need install (of 15 not-in-RMM; rest offline >31d)
- 1225-LENOVO-E14 (folder 3577293, seen 2026-07-01, 2d ago)
- 1225-LENOVO-E14 (folder 3577293, seen 2026-07-01, 2d ago)
- DESKTOP-2KKLG2B (folder 3577293, seen 2026-07-03, 0d ago)
- DESKTOP-8KQIDKH (folder 3577293, seen 2026-07-03, 0d ago)
- DESKTOP-ARNPE1U (folder 3577293, seen 2026-07-02, 1d ago)
- DESKTOP-B3ELJF5 (folder 3577293, seen 2026-07-02, 1d ago)
- DESKTOP-BA45FRS (folder 3577293, seen 2026-07-03, 0d ago)
- DESKTOP-EJM109L (folder 3577293, seen 2026-07-03, 0d ago)
- DESKTOP-FUB3PAV (folder 3577293, seen 2026-07-01, 2d ago)
- DESKTOP-V3H99FC (folder 3577293, seen 2026-07-01, 2d ago)
- DESKTOP-V9F9L23 (folder 3577293, seen 2026-06-09, 24d ago)
- LAPTOP-NFB98THE (folder 3577293, seen 2026-07-01, 2d ago)
**Horseshoe Management** - 1 need install (of 3 not-in-RMM; rest offline >31d)
- HSM-CATHY (folder 4086890, seen 2026-07-02, 1d ago)
**Grabb & Durando Law Office** - 2 need install (of 4 not-in-RMM; rest offline >31d)
- GND-ASUSWS (folder 4086884, seen 2026-07-02, 0d ago)
- GND-L-3 (folder 4086884, seen 2026-06-13, 20d ago)
**Stamback Septic** - 7 need install (of 10 not-in-RMM; rest offline >31d)
- DEREK-LAPTOP (folder 677304, seen 2026-07-03, 0d ago)
- DESKTOP-1BS5JL4 (folder 677399, seen 2026-07-03, 0d ago)
- JEREE (folder 677399, seen 2026-07-02, 1d ago)
- SERVER2 (folder 3638391, seen 2026-07-03, 0d ago)
- STAMBACK-JBECK (folder 677399, seen 2026-07-03, 0d ago)
- STAMBACK-NEW05 (folder 3638391, seen 2026-07-03, 0d ago)
- STAMBACK-NEW06 (folder 677304, seen 2026-07-03, 0d ago)
**Reliant Well Drilling and Pump Corporate** - 4 need install (of 16 not-in-RMM; rest offline >31d)
- Clarks iMac (folder 4095109, seen 2026-06-10, 23d ago)
- RWD-ALLENDESKTO (folder 4095109, seen 2026-06-16, 17d ago)
- RWD-CHRIS (folder 4095109, seen 2026-07-02, 1d ago)
- WILLCOXDOTADMIN (folder 4095109, seen 2026-07-02, 1d ago)
**Zeus Nestora** - 5 need install (of 5 not-in-RMM; rest offline >31d)
- SERVER-OLD (folder 3842122, seen 2026-07-03, 0d ago)
- WHITE-PC (folder 2948816, seen 2026-07-03, 0d ago)
- ZEUS-ACCOUNTING (folder 2948816, seen 2026-07-03, 0d ago)
- ZEUS-SHERRI (folder 2948816, seen 2026-07-03, 0d ago)
- ZEUS1 (folder 2948816, seen 2026-07-03, 0d ago)
**PUTT LAND SURVEYING, INC.** - 1 need install (of 5 not-in-RMM; rest offline >31d)
- PLS-SERVER (folder 3996026, seen 2026-06-26, 7d ago)
**Curtis Plumbing** - 2 need install (of 3 not-in-RMM; rest offline >31d)
- CP-QB (folder 613008, seen 2026-07-03, 0d ago)
- CURTIS-002-W7 (folder 4088509, seen 2026-07-03, 0d ago)
**The Prairie Schooner** - 2 need install (of 4 not-in-RMM; rest offline >31d)
- MEL-PC (folder 4086846, seen 2026-07-03, 0d ago)
- TPS-SVR (folder 3872949, seen 2026-07-03, 0d ago)
**Mineralogical Record** - 3 need install (of 5 not-in-RMM; rest offline >31d)
- CHRISTIPC2024 (folder 607593, seen 2026-07-03, 0d ago)
- DESKTOP-ERBA22G (folder 3937024, seen 2026-07-03, 0d ago)
- PUGET-CW (folder 3937024, seen 2026-07-03, 0d ago)
**Ridgetop Group** - 3 need install (of 3 not-in-RMM; rest offline >31d)
- CNX-LAB-00 (folder 667252, seen 2026-07-03, 0d ago)
- RGI-DC (folder 667252, seen 2026-07-03, 0d ago)
- RTG-HOST01 (folder 667252, seen 2026-07-03, 0d ago)
**Multicultural Counseling Center** - 1 need install (of 2 not-in-RMM; rest offline >31d)
- DESKTOP-CLJKB39 (folder 4896982, seen 2026-06-20, 13d ago)
**Brett Interiors** - 3 need install (of 3 not-in-RMM; rest offline >31d)
- BRETTWAREHOUSE (folder 4106776, seen 2026-07-03, 0d ago)
- DESKTOP-6LL5T6B (folder 4106776, seen 2026-07-03, 0d ago)
- SERVER (folder 696512, seen 2026-07-03, 0d ago)
**Heieck, Sheila** - 3 need install (of 3 not-in-RMM; rest offline >31d)
- John Heiecks iMac (folder 3426849, seen 2026-07-03, 0d ago)
- Sheila's iMac (folder 3426849, seen 2026-07-03, 0d ago)
- Sheilas MacBook Pro (folder 3426849, seen 2026-07-03, 0d ago)
**The Marc Group** - 1 need install (of 2 not-in-RMM; rest offline >31d)
- DESKTOP-6HT5SJ9 (folder 4086906, seen 2026-07-03, 0d ago)
**Business Services of Tucson LLC** - 2 need install (of 2 not-in-RMM; rest offline >31d)
- KAT (folder 3204798, seen 2026-06-03, 30d ago)
- KAT1 (folder 3204798, seen 2026-07-03, 0d ago)
**Pro-Tech Services** - 2 need install (of 2 not-in-RMM; rest offline >31d)
- DESKTOP-EKC9PRV (folder 4100925, seen 2026-07-03, 0d ago)
- LAPTOP-73UDDTTK (folder 4100925, seen 2026-07-02, 1d ago)
**Inside Track Productions** - 1 need install (of 1 not-in-RMM; rest offline >31d)
- DESKTOP-3ST7GFD (folder 4095118, seen 2026-07-03, 0d ago)
**Gary A Hartman LLC** - 1 need install (of 1 not-in-RMM; rest offline >31d)
- DESKTOP-EVA4H1A (folder 3121109, seen 2026-07-03, 0d ago)
**Robyn Pittman** - 1 need install (of 1 not-in-RMM; rest offline >31d)
- DESKTOP-PL2RCGL (folder 4088528, seen 2026-07-03, 0d ago)
**Marty Ryan** - 1 need install (of 1 not-in-RMM; rest offline >31d)
- DESKTOP-OC2PH4I (folder 594524, seen 2026-07-03, 0d ago)
## dead/no-session (58)
- DESKTOP-SUFJR0J [Bill Tedards] (no SC)
- TEDARDSLAPTOP [Bill Tedards] (no SC)
- KAT [Business Services of Tucson LLC] (no SC)
- CURTIS-003 [Curtis Plumbing] (no SC)
- GND-ASUSWS [Grabb & Durando Law Office] (no SC)
- GND-JEANNETTE [Grabb & Durando Law Office] (no SC)
- HOMEPC [Grabb & Durando Law Office] (no SC)
- John Heieck’s iMac [Heieck, Sheila] (no SC)
- Sheila's iMac [Heieck, Sheila] (no SC)
- Sheila’s MacBook Pro [Heieck, Sheila] (no SC)
- HSM-RANDI [Horseshoe Management] (no SC)
- HSM-SURFACE [Horseshoe Management] (no SC)
- DESKTOP-JQ0D38J [Instrumental Music Center] (105d)
- DESKTOP-URV3UGR [Instrumental Music Center] (79d)
- IMC-EVENTS [Instrumental Music Center] (110d)
- IMC-L1-GRAPHICS [Instrumental Music Center] (no SC)
- PHIL [Instrumental Music Center] (no SC)
- PHIL2021LAPTOP [Instrumental Music Center] (141d)
- PURCHASINGCOMP [Instrumental Music Center] (79d)
- LHLH [Little Hearts Little Hands] (no SC)
- WIN-KNVO6MUMMEM [Little Hearts Little Hands] (no SC)
- CPC-chris-UZR6E [MVAN Enterprises Inc] (no SC)
- DESKTOP-I7504C5 [MVAN Enterprises Inc] (no SC)
- June’s MacBook Pro [MVAN Enterprises Inc] (no SC)
- MITCH-LAPTOP [MVAN Enterprises Inc] (138d)
- DESKTOP-3VPT017 [Mineralogical Record] (no SC)
- DESKTOP-9QHSCIT [Mineralogical Record] (no SC)
- DESKTOP-S1HPLDF [Multicultural Counseling Center] (64d)
- PLS-FOUR [PUTT LAND SURVEYING, INC.] (no SC)
- PLS-FRONT [PUTT LAND SURVEYING, INC.] (no SC)
- PLS-LAPTOP [PUTT LAND SURVEYING, INC.] (no SC)
- PLS-ONE [PUTT LAND SURVEYING, INC.] (no SC)
- DESKTOP-A3IVMNF [Quantum Wealth Management] (no SC)
- Clark’s iMac [Reliant Well Drilling and Pump Corporate] (no SC)
- DESKTOP-09H7T66 [Reliant Well Drilling and Pump Corporate] (no SC)
- DESKTOP-QIGH458 [Reliant Well Drilling and Pump Corporate] (no SC)
- DESKTOP-V2247T9 [Reliant Well Drilling and Pump Corporate] (no SC)
- LAPTOP-8AUEP9N6 [Reliant Well Drilling and Pump Corporate] (no SC)
- LAPTOP-EJL9PFOU [Reliant Well Drilling and Pump Corporate] (no SC)
- LAPTOP-FR4QN9KF [Reliant Well Drilling and Pump Corporate] (no SC)
- LAPTOP-JQMU8N9K [Reliant Well Drilling and Pump Corporate] (no SC)
- RELIANT-L01 [Reliant Well Drilling and Pump Corporate] (no SC)
- RELIANT-L02 [Reliant Well Drilling and Pump Corporate] (no SC)
- RELIANT-L03 [Reliant Well Drilling and Pump Corporate] (no SC)
- RWD-ALANLAPTOP [Reliant Well Drilling and Pump Corporate] (126d)
- WILCOXADMIN [Reliant Well Drilling and Pump Corporate] (no SC)
- 1225-LENOVO-E16 [Safesite] (49d)
- DESKTOP-QAR6D04 [Safesite] (142d)
- DEREK-LAPTOP [Stamback Septic] (no SC)
- DESKTOP-1BS5JL4 [Stamback Septic] (no SC)
- DESKTOP-JVLQQIJ [Stamback Septic] (no SC)
- SSS-SPARE [Stamback Septic] (no SC)
- STAMBACK-JBECK [Stamback Septic] (no SC)
- STAMBACK-NEW06 [Stamback Septic] (no SC)
- STAMBACK-NEW06 [Stamback Septic] (no SC)
- LAPTOP-JMUNGO [The Marc Group] (54d)
- DESKTOP-SRUOH4R [The Prairie Schooner] (no SC)
- DESKTOP-TS1P9MT [The Prairie Schooner] (no SC)

View File

@@ -194,3 +194,15 @@ Built:
- projects/gps-rmm-audit/tools/reassign-staging.py: moves Staging agents to their real client via POST /api/agents/:id/move, matching hostname->Syncro customer business_name->GuruRMM client (main site). Idempotent; --dry supported. Verified runs clean (0 staging agents currently).
Next: Howard adds the one-liner to the Syncro all-machines policy; schedule reassign-staging.py (or fold into the daily GPS-RMM-Progress task). Unmatched agents stay in Staging + flagged.
## Update: Corrected online detection + Staging auto-enroll (WORKS end-to-end)
Howard caught that machines marked "offline 45+ days" were actually online. Two bugs found + fixed:
1. Online field: was reading GuestConnectedCount (always null -> everything looked offline). Correct = ActiveConnections with ProcessType==2 (guest agent connected); recency via GuestInfoUpdateTime.
2. Age metric: needs-list used Syncro last_synced_at (Syncro agent check-in, goes stale when the agent breaks) instead of ScreenConnect reachability.
Built projects/gps-rmm-audit/tools/rebuild-and-push.py: rebuilds needs-screenconnect.md by SC reachability (ONLINE now / active<=14d / stale15-45 / dead) and pushes the generic Staging installer (DARK-STORM-3150, base64 -EncodedCommand via SendCommandToSession) to every ONLINE machine. Ran it: 17 online -> pushed all 17 -> 15 enrolled into Staging within ~2 min. (Counts: online 17, active<=14d 31, stale 4, dead 58.)
reassign-staging.py sorted all 15 to their real clients (Curtis, Mineralogical, IMC, Prairie Schooner, Zeus, Stamback + Ridgetop/Gary Hartman/Robyn Pittman). Surfaced 3 clients I'd wrongly written off as no-footprint (Ridgetop has 3 machines, Gary Hartman 1, Robyn Pittman 1) - onboarded them. Added name normalization to reassign (strip LLC/Inc/Corp/etc.) so Syncro 'Safesite LLC' matches GuruRMM 'Safesite'. Staging now empty (all reassigned).
Proven pipeline: correct-online -> push staging installer -> enroll -> auto-reassign. Ready to repeat as machines come online (or via the Syncro all-machines policy Howard will add).

View File

@@ -24,11 +24,16 @@ def syncro_customer(hostname):
c=a.get("customer") or {}
return c.get("business_name") or c.get("fullname")
return None
import urllib.parse
import urllib.parse,re
def norm(s):
s=(s or "").lower().strip()
s=re.sub(r'[.,]',' ',s)
s=re.sub(r'\b(llc|inc|incorporated|corp|corporation|company|co|ltd|the)\b',' ',s)
return re.sub(r'\s+',' ',s).strip()
agents=rget("/api/agents")
staging=[a for a in agents if a.get("client_name")==STAGING_CLIENT]
print(f"{len(staging)} agents in Staging")
# GuruRMM client -> a target site id (prefer 'Main'/'Main Office', else first)
# GuruRMM client -> a target site id (prefer 'Main'/'Main Office', else first); keyed by normalized name
clients=rget("/api/clients")
name2site={}
for c in clients:
@@ -36,11 +41,11 @@ for c in clients:
sites=rget(f"/api/clients/{c['id']}/sites")
if not sites: continue
main=next((s for s in sites if s["name"].lower() in ("main","main office","office")), sites[0])
name2site[c["name"].lower()]=main["id"]
name2site[norm(c["name"])]=main["id"]
moved=0; unmatched=[]
for a in staging:
cust=syncro_customer(a["hostname"])
site=name2site.get((cust or "").lower())
site=name2site.get(norm(cust))
if cust and site:
if not DRY: move(a["id"],site)
moved+=1; print(f" {a['hostname']} -> '{cust}'")

View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python3
# rebuild-and-push.py — rebuild the "machines not in GuruRMM" list using the CORRECT
# ScreenConnect online signal (ActiveConnections ProcessType==2 = guest agent connected;
# GuestInfoUpdateTime for recency), NOT Syncro's stale last_synced_at. Then push the
# generic STAGING installer to every machine that is ONLINE right now (it will actually
# land instead of queuing). Machines enroll into Staging -> reassign-staging.py sorts them.
#
# Env: RMM, TOK (GuruRMM), SK (Syncro), SC_SECRET (ScreenConnect). --dry = no pushes.
import json,urllib.request,ssl,os,sys,base64,datetime,urllib.parse
sys.stdout.reconfigure(encoding='utf-8',errors='replace')
RMM=os.environ["RMM"]; TOK=os.environ["TOK"]; SK=os.environ["SK"]; SEC=os.environ["SC_SECRET"]
ctx=ssl.create_default_context(); DRY="--dry" in sys.argv
SB="https://computerguru.screenconnect.com/App_Extensions/2d558935-686a-4bd0-9991-07539f5fe749/Service.ashx"
STAGING_ONELINER="irm 'https://rmm.azcomputerguru.com/install/DARK-STORM-3150/windows'|iex"
ENC=base64.b64encode(STAGING_ONELINER.encode("utf-16-le")).decode()
PUSHCMD=f"powershell -NoProfile -ExecutionPolicy Bypass -EncodedCommand {ENC}"
def scp(m,b):
req=urllib.request.Request(f"{SB}/{m}",data=json.dumps(b).encode(),method="POST",headers={"CTRLAuthHeader":SEC,"Origin":"https://computerguru.screenconnect.com","Content-Type":"application/json"})
try:return json.loads(urllib.request.urlopen(req,context=ctx,timeout=25).read().decode("utf-8","replace"))
except Exception as e:return {"__err":str(e)}
def rget(p):
return json.loads("".join(c for c in urllib.request.urlopen(urllib.request.Request(f"{RMM}{p}",headers={"Authorization":f"Bearer {TOK}"}),context=ctx,timeout=30).read().decode("utf-8","replace") if ord(c)>=32 or c in "\t\n\r"))
def assets(cid):
raw=urllib.request.urlopen(urllib.request.Request(f"https://computerguru.syncromsp.com/api/v1/customer_assets?customer_id={cid}&per_page=100&api_key={SK}"),context=ctx,timeout=25).read()
raw="".join(chr(b) for b in raw if b>=32 or b in (9,10,13))
return [a["name"] for a in json.loads(raw).get("assets",[]) if a.get("asset_type")=="Syncro Device" and a.get("name")]
def online(s): return any(c.get("ProcessType")==2 for c in (s.get("ActiveConnections") or []))
def recency_days(s):
for f in ("GuestInfoUpdateTime","LastGuestConnectedEventTime"):
t=s.get(f)
if t and not str(t).startswith("0001"):
try: return (datetime.datetime.utcnow()-datetime.datetime.strptime(str(t)[:19],"%Y-%m-%dT%H:%M:%S")).days
except: pass
return None
rmm=set(a["hostname"].lower() for a in rget("/api/agents") if a.get("hostname"))
tgts=json.load(open("projects/gps-rmm-audit/targets.json"))["clients"]
groups={"ONLINE now":[],"active <=14d":[],"stale 15-45d":[],"dead/no-session":[]}
pushed=0; failed=0
for t in tgts:
for h in assets(t["cid"]):
if h.lower() in rmm: continue
ss=scp("GetSessionsByName",{"sessionName":h})
if not (isinstance(ss,list) and ss): groups["dead/no-session"].append((t["client"],h,"no SC")); continue
if len(ss)>1: continue # ambiguous shared name -> skip
s=ss[0]; d=recency_days(s)
if online(s):
groups["ONLINE now"].append((t["client"],h,f"{d}d" if d is not None else "?"))
if not DRY:
r=scp("SendCommandToSession",[s["SessionID"],PUSHCMD])
if isinstance(r,dict) and r.get("__err"): failed+=1
else: pushed+=1
elif d is not None and d<=14: groups["active <=14d"].append((t["client"],h,f"{d}d"))
elif d is not None and d<=45: groups["stale 15-45d"].append((t["client"],h,f"{d}d"))
else: groups["dead/no-session"].append((t["client"],h,f"{d}d" if d is not None else "old"))
out=["# Machines not in GuruRMM — by ScreenConnect reachability (CORRECTED)","",
"Online = ActiveConnections ProcessType==2 (guest agent connected). Recency = GuestInfoUpdateTime.",
f"Rebuilt {datetime.date(2026,7,4)}. Staging installer pushed to all ONLINE machines (land in Staging -> reassign-staging.py).",""]
for g,items in groups.items():
out.append(f"## {g} ({len(items)})")
for c,h,d in sorted(items): out.append(f"- {h} [{c}] ({d})")
out.append("")
open("projects/gps-rmm-audit/needs-screenconnect.md","w",encoding="utf-8").write("\n".join(out))
print(f"ONLINE now: {len(groups['ONLINE now'])} | active<=14d: {len(groups['active <=14d'])} | stale15-45: {len(groups['stale 15-45d'])} | dead: {len(groups['dead/no-session'])}")
print(f"Staging installer pushed: {pushed} (failed {failed}){' [DRY]' if DRY else ''}")