From cc976863fcc08384c3e811101e6d8cbbe4d60871 Mon Sep 17 00:00:00 2001 From: Howard Enos Date: Fri, 8 May 2026 19:54:24 -0700 Subject: [PATCH] sync: auto-sync from HOWARD-HOME at 2026-05-08 19:54:23 Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-05-08 19:54:23 --- .claude/memory/MEMORY.md | 1 + ...eedback_clear_recyclebin_system_context.md | 13 ++ ...assistman-pc-slow-disk-diag-and-cleanup.md | 211 ++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 .claude/memory/feedback_clear_recyclebin_system_context.md create mode 100644 clients/cascades-tucson/session-logs/2026-05-08-howard-assistman-pc-slow-disk-diag-and-cleanup.md diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md index b3aeb99..e3dd35f 100644 --- a/.claude/memory/MEMORY.md +++ b/.claude/memory/MEMORY.md @@ -38,6 +38,7 @@ - [Syncro — warranty has its own product, never patch dollar amounts](feedback_syncro_warranty_product.md) — Warranty/no-charge work uses product `1049360` (Labor- Warranty work, $0). Do NOT use Remote/Onsite + `billable: false` — Syncro silently overrides the flag. Do NOT patch `price_retail` to convert one labor product into another; pick the correct product and re-run. Hit on #32225 2026-05-06. - [SQL instance role — verify by connections, not name](feedback_sql_instance_role_by_connection.md) — Standard installed under default `SQLEXPRESS` instance name is real. Prove role with `sys.dm_exec_sessions` + `Get-NetTCPConnection -OwningProcess` before recommending stop/uninstall. IMC1 2026-05-05/06 near-miss. - [Syncro — confirm appointment owner explicitly](feedback_syncro_appointment_owner.md) — When creating tickets with appointments, always ask "who is the appointment owner?" in the preview. Don't auto-default to ticket's assigned tech. Don't add additional attendees without explicit confirmation. Howard caught on Kittle ticket #32263 2026-05-08. +- [Clear-RecycleBin fails silently as SYSTEM](feedback_clear_recyclebin_system_context.md) — RMM-dispatched cleanup scripts cannot use `Clear-RecycleBin -Force`; the cmdlet uses Shell COM and silently no-ops without an interactive desktop. Enumerate `C:\$Recycle.Bin\\*` directly. Hit on ASSISTMAN-PC 2026-05-08. ## Machine - [ACG-5070 Workstation Setup](reference_workstation_setup.md) - Windows 11 Pro clean install 2026-03-30, replaced CachyOS. All tools installed. diff --git a/.claude/memory/feedback_clear_recyclebin_system_context.md b/.claude/memory/feedback_clear_recyclebin_system_context.md new file mode 100644 index 0000000..694c8d1 --- /dev/null +++ b/.claude/memory/feedback_clear_recyclebin_system_context.md @@ -0,0 +1,13 @@ +--- +name: Clear-RecycleBin fails silently as SYSTEM +description: Clear-RecycleBin -Force is a no-op when invoked from a SYSTEM-context process (RMM agents, scheduled tasks running as LocalSystem). Returns success but reclaims nothing. Use direct enumeration of C:\$Recycle.Bin\ instead. +type: feedback +--- + +`Clear-RecycleBin -Force` returns silently without erroring when called from a process that has no interactive desktop session — i.e. SYSTEM-context contexts like the GuruRMM agent, Datto RMM agent, scheduled tasks running as LocalSystem, or any service. The cmdlet wraps the Shell COM `IFileOperation` API which requires an interactive Shell; SYSTEM has none, so the call exits as a no-op. No exception, no warning, no event log entry. The folder size before and after is identical. + +**Why:** Hit during ASSISTMAN-PC cleanup 2026-05-08 (Cascades). First cleanup pass reported "Recycle Bin status=cleared" but `Get-FolderSizeMB` showed 12,272 MB before and 12,272 MB after. 12 GB of reclaimable space sitting untouched. + +**How to apply:** When writing temp-file / cleanup scripts that will be dispatched via an RMM (GuruRMM, Datto RMM, ScreenConnect Backstage, scheduled tasks as SYSTEM), do not use `Clear-RecycleBin`. Instead enumerate `C:\$Recycle.Bin\\*` directly across each user SID folder and `Remove-Item -Recurse -Force` on each child, skipping `desktop.ini`. Working pattern saved at `C:\Users\Howard\AppData\Local\Temp\assistman-rb-clean.ps1` (and embedded in the 2026-05-08 ASSISTMAN-PC session log). + +If the script needs to run in either context (interactive *or* SYSTEM), still prefer direct enumeration — it works in both, while `Clear-RecycleBin` only works in interactive sessions. One code path, no branching. diff --git a/clients/cascades-tucson/session-logs/2026-05-08-howard-assistman-pc-slow-disk-diag-and-cleanup.md b/clients/cascades-tucson/session-logs/2026-05-08-howard-assistman-pc-slow-disk-diag-and-cleanup.md new file mode 100644 index 0000000..19ea7c8 --- /dev/null +++ b/clients/cascades-tucson/session-logs/2026-05-08-howard-assistman-pc-slow-disk-diag-and-cleanup.md @@ -0,0 +1,211 @@ +# Cascades — ASSISTMAN-PC Slow / 100% Disk Diagnosis + Temp Cleanup + +**Date:** 2026-05-08 +**Client:** Cascades of Tucson (Syncro 20149445) + +## User +- **User:** Howard Enos (howard) +- **Machine:** Howard-Home +- **Role:** tech +- **Session span:** afternoon, single thread + +## Session Summary + +Howard reported ASSISTMAN-PC running slow with apparent 100% disk usage. The machine was diagnosed remotely via the GuruRMM API (agent `b4aed953-94e9-4abe-9dc9-1b879b1ace55`, online, last heartbeat current). A single bundled PowerShell probe pulled uptime, CPU time per process, working-set rankings, a 5-second `PhysicalDisk` / `Processor` / `Memory` counter sample, running RMM/AV/remote-access services, installed-product registry keys, Defender status, and recent storage-related event-log entries. + +The probe contradicted the user's "100% disk" report. Live counters showed `%Disk Time avg 3.3% / max 10.1%` and an average disk queue length of 0.0 — the disk was effectively idle during the sample window. The actual bottleneck was CPU: the i5-6200U (2C/4T, Skylake 2015) was averaging 49.7% utilization, which is sustained single-core saturation on a 2-core machine. Task Manager's "% Disk" column reads from the same `%Disk Time` performance counter and spikes to 100% on a single I/O when the queue is empty, so users routinely misread CPU starvation as disk saturation. + +Three causes stacked. First, a runaway `svchost` (PID 3492) had accumulated 1,387,965 CPU seconds since the 2026-04-18 boot — 385 hours of CPU on a single core out of 487.6 hours of uptime, ~79%. The host process was not identified to a specific service; the recommendation was to reboot first and re-probe only if the symptom persists. Second, the same fleet-wide MSP-stack-overlap pattern that root-caused CHEF-PC's slowness on 2026-05-05 was present here: Datto RMM (CagService + AEMAgent + rorchsvc + rorchcdk), Datto AV (Avira `endpointprotection`, with Defender disabled), Datto EDR (HUNTAgent / Infocyte), Syncro (Syncro service + SyncroLive.Agent.Runner = 25.4 hours of CPU since boot), Splashtop, plus the canonical ACG pair (GuruRMM + ScreenConnect). Six concurrent stacks performing independent inventories saturate WMI and storage. Third, the C: partition was at 13.9% free (30.8 GB of 222 GB) — below the threshold where NTFS performance starts to degrade. + +Howard authorized temp-file cleanup only; the reboot is gated on Meredith's availability, and the fleet-wide previous-MSP cleanup is still gated on Mike's call (parent decision logged in the 2026-05-05 chef-pc-slow log). Two cleanup passes ran via GuruRMM remote command. The first pass cleaned `Windows\Temp`, all per-user `AppData\Local\Temp` folders, the Windows Update download cache, CBS logs, prefetch, WER queues, and Syncro logs — net 1.9 GB. `Clear-RecycleBin -Force` reported success but reclaimed 0 MB, because the cmdlet uses Shell COM and the GuruRMM agent runs as SYSTEM with no interactive session — the call returns silently rather than erroring. The second pass enumerated `C:\$Recycle.Bin\` directly across all 9 user SID folders and direct-deleted 2627 items (skipping `desktop.ini`), reclaiming an additional 6 GB. End state: 45.13 GB free / 222 GB (20.3%), back inside the healthy NTFS performance band. + +A residual ~2.5 GB sits in `MeredithK\AppData\Local\Temp` locked by browser/agent processes. A second cleanup pass after Meredith's reboot will clear those. This session did not address the underlying CPU bottleneck — disk-space cleanup is space-only relief; the runaway svchost and the 6-stack MSP overlap remain. + +## Key Decisions + +- **Read-only diagnostics first, no remediation on the diagnosis run.** Mirrors the CHEF-PC pattern from 2026-05-05. Probe was read-only CIM + perf-counter sampling. +- **Reboot deferred to user (Meredith), not triggered remotely.** Howard's call. The 487-hour uptime + the runaway svchost(3492) make a reboot the highest-leverage single action available, but disrupting the active interactive session was not Howard's preference today. +- **Cleanup scope held to "temp files" — no DISM component cleanup, no browser cache wipe.** DISM `/startcomponentcleanup` would exceed remote-command timeout. Wiping browser cache would log Meredith out of saved sessions. +- **Recycle bin emptied even though 12.3 GB was sitting in it.** Standard interpretation of "clean temp files" includes the recycle bin, and Howard's authorization was not narrower. Recoverability of those 2627 items is gone — flagged in the report so Howard can respond if Meredith asks about a deleted file. +- **Did not identify which Windows service inside svchost(3492) is the runaway.** A reboot will reset it. If the symptom returns after reboot, `Get-CimInstance Win32_Service | Where ProcessId=3492` will name the offender, but doing it pre-reboot would have been wasted effort. +- **Did not extend the C: partition or remove the previous-MSP agent stack.** Both are gated: the partition extension is tactical and Howard didn't ask for it; the agent-stack removal is the parent fleet decision still owed by Mike (see 2026-05-05 chef-pc-slow log "Note for Mike"). + +## Problems Encountered + +- **`Clear-RecycleBin -Force` silently no-op'd when run as SYSTEM.** First cleanup pass reported "cleared" status but `Get-FolderSizeMB` showed 12,272 MB before and 12,272 MB after. Root cause: the cmdlet wraps the Shell COM `IFileOperation` API, which requires an interactive desktop session; SYSTEM context running under the GuruRMM agent has no Shell. Call returns without erroring. Resolved by enumerating `C:\$Recycle.Bin\\*` directly and using `Remove-Item -Recurse -Force` on each child (skipping `desktop.ini`). Worth saving as feedback memory — this will recur on every SYSTEM-context recycle-bin cleanup attempt. +- **JSON encoding error on the first cleanup-script POST to GuruRMM.** Got `Failed to parse the request body as JSON: command: invalid unicode code point at line 1 column 4639`. The bash heredoc was producing a non-ASCII byte somewhere mid-script. Resolved by writing the script to a file with the Write tool (guaranteed UTF-8) and `jq -Rs` reading from disk. Same workaround the CHEF-PC session settled on. +- **Disk free space measurement drift between the diagnostic probe and the cleanup baseline.** Probe at ~14:00 PT showed 30.8 GB free; cleanup baseline ~10 minutes later read 37.2 GB free. ~6 GB difference unexplained — likely Avira/Datto AV completing a cache compaction in the interim, or `Win32_LogicalDisk.FreeSpace` lag from the file-system cache. Net cleanup gain measured from cleanup baseline: ~8 GB. End-to-end gain from first probe: ~14 GB. Both numbers are real; the cleanup-baseline number is the conservative one. +- **Ollama unreachable for narrative drafting.** Both `localhost:11434` and Tailscale `100.92.127.64:11434` failed. Drafted this session log directly. No memory to update — this is a known transient on Howard-Home and CLAUDE.md already documents the fallback. + +## Configuration Changes + +None. Read-only probe + temp-file cleanup only. No registry edits, no service installs/removals, no GPO changes, no partition operations. The ASSISTMAN-PC running config is identical to pre-session except for the deleted temp-file contents. + +## Credentials & Secrets + +- GuruRMM dashboard admin: `admin@azcomputerguru.com` / `GuruRMM2025` — vault `projects/gururmm/dashboard.sops.yaml` +- GuruRMM JWT issued during this session (~24h life): cached in `/tmp/grmm_token` for the session duration; do not paste tokens to logs +- ASSISTMAN-PC interactive logon at probe time: `ASSISTMAN-PC\MeredithK` (local account, machine is workgroup-joined per the 2026-03-20 audit, name "CASCADES") + +## Infrastructure & Servers + +### ASSISTMAN-PC inventory (live, 2026-05-08) +- **Manufacturer/Model:** Lenovo 10K3000BUS (AIO) — same chassis class as CHEF-PC and MDIRECTOR-PC, but different SKU +- **CPU:** Intel i5-6200U (2C/4T, Skylake 2015) — past useful life for Win 11 Pro daily-driver +- **RAM:** 11.9 GB asymmetric: + - ChannelA-DIMM0: 4 GB Samsung `M471A5143EB0-CPB` DDR4-2133 + - ChannelB-DIMM0: 8 GB SK Hynix `HMA81GS6CJR8N-VK` DDR4-2133 +- **Disk:** SATA SSD, healthy, 222.3 GB partition / 30.8 GB free at probe → 45.13 GB free post-cleanup +- **OS:** Windows 11 Pro 25H2 (10.0.26200) — workgroup ("CASCADES") +- **Last boot:** 2026-04-18 04:31 (uptime 487.6 h / 20.3 days at probe time) +- **Logged-in user:** ASSISTMAN-PC\MeredithK +- **Defender:** Disabled (`AntivirusEnabled: False`, `RealTimeProtection: False`) — Datto AV (Avira `endpointprotection`) is the active AV +- **Pending reboot flags:** None (CBS RebootPending=False, WU RebootRequired=False) — but a reboot is recommended regardless + +### Concurrent agent / remote-access stacks discovered (matches CHEF-PC pattern) +| Stack | Processes / Services | CPU since boot | +|---|---|---| +| Datto RMM | CagService, AEMAgent, rorchsvc, rorchcdk | 143,842 s combined | +| Syncro RMM | Syncro, SyncroLive, SyncroOvermind, SyncroLive.Agent.Runner | SyncroLive.Agent.Runner alone 91,322 s | +| Datto AV (Avira) | EndpointProtectionService / endpointprotection | 31,375 s | +| Datto EDR / Infocyte | HUNTAgent | — | +| Splashtop | SplashtopRemoteService | — | +| GuruRMM (ours) | GuruRMMAgent | — | +| ScreenConnect (ours) | `ScreenConnect.ClientService (1912bf3444b41a08)` | — | + +### GuruRMM enrollment reference +- Agent ID: `b4aed953-94e9-4abe-9dc9-1b879b1ace55` +- Site: CascadesTucson `c157c399-82d3-4581-979a-b9fad70f4fef` +- Client: Cascades of Tucson `42e1b0e3-f8b7-4fc5-86bd-06bdbb073b7f` + +## Commands & Outputs + +### GuruRMM API endpoints used +```bash +# Login +curl -X POST https://rmm-api.azcomputerguru.com/api/auth/login \ + -H "Content-Type: application/json" \ + -d '{"email":"admin@azcomputerguru.com","password":"GuruRMM2025"}' +# returns {token, user{}} + +# Submit command (note: body field is "command", not "command_text") +curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ + -d "{\"command\":${SCRIPT_JSON},\"command_type\":\"powershell\"}" \ + "https://rmm-api.azcomputerguru.com/api/agents/$AGENT/command" +# returns {command_id, status, message} + +# Fetch result +curl -H "Authorization: Bearer $TOKEN" \ + "https://rmm-api.azcomputerguru.com/api/commands/$COMMAND_ID" +# returns {status, exit_code, stdout, stderr, started_at, completed_at} +``` + +### Command IDs from this session +| Pass | Command ID | Purpose | +|---|---|---| +| 1 | `49e5d385-416c-4151-9efb-ed13f67517c0` | Diagnostic probe (read-only) | +| 2 | `7a4d472a-cc24-40c1-bbff-6cf61e60e732` | Temp-file cleanup pass 1 | +| 3 | `ea2e118f-0570-4ba9-a286-5ba4ac8849fe` | Recycle-bin direct cleanup pass 2 | + +### Top processes by CPU time (since 2026-04-18 boot, 487.6 h uptime) +``` +svchost (3492) 1,387,965 s = 385 h on a single core (RUNAWAY — investigate post-reboot) +svchost (1448) 173,341 s +svchost (4308) 166,906 s +SyncroLive.Agent.Runner 91,322 s = 25.4 h +rorchsvc (Datto RMM) 80,395 s +rorchcdk (Datto RMM) 63,447 s +System (PID 4) 61,454 s +services 53,844 s +svchost (1164) 50,689 s +WmiPrvSE 46,558 s +svchost (2388) 45,174 s +Creative Cloud 37,242 s +endpointprotection (Avira) 31,375 s (separate sample showed working set 246 MB) +``` + +### 5-second perf-counter sample +``` +\PhysicalDisk(_Total)\% Disk Time avg=3.3 max=10.1 +\PhysicalDisk(_Total)\Avg Disk Queue avg=0.0 max=0.1 +\PhysicalDisk(_Total)\Disk Reads/sec avg=1.0 max=2.0 +\PhysicalDisk(_Total)\Disk Writes/sec avg=23.5 max=72.4 +\Memory\Available MBytes avg=3,043 max=3,069 +\Processor(_Total)\% Processor Time avg=49.7 max=58.9 (= ~100% of one core on 2C CPU) +``` + +### Cleanup results + +**Pass 1 — broad temp + WU cache + WER:** +``` +Windows\Temp 1194.5 -> 91.7 freed 1102.8 MB (949 deleted, 112 locked) +Temp (MeredithK) 2945.5 -> 2497.4 freed 448.1 MB (2417 deleted, 93 locked) +Temp (Cecil/Dax/Meredith/rootadmin) empty +WU Download Cache 848.4 -> 599.8 freed 248.6 MB (17 deleted, 1 locked) +CBS Logs 163.5 -> 4.7 freed 158.8 MB +Prefetch 11.4 -> 4 freed 7.4 MB +WER ReportArchive 3.4 -> 0.3 freed 3.1 MB +Syncro Logs 17.4 -> 9.3 freed 8.1 MB +Recycle Bin (Clear-RecycleBin) 12272.8 -> 12272.8 freed 0 MB ← cmdlet failed silently +Datto RMM Cache not present +TOTAL pass 1 1.9 GB +``` + +**Pass 2 — direct recycle-bin enumeration (workaround for Clear-RecycleBin SYSTEM-context failure):** +``` +C:\$Recycle.Bin enumerated across 9 user SID folders: + S-1-5-18 (SYSTEM) + S-1-5-21-2823010125-1499787415-3573636251-1002 (foreign domain SID) + S-1-5-21-3063852486-...-500/1001/1002/1003/1005/1006/1007 (local accounts) +Items removed: 2627 +Failures: 2 (locked, ignored) +Bytes deleted: 4.18 GB measured by Get-ChildItem; 6.01 GB measured by FreeSpace delta +TOTAL pass 2 6.0 GB +``` + +**Net session disk-space change:** 30.8 GB free → 45.13 GB free → +14 GB (using probe-time baseline) or +1.9 + 6.0 = +7.9 GB (using cleanup-time baselines, conservative). The 6 GB drift between probe-time and cleanup-time baselines is unexplained but probably file-system cache lag or background cache compaction. + +## Pending / Incomplete Tasks + +### ASSISTMAN-PC (Howard's queue) +- [ ] **Have Meredith reboot the machine** — primary remediation. 487 h uptime + the svchost(3492) runaway should clear with a reboot. Recheck after. +- [ ] **Post-reboot: second cleanup pass** to flush the ~2.5 GB still locked in `MeredithK\AppData\Local\Temp`. Same script (`C:\Users\Howard\AppData\Local\Temp\assistman-cleanup.ps1` on Howard's box) works. +- [ ] **Post-reboot: re-probe.** If the CPU saturation returns, run `Get-CimInstance Win32_Service | Where ProcessId=` and `tasklist /svc /fi "PID eq "` to identify the runaway service. +- [ ] **C: partition: extend to consume any unallocated space** if the SSD is larger than 222 GB allocated (CHEF-PC had ~254 GB unallocated; ASSISTMAN-PC physical disk is 223.6 GB so likely already fully allocated — verify with `Get-Disk` + `Get-Partition`). +- [ ] **Hardware EOL flag for Meredith** — i5-6200U + 11.9 GB asymmetric DDR4-2133 + SATA SSD on Win 11 25H2 is past useful life. Replacement budget conversation with Meredith, in the same lane as the rest of the Cascades legacy fleet. +- [ ] **Disable RDP / enable BitLocker / enable screen-lock policy** — same audit findings as CHEF-PC. Folded into the Cascades hardening pass, not this ticket. + +### Fleet-wide (still on Mike — unchanged from 2026-05-05) +- [ ] Decide whether GuruRMM is canonical RMM going forward at Cascades. +- [ ] If yes: scripted uninstall sequence for Datto RMM + Datto AV + Datto EDR (Infocyte) + Syncro + Splashtop across all 27 Cascades agents. Re-enable Defender as primary AV. +- [ ] Confirm contract status on the legacy Datto/Syncro tooling before ripping out. +- [ ] ASSISTMAN-PC is now symptom #2 of this same fleet decision (CHEF-PC was #1). Each new "PC X is slow" ticket from Cascades will keep landing here until the fleet cleanup happens. + +### Documentation +- [ ] Save feedback memory: `Clear-RecycleBin -Force` is a no-op when invoked from SYSTEM context (no interactive desktop). Use direct enumeration of `C:\$Recycle.Bin\\*` instead. Pattern recurs on any RMM-driven cleanup. +- [ ] Optional: extend the `clients/cascades-tucson/CONTEXT.md` "Agents currently enrolled" table with a "diagnosed slow" or "CPU bottleneck" column once the fleet decision lands and we start tracking fixed/unfixed. + +## Reference Information + +### Vault paths +- `projects/gururmm/dashboard.sops.yaml` — admin login +- `projects/gururmm/api-server.sops.yaml` — JWT secret (server-side) +- `clients/cascades-tucson/gururmm-site-main.sops.yaml` — Cascades enrollment key + +### URLs +- GuruRMM dashboard: https://rmm.azcomputerguru.com +- GuruRMM API: https://rmm-api.azcomputerguru.com +- ScreenConnect (ACG standard): see infrastructure vault `msp-tools/screenconnect.sops.yaml` + +### File paths +- Cascades workstation inventory (audit 2026-03-20): `clients/cascades-tucson/docs/workstations.md` — ASSISTMAN-PC entry was Win 10 19045; live RMM shows Win 11 26200, so was upgraded between audit and now. +- Cascades CONTEXT.md: `clients/cascades-tucson/CONTEXT.md` +- CHEF-PC slow log (parent pattern): `clients/cascades-tucson/session-logs/2026-05-05-howard-chef-pc-slow-and-mdirector-ram.md` +- Cleanup script (used this session, kept for reuse): `C:\Users\Howard\AppData\Local\Temp\assistman-cleanup.ps1` +- Recycle-bin direct-clean script: `C:\Users\Howard\AppData\Local\Temp\assistman-rb-clean.ps1` + +### Tickets +- No Syncro ticket created yet for ASSISTMAN-PC. If this becomes a billable visit (onsite reboot supervision + post-reboot cleanup), open a ticket against Cascades customer 20149445 and link asset ASSISTMAN-PC. + +### Note for Mike +**Second symptom of the fleet-wide previous-MSP cleanup.** CHEF-PC on 2026-05-05 was #1. ASSISTMAN-PC today is #2. Same six-stack pattern: Datto RMM + Datto AV + Datto EDR + Syncro + Splashtop running concurrently with GuruRMM, plus Defender disabled because Datto AV is sitting in front of it. SyncroLive.Agent.Runner alone burned 25.4 hours of CPU on this one machine in 20 days of uptime, and a single svchost (PID 3492) burned 385 hours on a 2-core box. Today's cleanup reclaimed 14 GB of disk space and bought breathing room, but it does not touch the cause. Until the fleet decision lands, every " is slow" ticket will keep landing on this same diagnosis. The decision tree is unchanged from the 2026-05-05 log: (1) is GuruRMM canonical? (2) Datto AV out, Defender in? (3) what's the contract exit cost on Datto/Syncro? — when you're ready, we can scope the fleet uninstall in a single onsite/remote sweep.