sync: auto-sync from HOWARD-HOME at 2026-07-14 17:02:24
Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-07-14 17:02:24
This commit is contained in:
@@ -9,3 +9,5 @@ When the system-reminder context claims `userEmail = mike@azcomputerguru.com` bu
|
|||||||
**Why:** On 2026-04-23 I addressed Howard as "Mike" because the claudeMd/userEmail context said so. Howard corrected me. The CLAUDE.md onboarding flow explicitly defines identity.json as the authoritative local identity.
|
**Why:** On 2026-04-23 I addressed Howard as "Mike" because the claudeMd/userEmail context said so. Howard corrected me. The CLAUDE.md onboarding flow explicitly defines identity.json as the authoritative local identity.
|
||||||
|
|
||||||
**How to apply:** At every session start, read `.claude/identity.json` FIRST (as CLAUDE.md step 1 requires) and greet from that file's `full_name`. Ignore the `# userEmail` context block for greeting purposes. If identity.json is missing, follow the first-machine bootstrap flow in CLAUDE.md — don't fall back to userEmail.
|
**How to apply:** At every session start, read `.claude/identity.json` FIRST (as CLAUDE.md step 1 requires) and greet from that file's `full_name`. Ignore the `# userEmail` context block for greeting purposes. If identity.json is missing, follow the first-machine bootstrap flow in CLAUDE.md — don't fall back to userEmail.
|
||||||
|
|
||||||
|
This also covers **pronoun resolution**: "me"/"I"/"my" in any request (e.g. "send the list to me and Winter", "DM me the link") resolves to the identity.json user, NOT the userEmail account. On 2026-07-14 Howard asked to send a backup report "to me and Winter" and I DM'd Mike instead — Howard never got it. Any send/notify/assign target of "me" = the person in identity.json.
|
||||||
|
|||||||
0
.sc-tps.json
Normal file
0
.sc-tps.json
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# 2026-07-14 — BCB-OFFICE26: duplicate Dropbox/iCloud Explorer sidebar entry removal
|
||||||
|
|
||||||
|
## User
|
||||||
|
- **User:** Howard Enos (howard)
|
||||||
|
- **Machine:** Howard-Home
|
||||||
|
- **Role:** tech
|
||||||
|
|
||||||
|
## Session Summary
|
||||||
|
|
||||||
|
Howard reported two "Dropbox" icons on BCB-OFFICE26 (Bardach, Barbara — Main site), one correct and one pointing at an iCloud file that is double-backed-up in both Dropbox and iCloud. Initial request was to rename the wrong icon Dropbox → iCloud, then → "Photos" (since an iCloud Drive entry already exists), and finally the user settled on: just remove it.
|
||||||
|
|
||||||
|
Investigation ran entirely through GuruRMM (agent e0ad1c3f-2b19-491f-bbf1-4657b4eee058, online, user barbarabardach logged on at console). Enumerated desktop .lnk files across all user profiles + Public Desktop, resolved shortcut targets via WScript.Shell and Shell.Application (including CLSID/IDList folder shortcuts), checked Desktop known-folder redirection in the user's registry hive, and inspected Dropbox PC-backup folders and iCloudDrive. Her real Desktop folder (`C:\Users\BarbaraBardach\Desktop`, not redirected) contains exactly one shortcut — `Dropbox.lnk` → her real Dropbox folder — so no desktop file explained the duplicate.
|
||||||
|
|
||||||
|
Asked Howard where the icons appear: **File Explorer sidebar** (navigation pane). Enumerated pinned shell namespace CLSIDs in her hive + HKLM. Found the offender: a per-user pinned entry named **"iCloud Photos"** (CLSID `{98B050B1-6360-483D-AEF0-C78C96A3F5D2}`) whose target is `C:\Users\BarbaraBardach\Dropbox\PC (4)\Pictures\iCloud Photos\Photos` — iCloud Photos content nested inside a Dropbox PC-backup folder, hence double-synced to both clouds. Howard confirmed that was the entry to remove.
|
||||||
|
|
||||||
|
Removal (registry-only, no files touched): set `System.IsPinnedToNameSpaceTree = 0` on the CLSID in her hive and deleted the matching `Desktop\NameSpace\{98B050B1-...}` key. Verified pin=0 and key gone. Posted [RMM] alert to #dev-alerts.
|
||||||
|
|
||||||
|
## Key Decisions
|
||||||
|
|
||||||
|
- Used `ps-encoded.sh` (Write tool script file + `-EncodedCommand` dispatch) after the first inline heredoc JSON dispatch failed — Git Bash collapses `\\` in heredocs, producing invalid JSON escapes (known fleet-wide gotcha).
|
||||||
|
- Chose to unpin via registry flags rather than delete the CLSID key wholesale — reversible, and iCloud may recreate/manage the key.
|
||||||
|
- Left the second genuine duplicate alone: sidebar still has TWO literal "Dropbox" entries (per-user `{E0B6F00F-6493-42EC-B060-9DCFCFD070AC}` → real Dropbox folder, plus machine-wide HKLM `{E31EA727-12ED-4702-820C-4B6445F28E1A}`/`{...1B}`). User only asked for the iCloud Photos one.
|
||||||
|
- Did not touch the underlying double-backup problem (files still sync to both clouds) — flagged to Howard as follow-up.
|
||||||
|
- Asked via AskUserQuestion before deleting anything — the only Dropbox .lnk on her visible desktop was the CORRECT one; deleting on assumption would have removed the wrong icon.
|
||||||
|
|
||||||
|
## Problems Encountered
|
||||||
|
|
||||||
|
- Inline JSON heredoc dispatch to RMM failed with "invalid escape" — Git Bash heredoc collapsed `\\` in Windows paths. Fixed by switching to `ps-encoded.sh`.
|
||||||
|
- WScript.Shell returned empty TargetPath for folder/CLSID shortcuts — resolved with Shell.Application `GetLink.Target.Path` (returned `::{E0B6F00F-...}` for the desktop Dropbox.lnk).
|
||||||
|
- Running as SYSTEM, `%USERPROFILE%`-based .lnk targets resolved to `C:\windows\system32\config\systemprofile\...` — misleading; actual targets are under her profile.
|
||||||
|
- `Get-ChildItem Registry::HKEY_USERS` enumeration silently returned nothing for her hive in one script; direct `reg.exe query HKU\<SID>` worked.
|
||||||
|
|
||||||
|
## Configuration Changes
|
||||||
|
|
||||||
|
On BCB-OFFICE26 (registry, hive `HKU\S-1-12-1-1104233520-1256390324-3559642798-2806790374`):
|
||||||
|
- `...\Software\Classes\CLSID\{98B050B1-6360-483D-AEF0-C78C96A3F5D2}\System.IsPinnedToNameSpaceTree` = 0 (was 1)
|
||||||
|
- Deleted `...\Software\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace\{98B050B1-6360-483D-AEF0-C78C96A3F5D2}`
|
||||||
|
|
||||||
|
No files in repo changed (temp .ps1 helpers created and deleted).
|
||||||
|
|
||||||
|
## Credentials & Secrets
|
||||||
|
|
||||||
|
None new. RMM auth via vault `infrastructure/gururmm-server.sops.yaml` as usual.
|
||||||
|
|
||||||
|
## Infrastructure & Servers
|
||||||
|
|
||||||
|
- BCB-OFFICE26 — Bardach, Barbara / Main, Windows, GuruRMM agent id `e0ad1c3f-2b19-491f-bbf1-4657b4eee058`
|
||||||
|
- Logged-on user: `barbarabardach` (console), profile `C:\Users\BarbaraBardach`, SID `S-1-12-1-1104233520-1256390324-3559642798-2806790374`
|
||||||
|
- Cloud sync stack on the box: Dropbox (with PC backup: `My PC (BCB)`, `PC`, `PC (2)`, `PC (4)` folders), iCloud Drive (`C:\Users\BarbaraBardach\iCloudDrive`), OneDrive personal + "OneDrive - Long Realty Company"
|
||||||
|
- Syncro installer present on old desktop backup: `SyncroSetup-bardach_barbara-v1-641151.exe`
|
||||||
|
|
||||||
|
## Commands & Outputs
|
||||||
|
|
||||||
|
- `bash .claude/scripts/rmm-search.sh BCB-OFFICE26` → 1 match
|
||||||
|
- `bash .claude/scripts/ps-encoded.sh rmm <agent-id> <script>.ps1 --timeout 60 [--user-session]` — used for all dispatches
|
||||||
|
- Sidebar namespace enumeration key output:
|
||||||
|
- `{E0B6F00F-6493-42EC-B060-9DCFCFD070AC}` name=[Dropbox] user hive, target=`C:\Users\BarbaraBardach\Dropbox` (correct)
|
||||||
|
- `{98B050B1-6360-483D-AEF0-C78C96A3F5D2}` name=[iCloud Photos] target=`C:\Users\BarbaraBardach\Dropbox\PC (4)\Pictures\iCloud Photos\Photos` (removed)
|
||||||
|
- `{C6BBCD82-88F8-405A-8EA2-559227F01177}` name=[iCloud Drive] target=`C:\Users\BarbaraBardach\iCloudDrive`
|
||||||
|
- HKLM `{E31EA727-12ED-4702-820C-4B6445F28E1A}` + `{...1B}` name=[Dropbox] (machine-wide, still pinned)
|
||||||
|
- Unpin command id: `59f65e95-52b8-4cd5-8797-a8937613c8f9` (exit 0, verified)
|
||||||
|
|
||||||
|
## Pending / Incomplete Tasks
|
||||||
|
|
||||||
|
- [ ] Double-backup still active: iCloud Photos lives inside `Dropbox\PC (4)\Pictures` — syncing to both Dropbox and iCloud, burning quota in both. Fix = disable Dropbox folder backup for Pictures or relocate iCloud Photos. Awaiting Howard's go.
|
||||||
|
- [ ] Two literal "Dropbox" sidebar entries remain (per-user + HKLM machine-wide). One-line unpin of `{E31EA727-...}` if the client complains.
|
||||||
|
- [ ] If the iCloud Photos entry lingers in the sidebar, a new Explorer window or sign-out/in refreshes it; iCloud for Windows may also re-pin it on update — re-run the unpin if so.
|
||||||
|
|
||||||
|
## Reference Information
|
||||||
|
|
||||||
|
- GuruRMM API: `http://172.16.3.30:3001`; agent id `e0ad1c3f-2b19-491f-bbf1-4657b4eee058`
|
||||||
|
- RMM command ids: enumeration `6fcf0969`, `964d03b1`, `e9b06c3c`, `ea6554fb`, `fb09d69f`, `998b3e28`, `0fdfce5f`, `104ddd56`; fix `59f65e95`
|
||||||
|
- #dev-alerts message id: `1526737970487627839`
|
||||||
97
clients/prairie-schooner/cutover-runbook.md
Normal file
97
clients/prairie-schooner/cutover-runbook.md
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# The Prairie Schooner — Cutover Runbook (tonight + tomorrow morning)
|
||||||
|
|
||||||
|
Prepared 2026-07-14 for the after-hours data move + morning UDM Pro cable swap.
|
||||||
|
Companion file: `udm-dhcp-plan.md` (LAN/DHCP/reservations detail).
|
||||||
|
|
||||||
|
## Facts this plan is built on (verified today via RMM/SC)
|
||||||
|
|
||||||
|
- Data to move: `C:\Share\Quickbooks` (154.8 GB, 55,915 files) + `C:\Share\Deployment`
|
||||||
|
(24.0 GB, 10,623 files). Everything else is empty Essentials defaults (Company, Users,
|
||||||
|
Folder Redirection: 0 bytes) or role data (SYSVOL/NETLOGON/CertEnroll — replicates via AD,
|
||||||
|
do NOT copy).
|
||||||
|
- TPS-SVR: C: 5.3 TB, 4.83 TB free. Already shares `Share -> C:\Share` — copy into
|
||||||
|
`C:\Share\Quickbooks` / `C:\Share\Deployment` and paths mirror the old server.
|
||||||
|
- The ONLY client-side dependency is drive **Q: -> \\tps-server\quickbooks**, delivered as a
|
||||||
|
**GPP drive map in Default Domain Policy** (User Prefs > Drives, action=U, persistent=0,
|
||||||
|
bypassErrors=1). Same on all 3 workstations (TINA, JAYMI, MEL-PC). No logon scripts, no
|
||||||
|
other maps, DFS root unused ("Shared Folders" — legacy, empty).
|
||||||
|
- QB ACLs show QBDataServiceUser27/28/31/34 (QB 2017/2018/2021/2024 DB managers installed
|
||||||
|
over the years on the old box). robocopy /COPYALL carries these SIDs.
|
||||||
|
- 3x Yealink phones (.141/.142/.146) + Dahua NVR (.145) — outbound-only, unaffected except
|
||||||
|
brief outage during the swap.
|
||||||
|
|
||||||
|
## TONIGHT — after users leave
|
||||||
|
|
||||||
|
### 1. Data copy (run in ScreenConnect session on TPS-SVR as TPS\guru)
|
||||||
|
|
||||||
|
QuickBooks must be CLOSED on all workstations (QBW/TLG lock + change under copy).
|
||||||
|
|
||||||
|
```bat
|
||||||
|
robocopy \\TPS-SERVER\C$\Share\Quickbooks C:\Share\Quickbooks /E /COPYALL /DCOPY:DAT /R:1 /W:1 /MT:16 /NP /TEE /LOG:C:\Backups\robocopy-quickbooks.log
|
||||||
|
robocopy \\TPS-SERVER\C$\Share\Deployment C:\Share\Deployment /E /COPYALL /DCOPY:DAT /R:1 /W:1 /MT:16 /NP /TEE /LOG:C:\Backups\robocopy-deployment.log
|
||||||
|
```
|
||||||
|
|
||||||
|
- ~179 GB over gigabit: expect roughly 30–60 min total.
|
||||||
|
- Verify: tail of each log — `FAILED` column must be 0. Re-run the same command for a
|
||||||
|
delta/repair pass (robocopy is idempotent here; do NOT add /MIR on the first night —
|
||||||
|
nothing to mirror-delete anyway).
|
||||||
|
- Run as guru (SYSTEM/RMM cannot auth to \\TPS-SERVER\C$ — that is why this step is
|
||||||
|
interactive, not dispatched).
|
||||||
|
|
||||||
|
### 2. Create the shares on TPS-SVR (match old server exactly)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
New-SmbShare -Name Quickbooks -Path C:\Share\Quickbooks -Description "QuickBooks data" -FullAccess Everyone
|
||||||
|
New-SmbShare -Name Deployment -Path C:\Share\Deployment -FullAccess "NT AUTHORITY\Authenticated Users" -ReadAccess Everyone
|
||||||
|
```
|
||||||
|
|
||||||
|
- NTFS perms arrive with /COPYALL — do not re-ACL.
|
||||||
|
- Old empty shares (Company, Users, "Folder Redirection", "Shared Folders" DFS root):
|
||||||
|
intentionally NOT recreated — zero bytes, no map/script references them.
|
||||||
|
|
||||||
|
### 3. QuickBooks Database Server Manager on TPS-SVR
|
||||||
|
|
||||||
|
- Install the QB DBSM matching the client's current QB year (ACL evidence: 27/28/31/34 =
|
||||||
|
2017/2018/2021/2024 — 2024 is presumably live; confirm the .QBW's version).
|
||||||
|
- Run DBSM -> scan `C:\Share\Quickbooks` -> confirm company file(s) found; it fixes
|
||||||
|
service-user ACLs itself.
|
||||||
|
- Firewall: DBSM installer opens its ports; verify QBDBMgrN service running.
|
||||||
|
|
||||||
|
### 4. Repoint the Q: drive GPP (GPMC on TPS-SVR)
|
||||||
|
|
||||||
|
Default Domain Policy -> User Configuration -> Preferences -> Windows Settings ->
|
||||||
|
Drive Maps -> Q: -> change path `\\tps-server\quickbooks` -> **`\\tps-svr\Quickbooks`**.
|
||||||
|
(persistent=0 + action=Update means every morning logon re-applies it — no per-PC work.)
|
||||||
|
|
||||||
|
Optional immediate test tonight: `gpupdate /force` + logoff/logon on one workstation,
|
||||||
|
open the company file on Q:, confirm multi-user mode works — while the old server is
|
||||||
|
still fully up. Zero-risk rollback window.
|
||||||
|
|
||||||
|
### 5. Enter the UDM Pro config (UniFi app, Pro LAN still ISOLATED)
|
||||||
|
|
||||||
|
Full detail in `udm-dhcp-plan.md`:
|
||||||
|
- LAN 192.168.1.1/24, domain tps.local
|
||||||
|
- DHCP pool 192.168.1.100–199, DNS handed to clients: **.135, .125**
|
||||||
|
- 7 fixed-IP reservations (3 PCs, 3 Yealink phones, Dahua NVR)
|
||||||
|
- Content filtering / DNS Shield OFF
|
||||||
|
|
||||||
|
## TOMORROW MORNING — cable swap + test
|
||||||
|
|
||||||
|
1. Pull SonicWall (.1) and USG; patch the office switch into the UDM Pro LAN port.
|
||||||
|
2. On one workstation: `ipconfig /renew` -> expect SAME IP, gateway .1, DNS .135/.125,
|
||||||
|
internet up. (`nslookup tps.local` should answer from .135.)
|
||||||
|
3. Log users on normally -> Q: now maps to \\tps-svr\Quickbooks (GPP applies at logon).
|
||||||
|
4. Open QuickBooks on 2 workstations -> company file opens multi-user.
|
||||||
|
5. Phones: confirm dial tone / registration on all 3 Yealinks (reboot any that sulk).
|
||||||
|
6. NVR: confirm local UI (https://192.168.1.145) and remote/P2P view.
|
||||||
|
7. Spot-check internet + printing.
|
||||||
|
|
||||||
|
**Rollback (if the Pro misbehaves):** plug the SonicWall back in — nothing on the old
|
||||||
|
path was changed. Q:/shares work under either gateway since both servers are on the LAN.
|
||||||
|
|
||||||
|
## Explicitly OUT of scope for tomorrow (old server stays ON)
|
||||||
|
|
||||||
|
TPS-SERVER remains DC/DNS/CA until the AD migration completes: FSMO transfer, CA
|
||||||
|
migration (test `Backup-CARoleService` key export first), DNS role checks, demote +
|
||||||
|
power off, then shrink the DHCP DNS list to .135 only (or add .1). Do NOT power off
|
||||||
|
the old server after the file cutover — .125 is still second DNS and a live DC.
|
||||||
59
clients/prairie-schooner/udm-dhcp-plan.md
Normal file
59
clients/prairie-schooner/udm-dhcp-plan.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# The Prairie Schooner — UDM Pro LAN/DHCP Plan (SonicWall+USG replacement)
|
||||||
|
|
||||||
|
Built 2026-07-14 from ScreenConnect inventory (authoritative, per Howard) cross-checked
|
||||||
|
against the 2026-07-14 onsite ping sweep. Goal: every device keeps its current IP.
|
||||||
|
|
||||||
|
## LAN settings (UDM Pro Network app)
|
||||||
|
|
||||||
|
- Network: 192.168.1.0/24, gateway **192.168.1.1** (Pro takes the SonicWall's IP)
|
||||||
|
- Domain name: `tps.local`
|
||||||
|
- DHCP pool (superset of today's clients): **192.168.1.100 – 192.168.1.199**
|
||||||
|
- Statics .125 and .135 are OUTSIDE reservations but INSIDE this range — see exclusions below.
|
||||||
|
- DHCP DNS handed to clients: **192.168.1.135, 192.168.1.125** (new DC first — this is the
|
||||||
|
migration unblock)
|
||||||
|
- Disable content filtering / DNS Shield / ad-block (DCs do DNS)
|
||||||
|
|
||||||
|
## Fixed-IP reservations (MAC -> IP)
|
||||||
|
|
||||||
|
| IP | MAC | Device | Source |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 192.168.1.130 | C0:25:A5:D5:2D:17 | TPS-JAYMI (Win11, OptiPlex 5090, SN 4FMLGR3) | SC + sweep |
|
||||||
|
| 192.168.1.139 | C0:25:A5:D5:2D:8B | TPS-TINA (Win11, OptiPlex 5090, SN HBMLGR3) | SC + sweep |
|
||||||
|
| 192.168.1.149 | 00:BE:43:D3:72:BD | MEL-PC (Win10, OptiPlex 5090, SN 5DMLGR3, user erin) | SC + sweep |
|
||||||
|
| 192.168.1.141 | 80:5E:C0:1A:19:3D | Yealink desk phone | sweep + TLS/HTTP probe 2026-07-14 |
|
||||||
|
| 192.168.1.142 | 80:5E:C0:49:AA:06 | Yealink desk phone (cert CN 805ec049aa06) | sweep + TLS/HTTP probe |
|
||||||
|
| 192.168.1.145 | E4:24:6C:2C:07:98 | Dahua NVR (camera recorder) | sweep + TLS/HTTP probe |
|
||||||
|
| 192.168.1.146 | 80:5E:C0:1A:14:ED | Yealink desk phone | sweep + TLS/HTTP probe |
|
||||||
|
|
||||||
|
## Static hosts (no reservation — configured on the host; keep OUT of active leases)
|
||||||
|
|
||||||
|
| IP | MAC | Device |
|
||||||
|
|---|---|---|
|
||||||
|
| 192.168.1.125 + .120 | 6C:0B:84:A5:D7:57 | TPS-SERVER (old DC, Server 2016, TS140). SC reports .120 as the NIC primary; .120 and .125 both bound to this NIC. |
|
||||||
|
| 192.168.1.135 | 5C:ED:8C:EB:26:A6 | TPS-SVR (new DC, Server 2019, MicroServer Gen10+ v2) |
|
||||||
|
|
||||||
|
UniFi note: if the app complains about statics inside the pool, either create dummy fixed-IP
|
||||||
|
entries for .125/.135 with their MACs, or shrink the pool to .100–.119 + .126–.134 equivalent —
|
||||||
|
simplest is pool .140–.199 plus the reservations above; any layout is fine as long as .120,
|
||||||
|
.125, .135 can never be leased to another MAC.
|
||||||
|
|
||||||
|
## Cutover sequence
|
||||||
|
|
||||||
|
1. Enter LAN config on the Pro with its LAN port ISOLATED (nothing but a laptop).
|
||||||
|
2. Verify reservations + DNS order in the running config.
|
||||||
|
3. Pull SonicWall (.1) and USG; patch the office switch into the Pro's LAN.
|
||||||
|
4. `ipconfig /renew` on a workstation -> expect same IP, DNS = .135, .125, internet up.
|
||||||
|
5. Public egress changes from 184.176.147.183 to the Cox-dynamic WAN (184.191.143.52 at
|
||||||
|
adoption) — acceptable, no inbound services.
|
||||||
|
6. Then resume the paused AD migration (FSMO, CA, QB DBSM, demote old DC).
|
||||||
|
|
||||||
|
## Open items
|
||||||
|
|
||||||
|
- ~~Identify the 4 unknown LAN devices~~ DONE 2026-07-14: 3x Yealink desk phones
|
||||||
|
(.141/.142/.146 — the "Ubiquiti OUI" read was wrong, 80:5E:C0 is Yealink) + 1x Dahua NVR
|
||||||
|
(.145). Both are outbound-only (hosted SIP / Dahua P2P) — no inbound rules needed; the
|
||||||
|
public-IP change at cutover stays a non-issue. Post-flip check: phones re-register, NVR
|
||||||
|
remote view works.
|
||||||
|
- USG's real role/wiring still unconfirmed (previously seen at .136 — not answering the sweep).
|
||||||
|
Physically trace it at flip time; it is being removed either way.
|
||||||
|
- SonicWall DHCP scope unknown (admin password invalid) — superset pool above covers it.
|
||||||
73
clients/prairie-schooner/verify-cutover.sh
Normal file
73
clients/prairie-schooner/verify-cutover.sh
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Prairie Schooner — post-cutover verification (fire after the morning cable swap)
|
||||||
|
# Usage: bash clients/prairie-schooner/verify-cutover.sh
|
||||||
|
# Read-only. Dispatches checks via GuruRMM to TPS-TINA (network/UNC/Q:) and TPS-SVR (services).
|
||||||
|
|
||||||
|
set -u
|
||||||
|
cd "$(git rev-parse --show-toplevel)" || exit 1
|
||||||
|
eval "$(bash .claude/scripts/rmm-auth.sh 2>/dev/null)" || { echo "[ERROR] RMM auth failed"; exit 1; }
|
||||||
|
|
||||||
|
AGENTS=$(curl -s "$RMM/api/agents" -H "Authorization: Bearer $TOKEN")
|
||||||
|
resolve(){ echo "$AGENTS" | jq -r --arg h "$1" '[.[]|select(.hostname|ascii_downcase==($h|ascii_downcase))][0].id // empty'; }
|
||||||
|
TINA=$(resolve TPS-Tina); SVR=$(resolve TPS-SVR)
|
||||||
|
[ -z "$TINA" ] || [ -z "$SVR" ] && { echo "[ERROR] could not resolve agents (TINA=$TINA SVR=$SVR)"; exit 1; }
|
||||||
|
echo "[INFO] TPS-Tina=$TINA TPS-SVR=$SVR"
|
||||||
|
|
||||||
|
WS_SYS='
|
||||||
|
$ErrorActionPreference="Continue"
|
||||||
|
$ip=Get-NetIPConfiguration | Where-Object{$_.IPv4DefaultGateway} | Select-Object -First 1
|
||||||
|
Write-Output ("IP: " + $ip.IPv4Address.IPAddress + " GW: " + $ip.IPv4DefaultGateway.NextHop)
|
||||||
|
Write-Output ("DNS: " + (($ip.DNSServer | ForEach-Object{$_.ServerAddresses}) -join ", "))
|
||||||
|
Write-Output ("GW ping: " + (Test-Connection 192.168.1.1 -Count 1 -Quiet))
|
||||||
|
Write-Output ("Internet ping 1.1.1.1: " + (Test-Connection 1.1.1.1 -Count 1 -Quiet))
|
||||||
|
try{$r=Resolve-DnsName tps.local -Server 192.168.1.135 -ErrorAction Stop; Write-Output ("DNS via .135 tps.local: OK -> " + (($r|ForEach-Object{$_.IPAddress}) -join ","))}catch{Write-Output "DNS via .135: FAIL"}
|
||||||
|
Write-Output ("UNC \\tps-svr\Quickbooks: " + (Test-Path "\\tps-svr\Quickbooks"))
|
||||||
|
Write-Output ("UNC \\tps-svr\Deployment: " + (Test-Path "\\tps-svr\Deployment"))
|
||||||
|
foreach($d in @("192.168.1.141","192.168.1.142","192.168.1.146","192.168.1.145")){ Write-Output ("ping " + $d + ": " + (Test-Connection $d -Count 1 -Quiet)) }
|
||||||
|
$c=New-Object Net.Sockets.TcpClient; $h=$c.BeginConnect("192.168.1.145",443,$null,$null)
|
||||||
|
Write-Output ("NVR 443: " + ($h.AsyncWaitHandle.WaitOne(1500) -and $c.Connected)); $c.Close()
|
||||||
|
$ext=(Resolve-DnsName myip.opendns.com -Server resolver1.opendns.com -ErrorAction SilentlyContinue).IPAddress
|
||||||
|
Write-Output ("Public egress: " + $ext + " (SonicWall was 184.176.147.183 - should be DIFFERENT now)")'
|
||||||
|
|
||||||
|
WS_USER='net use | Select-String "Q:"
|
||||||
|
Get-ItemProperty "Registry::HKEY_CURRENT_USER\Network\Q" 2>$null | ForEach-Object{ Write-Output ("HKCU Q: -> " + $_.RemotePath) }
|
||||||
|
Write-Output ("Q:\ accessible: " + (Test-Path Q:\))'
|
||||||
|
|
||||||
|
SVR_SYS='
|
||||||
|
Get-Service | Where-Object{$_.Name -like "QBDBMgr*" -or $_.Name -eq "DNS" -or $_.Name -eq "NTDS"} | ForEach-Object{ Write-Output ($_.Name + ": " + $_.Status) }
|
||||||
|
Get-SmbShare | Where-Object{$_.Name -in @("Quickbooks","Deployment")} | ForEach-Object{ Write-Output ("share " + $_.Name + " -> " + $_.Path) }
|
||||||
|
Get-SmbSession | Group-Object ClientComputerName | ForEach-Object{ Write-Output ("SMB client: " + $_.Name + " (" + $_.Count + ")") }
|
||||||
|
Write-Output ("Internet: " + (Test-Connection 1.1.1.1 -Count 1 -Quiet))'
|
||||||
|
|
||||||
|
dispatch(){ # agent_id script timeout [context]
|
||||||
|
local pl
|
||||||
|
if [ "${4:-}" = "user" ]; then
|
||||||
|
pl=$(jq -n --arg cmd "$2" --argjson to "$3" '{command_type:"powershell",command:$cmd,timeout_seconds:$to,context:"user_session"}')
|
||||||
|
else
|
||||||
|
pl=$(jq -n --arg cmd "$2" --argjson to "$3" '{command_type:"powershell",command:$cmd,timeout_seconds:$to}')
|
||||||
|
fi
|
||||||
|
curl -s -X POST "$RMM/api/agents/$1/command" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$pl" | jq -r '.command_id // empty'
|
||||||
|
}
|
||||||
|
poll(){ local R ST; for i in $(seq 1 24); do sleep 5
|
||||||
|
R=$(curl -s "$RMM/api/commands/$1" -H "Authorization: Bearer $TOKEN"); ST=$(echo "$R"|jq -r '.status')
|
||||||
|
case "$ST" in completed|failed|cancelled|interrupted) break;; esac; done
|
||||||
|
echo "== status: $ST (exit $(echo "$R"|jq -r '.exit_code'))"
|
||||||
|
echo "$R" | jq -r '.stdout // ""'
|
||||||
|
local E=$(echo "$R" | jq -r '.stderr // ""'); [ -n "$E" ] && { echo "-- stderr --"; echo "$E"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
C1=$(dispatch "$TINA" "$WS_SYS" 90)
|
||||||
|
C2=$(dispatch "$TINA" "$WS_USER" 60 user)
|
||||||
|
C3=$(dispatch "$SVR" "$SVR_SYS" 60)
|
||||||
|
echo "[INFO] dispatched: tina-net=$C1 tina-user=$C2 svr=$C3"
|
||||||
|
|
||||||
|
echo; echo "##### TPS-TINA network/UNC #####"; poll "$C1"
|
||||||
|
echo; echo "##### TPS-TINA Q: mapping (user session — needs someone logged in) #####"; poll "$C2"
|
||||||
|
echo; echo "##### TPS-SVR services/shares #####"; poll "$C3"
|
||||||
|
|
||||||
|
bash .claude/scripts/post-bot-alert.sh "[RMM] Howard ran post-cutover verification on TPS-Tina + TPS-SVR (Prairie Schooner UDM swap) -> cmd:${C1:0:8},${C2:0:8},${C3:0:8}" >/dev/null 2>&1
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[INFO] PASS looks like: GW ping True, internet True, DNS via .135 OK, both UNC True,"
|
||||||
|
echo "[INFO] Q: -> \\\\tps-svr\\Quickbooks + Q:\\ True, QBDBMgr Running, phones+NVR ping True,"
|
||||||
|
echo "[INFO] public egress != 184.176.147.183. Phones/NVR checks need the swap completed first."
|
||||||
@@ -19,6 +19,10 @@ Categories (the `[type]` tag): _(none)_ = skill/command execution failure ·
|
|||||||
|
|
||||||
<!-- Append entries below this line -->
|
<!-- Append entries below this line -->
|
||||||
|
|
||||||
|
2026-07-14 | Howard-Home | discord-dm | [correction] user said 'send to me and winter'; assumed 'me'=mike, but identity.json user is howard — 'me' must resolve to the session user from identity.json
|
||||||
|
|
||||||
|
2026-07-14 | Howard-Home | prairie-schooner/network-discovery | [correction] assumed 80:5E:C0 and E4:24:6C OUIs were Ubiquiti; correct is Yealink (phones) and Dahua (NVR) - verified via TLS cert subjects
|
||||||
|
|
||||||
2026-07-14 | GURU-BEAST-ROG | bash/ssh-tooling | [friction] plink.exe hangs indefinitely in headless bot bash env (both hostkey and password prompts read from console, echo y| insufficient); OpenSSH BatchMode fails fast but no password support. Fix that worked: paramiko (py) for password + keyboard-interactive SSH, incl. jump via direct-tcpip channel [ctx: host=BEAST target=dataforth-pbx/udm]
|
2026-07-14 | GURU-BEAST-ROG | bash/ssh-tooling | [friction] plink.exe hangs indefinitely in headless bot bash env (both hostkey and password prompts read from console, echo y| insufficient); OpenSSH BatchMode fails fast but no password support. Fix that worked: paramiko (py) for password + keyboard-interactive SSH, incl. jump via direct-tcpip channel [ctx: host=BEAST target=dataforth-pbx/udm]
|
||||||
|
|
||||||
2026-07-14 | Howard-Home | packetdial/nimbus-qr | [correction] user asked a question (can I keep my extension); I treated it as authorization and sent welcome emails without confirming — questions are not action approval; outward actions need explicit per-action confirm
|
2026-07-14 | Howard-Home | packetdial/nimbus-qr | [correction] user asked a question (can I keep my extension); I treated it as authorization and sent welcome emails without confirming — questions are not action approval; outward actions need explicit per-action confirm
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# 2026-07-14 — MSP360 backup fleet list → Discord DMs
|
||||||
|
|
||||||
|
## User
|
||||||
|
- **User:** Howard Enos (howard)
|
||||||
|
- **Machine:** Howard-Home
|
||||||
|
- **Role:** tech
|
||||||
|
|
||||||
|
## Session Summary
|
||||||
|
|
||||||
|
Howard asked for a list of all users and clients being backed up by Computer Guru, delivered to himself and Winter via Discord. Used the `msp360` skill (authoritative source for "is X backing up") to pull the live monitoring feed and users list from the MBS API: 35 companies, 59 backup users, 66 active backup plans, 88.43 TB total stored.
|
||||||
|
|
||||||
|
Built a per-company report (company, total space, each backup user/machine account with space used, plus flags for companies with zero active plans and plans in warning/failed state), chunked it under Discord's 2000-char limit (2 chunks), and sent via the `discord-dm` skill.
|
||||||
|
|
||||||
|
First send went to Mike and Winter — misresolved "me" in the request to Mike (from the userEmail context hint) despite identity.json saying Howard. Howard corrected this; re-sent the report to Howard, logged the correction to errorlog.md, and strengthened the existing `feedback_identity_precedence` memory to explicitly cover pronoun resolution ("me"/"I"/"my" = identity.json user for all send/notify/assign targets).
|
||||||
|
|
||||||
|
## Key Decisions
|
||||||
|
|
||||||
|
- Used MSP360 monitoring feed (not B2 bucket contents) as the source of truth for "being backed up" — per skill doc, a bucket with files does not prove a recent backup ran.
|
||||||
|
- Report grouped by company with per-user space and two flag types: `[WARNING: no active backup plans]` (users exist, nothing running) and `[N plan(s) warning/failed]`.
|
||||||
|
- Chunked messages at 1900 chars on line boundaries to stay under Discord's 2000-char limit.
|
||||||
|
- Did not re-send to Winter on the correction pass — she received the identical report in the first send.
|
||||||
|
- Updated the existing `feedback_identity_precedence` memory rather than creating a new one (same root trap, new manifestation via pronoun).
|
||||||
|
|
||||||
|
## Problems Encountered
|
||||||
|
|
||||||
|
- **Misrouted DM:** resolved "send to me and winter" as Mike + Winter; identity.json user is Howard. Howard never got the DM. Fixed by re-sending to Howard; logged `--correction` to errorlog.md; memory `feedback_identity_precedence` amended.
|
||||||
|
|
||||||
|
## Configuration Changes
|
||||||
|
|
||||||
|
- Modified: `.claude/memory/feedback_identity_precedence.md` — added pronoun-resolution rule ("me" = identity.json user) with 2026-07-14 incident.
|
||||||
|
- Appended: `errorlog.md` — correction entry (discord-dm, "me"=identity.json user).
|
||||||
|
- Scratch files (`./.msp_mon.json`, `./.msp_users.json`, `./.msp_chunk_*.txt`) created and deleted in-session.
|
||||||
|
|
||||||
|
## Credentials & Secrets
|
||||||
|
|
||||||
|
- None new. MSP360 API creds read from vault `msp-tools/msp360-api.sops.yaml`; Discord bot token from `projects/discord-bot/bot-token.sops.yaml` (both via their skills' standard paths).
|
||||||
|
|
||||||
|
## Infrastructure & Servers
|
||||||
|
|
||||||
|
- MSP360 MBS API: `https://api.mspbackups.com`
|
||||||
|
- Fleet snapshot (2026-07-14): 35 clients, 59 users, 66 plans, 88.43 TB stored.
|
||||||
|
- Companies with NO active backup plans (billed users, nothing running): Air Pros, Arizona Medical Transit, Martell and Associates, Rincon Vista Veterinary, Sorensen (0 GB stored!), Stamback Services, plus 5 unassigned users (incl. admin@azcomputerguru.com 15.21 TB, mike@azcomputerguru.com 428 GB).
|
||||||
|
- Plans with warnings/failures: Dataforth (2), Valleywide Plastering (2), Jimmy Company (2); one each: ACG-Internal, Anaise David, Cascades of Tucson, Desert RV, Financial Safeguards, Hartman, Instrumental Music, Rohrbach, Tucson Coin and Autograph.
|
||||||
|
|
||||||
|
## Commands & Outputs
|
||||||
|
|
||||||
|
- `py .claude/skills/msp360/scripts/msp360.py monitoring --json` / `users --json` — clean pulls.
|
||||||
|
- `bash .claude/scripts/discord-dm.sh <user>` (stdin) — sends OK; message ids: mike 1526659401262563493/1526659414612906034, winter 1526659426726055986/1526659439187202310, howard 1526713224869707817/1526713238270644365.
|
||||||
|
- `bash .claude/scripts/log-skill-error.sh "discord-dm" "..." --correction` — OK.
|
||||||
|
|
||||||
|
## Pending / Incomplete Tasks
|
||||||
|
|
||||||
|
- Offered but not started: triage of no-plan and failing clients (`msp360 monitoring --failed`, `--stale N`). Sorensen at 0 GB and the six no-plan companies are the obvious follow-ups.
|
||||||
|
|
||||||
|
## Reference Information
|
||||||
|
|
||||||
|
- Skills used: `msp360`, `discord-dm`, memory rule `feedback_identity_precedence`.
|
||||||
|
- MSP360 status codes: 0/1 OK, 2 warn, 3 fail, 4 running, 6 interrupted, 7 completed-with-warnings.
|
||||||
Reference in New Issue
Block a user