sync: auto-sync from HOWARD-HOME at 2026-07-14 19:13:30

Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-07-14 19:13:30
This commit is contained in:
2026-07-14 19:14:01 -07:00
parent ec2fe6060b
commit 941de499c2
9 changed files with 835 additions and 731 deletions

View File

@@ -35,7 +35,7 @@ py "$MSP" create-company --name "New Client LLC" --confirm
py "$MSP" create-user --email backup@client.com --company "New Client LLC" \
--first Jane --last Doe --notify admin@acg.com --confirm
py "$MSP" grant-license --user-id <UUID> --license-id <UUID> --confirm
py "$MSP" release-license --user-id <UUID> --confirm
py "$MSP" release-license --user-id <UUID> --license-id <UUID> --confirm
py "$MSP" delete-user --id <UUID> [--keep-data] --confirm
py "$MSP" delete-company --id <UUID> --confirm
py "$MSP" raw POST /api/Accounts/CreateDestination --data '{...}' --confirm
@@ -91,6 +91,11 @@ RequestCustomBuilds), **Administrators** (GET/POST/PUT/DELETE). Reference:
- **`/api/Computers` returns HTTP 400 "Remote Management API methods are not enabled"** —
that feature is off on this account. `computers` prints a clean [INFO] and points you at
`users` + `monitoring`, which cover endpoint/backup data without it.
- **Licensing API is also feature-gated:** `POST /api/Licenses/Grant|Release|Revoke` returns
HTTP 400 "Licensing API methods are not enabled for your account" — license moves must be
done in the mspbackups.com console (Mike's admin account) until that's enabled.
- **Release/Revoke require `--license-id`:** the API rejects a Release/Revoke payload without
`LicenseID` (HTTP 400 ModelState). The CLI now enforces it; get the ID from `licenses --json`.
- **Git-Bash path mangling:** a leading-slash `raw` path like `/api/Users` gets rewritten to
`C:/Program Files/Git/api/Users` by MSYS. The `raw` command auto-recovers the `/api/...`
tail, so pass the path normally.

View File

@@ -392,12 +392,14 @@ def build_parser() -> argparse.ArgumentParser:
sp.add_argument("--confirm", action="store_true")
sp.set_defaults(func=cmd_delete_user)
for name, fn, verb in (("grant-license", cmd_grant_license, "grant"),
("release-license", cmd_release_license, "release"),
("revoke-license", cmd_revoke_license, "revoke")):
# API requires LicenseID for Release/Revoke (HTTP 400 without it); Grant can
# auto-pick a license, so it stays optional there.
for name, fn, verb, lic_required in (("grant-license", cmd_grant_license, "grant", False),
("release-license", cmd_release_license, "release", True),
("revoke-license", cmd_revoke_license, "revoke", True)):
sp = sub.add_parser(name, help=f"{verb} a license [--confirm]")
sp.add_argument("--user-id", required=True)
sp.add_argument("--license-id")
sp.add_argument("--license-id", required=lic_required)
sp.add_argument("--confirm", action="store_true")
sp.set_defaults(func=fn)

128
.lic.json
View File

@@ -142,6 +142,45 @@
"User": null,
"UserID": null
},
{
"ID": "7d26ae45-8af9-4fd0-8bed-011d18e82631",
"Number": 28,
"ComputerName": null,
"OperatingSystem": null,
"IsTrial": false,
"IsTaken": false,
"LicenseType": "Server",
"DateExpired": "2026-07-01T00:00:00Z",
"Transaction": "dbc23ae9-2010-4e27-863c-37290bcb0db1",
"User": null,
"UserID": null
},
{
"ID": "0a120352-aa4a-4785-bfdb-4e0c2980dd3c",
"Number": 18,
"ComputerName": null,
"OperatingSystem": null,
"IsTrial": false,
"IsTaken": false,
"LicenseType": "Server",
"DateExpired": "2026-07-01T00:00:00Z",
"Transaction": "dbc23ae9-2010-4e27-863c-37290bcb0db1",
"User": null,
"UserID": null
},
{
"ID": "93b3412b-9746-4949-a592-5369cd29d1c7",
"Number": 6,
"ComputerName": null,
"OperatingSystem": null,
"IsTrial": false,
"IsTaken": false,
"LicenseType": "Server",
"DateExpired": "2026-07-01T00:00:00Z",
"Transaction": "dbc23ae9-2010-4e27-863c-37290bcb0db1",
"User": null,
"UserID": null
},
{
"ID": "dfb1b1b9-bf99-49e9-ad28-6fca59bd86be",
"Number": 4,
@@ -259,32 +298,6 @@
"User": "jimmyco333@gmail.com",
"UserID": "d94b286b-d22e-49c3-8bb1-415848f448f4"
},
{
"ID": "0a120352-aa4a-4785-bfdb-4e0c2980dd3c",
"Number": 18,
"ComputerName": "VWP-FILES",
"OperatingSystem": "Microsoft Windows Server 2019 Standard ",
"IsTrial": false,
"IsTaken": true,
"LicenseType": "Server",
"DateExpired": "2026-07-01T00:00:00Z",
"Transaction": "dbc23ae9-2010-4e27-863c-37290bcb0db1",
"User": "VWP-FILES-BDC660BB0EB7",
"UserID": "634e86db-b3e5-4f4e-ae9b-74d83eeb21de"
},
{
"ID": "93b3412b-9746-4949-a592-5369cd29d1c7",
"Number": 6,
"ComputerName": "WINFileSvr",
"OperatingSystem": "Microsoft Windows Server 2019 Standard ",
"IsTrial": false,
"IsTaken": true,
"LicenseType": "Server",
"DateExpired": "2026-07-01T00:00:00Z",
"Transaction": "dbc23ae9-2010-4e27-863c-37290bcb0db1",
"User": "WINFileSvr-BDC660835B68",
"UserID": "30d7edce-1d60-4657-abc1-58ad30210e81"
},
{
"ID": "52e2b4a4-da50-4980-bfad-61f3b397e559",
"Number": 115,
@@ -299,17 +312,17 @@
"UserID": "06109a61-2ba2-4547-8294-f88d5e1799ba"
},
{
"ID": "7d26ae45-8af9-4fd0-8bed-011d18e82631",
"Number": 28,
"ComputerName": "CS-SERVER",
"OperatingSystem": "Microsoft Windows Server 2019 Standard ",
"ID": "b6c96a4c-cdfd-4035-a218-06d965315296",
"Number": 137,
"ComputerName": null,
"OperatingSystem": null,
"IsTrial": false,
"IsTaken": true,
"IsTaken": false,
"LicenseType": "Server",
"DateExpired": "2026-07-01T00:00:00Z",
"Transaction": "dbc23ae9-2010-4e27-863c-37290bcb0db1",
"User": "CS-SERVER-9163AEDE7357",
"UserID": "08d55d69-bf76-40b5-ae45-b1bbe0064c14"
"DateExpired": "2026-08-01T00:00:00Z",
"Transaction": "33df8a30-ef00-42c8-9c37-2b8b207c845f",
"User": null,
"UserID": null
},
{
"ID": "8d60d555-ad23-40e8-8962-29c7d0c143ce",
@@ -470,10 +483,10 @@
{
"ID": "7454b8e3-5aa7-43a1-b3c1-eb7605bad6c2",
"Number": 6,
"ComputerName": "SERVER",
"OperatingSystem": "Microsoft Windows NT 6.3.9600.0",
"ComputerName": null,
"OperatingSystem": null,
"IsTrial": false,
"IsTaken": true,
"IsTaken": false,
"LicenseType": "Server",
"DateExpired": "2026-08-01T00:00:00Z",
"Transaction": "9fff9d71-0db7-4b66-9c9c-b0fafff28cc9",
@@ -545,6 +558,32 @@
"User": "vwp",
"UserID": "38905235-0bb7-48a9-8728-de469d544fed"
},
{
"ID": "fcc6c069-b745-4234-b399-b492b6d61bce",
"Number": 137,
"ComputerName": "VWP-FILES",
"OperatingSystem": "Microsoft Windows Server 2019 Standard ",
"IsTrial": false,
"IsTaken": true,
"LicenseType": "Server",
"DateExpired": "2026-08-01T00:00:00Z",
"Transaction": "33df8a30-ef00-42c8-9c37-2b8b207c845f",
"User": "VWP-FILES-BDC660BB0EB7",
"UserID": "634e86db-b3e5-4f4e-ae9b-74d83eeb21de"
},
{
"ID": "5bf8d40c-430b-4108-b4a6-c4001e2dabdd",
"Number": 137,
"ComputerName": "WINFileSvr",
"OperatingSystem": "Microsoft Windows Server 2019 Standard ",
"IsTrial": false,
"IsTaken": true,
"LicenseType": "Server",
"DateExpired": "2026-08-01T00:00:00Z",
"Transaction": "33df8a30-ef00-42c8-9c37-2b8b207c845f",
"User": "WINFileSvr-BDC660835B68",
"UserID": "30d7edce-1d60-4657-abc1-58ad30210e81"
},
{
"ID": "7c1a1758-52a7-4c4e-8caa-426ebb776ab4",
"Number": 136,
@@ -662,6 +701,19 @@
"User": "lulu.camacho@khalsaschools.org",
"UserID": "3f80c65f-ea43-4e40-bd38-e4a5854d2e1d"
},
{
"ID": "db511bb2-0f59-41f4-bbff-da6db1c814c2",
"Number": 137,
"ComputerName": "CS-SERVER",
"OperatingSystem": "Microsoft Windows Server 2019 Standard ",
"IsTrial": false,
"IsTaken": true,
"LicenseType": "Server",
"DateExpired": "2026-08-01T00:00:00Z",
"Transaction": "33df8a30-ef00-42c8-9c37-2b8b207c845f",
"User": "CS-SERVER-9163AEDE7357",
"UserID": "08d55d69-bf76-40b5-ae45-b1bbe0064c14"
},
{
"ID": "53f1df9f-72f8-4b89-b7e8-5e717184d645",
"Number": 82,

View File

@@ -1,97 +1,64 @@
# The Prairie Schooner — Cutover Runbook (tonight + tomorrow morning)
# The Prairie Schooner — Cutover Runbook
Prepared 2026-07-14 for the after-hours data move + morning UDM Pro cable swap.
REVISED 2026-07-14 evening (Howard's call): **decouple the two migrations.**
Tomorrow morning = NETWORK SWAP ONLY (SonicWall/USG out, UDM Pro in). Nothing else
changes — Q: keeps pointing at \\tps-server, QB keeps running off the OLD server.
If QB works after the cable move, the network is proven. The QB/file-server move to
TPS-SVR happens LATER as its own step with its own test.
Companion file: `udm-dhcp-plan.md` (LAN/DHCP/reservations detail).
## Facts this plan is built on (verified today via RMM/SC)
## State as of tonight (all verified)
- 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.
- QuickBooks CLOSED everywhere: MEL-PC killed clean; TINA + JAYMI had kernel-zombie
QBW (unkillable, hung SMB handle) -> users logged off, both machines rebooted,
QBCFMonitorService stopped on all 3. Zero open handles on the server's Quickbooks share.
- Data ALREADY STAGED on TPS-SVR (held in reserve for the later server move):
robocopy delta completed 18:40 with FAILED=0 — Quickbooks 144.2 GB / Deployment 22.4 GB
in C:\Share\*. Company file: schoonerQB2025.QBW (2.9 GB) + consistent ND/DSN/TLG set.
- Q: -> \\tps-server\quickbooks via GPP in Default Domain Policy — **NOT touched** (stays
on the old server for tomorrow's test).
- Client-visible network today: gateway .1, DHCP from SonicWall, DNS handed = .125.
## TONIGHT — after users leave
## TONIGHT — UDM Pro config only (UniFi app, Pro LAN ISOLATED)
### 1. Data copy (run in ScreenConnect session on TPS-SVR as TPS\guru)
Values in `udm-dhcp-plan.md`. Summary:
- LAN 192.168.1.1/24 (Pro takes the SonicWall's IP), domain tps.local
- DHCP pool 192.168.1.100199
- DNS handed to clients: **.125, .135** — SAME primary as today. Zero observable change.
(Flip to .135-first later, after the network is proven — that control is the point
of this swap.)
- 7 fixed-IP reservations: 3 PCs, 3 Yealink phones, Dahua NVR (MACs in the plan file)
- Content filtering / DNS Shield / ad-block OFF
- WAN already live on the Cox modem (public DHCP)
QuickBooks must be CLOSED on all workstations (QBW/TLG lock + change under copy).
## TOMORROW MORNING — cables + test
```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
```
1. Pull SonicWall (.1) and USG; patch the office switch into the Pro's LAN port.
2. On one workstation: `ipconfig /renew` -> expect SAME IP, gw .1, DNS .125/.135,
internet up.
3. Log on as a user (Howard has passwords): Q: maps to \\tps-server\Quickbooks
(unchanged), open the company file — QB works exactly as yesterday.
-> proves the network move broke nothing.
4. Phones: dial tone / registration on all 3 Yealinks. NVR: local UI + remote view.
5. Run `bash clients/prairie-schooner/verify-cutover.sh` from ClaudeTools for the
scripted pass/fail readout.
- ~179 GB over gigabit: expect roughly 3060 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).
**Rollback:** plug the SonicWall back in — nothing else was changed.
### 2. Create the shares on TPS-SVR (match old server exactly)
## LATER (separate visit) — QB/file-server move to TPS-SVR
```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
```
Data is already staged; refresh + cut when ready:
1. QB closed everywhere -> re-run the robocopy delta (seconds).
2. On TPS-SVR: create shares
`New-SmbShare -Name Quickbooks -Path C:\Share\Quickbooks -FullAccess Everyone`
`New-SmbShare -Name Deployment -Path C:\Share\Deployment -FullAccess "NT AUTHORITY\Authenticated Users" -ReadAccess Everyone`
3. Install QB Database Server Manager (match their QB Desktop year) -> scan C:\Share\Quickbooks.
4. GPMC: Default Domain Policy -> User Prefs -> Drive Maps -> Q: -> \\tps-svr\Quickbooks.
5. Relogon test on one PC, open company file multi-user.
6. Flip Pro DHCP DNS order to .135, .125.
- 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.
## Then the AD retirement (unchanged)
### 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.100199, 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.
FSMO transfer, CA migration (test Backup-CARoleService key export first), QB checks,
demote TPS-SERVER + power off, real backup. Old server stays ON until this completes —
it is still a DC, DNS (.125), CA, and (for now) the QB host.

View File

@@ -9,8 +9,10 @@ against the 2026-07-14 onsite ping sweep. Goal: every device keeps its current I
- 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)
- DHCP DNS handed to clients: **192.168.1.125, 192.168.1.135** for the swap (SAME primary as
the SonicWall hands today — the gateway swap must change nothing observable). AFTER the
network is proven, flip the order to .135 first on the Pro (the migration unblock — now a
10-second change we control).
- Disable content filtering / DNS Shield / ad-block (DCs do DNS)
## Fixed-IP reservations (MAC -> IP)

View File

@@ -9,9 +9,9 @@ eval "$(bash .claude/scripts/rmm-auth.sh 2>/dev/null)" || { echo "[ERROR] RMM au
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"
TINA=$(resolve TPS-Tina); SVR=$(resolve TPS-SERVER)
[ -z "$TINA" ] || [ -z "$SVR" ] && { echo "[ERROR] could not resolve agents (TINA=$TINA SERVER=$SVR)"; exit 1; }
echo "[INFO] TPS-Tina=$TINA TPS-SERVER=$SVR"
WS_SYS='
$ErrorActionPreference="Continue"
@@ -20,9 +20,10 @@ Write-Output ("IP: " + $ip.IPv4Address.IPAddress + " GW: " + $ip.IPv4DefaultGat
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"))
try{$r=Resolve-DnsName tps.local -Server 192.168.1.125 -ErrorAction Stop; Write-Output ("DNS via .125 tps.local: OK -> " + (($r|ForEach-Object{$_.IPAddress}) -join ","))}catch{Write-Output "DNS via .125: FAIL"}
try{$r=Resolve-DnsName tps.local -Server 192.168.1.135 -ErrorAction Stop; Write-Output "DNS via .135: OK"}catch{Write-Output "DNS via .135: FAIL"}
Write-Output ("UNC \\tps-server\Quickbooks (LIVE QB path): " + (Test-Path "\\tps-server\Quickbooks"))
Write-Output ("UNC \\tps-svr\Share (staging): " + (Test-Path "\\tps-svr\Share"))
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()
@@ -30,12 +31,12 @@ $ext=(Resolve-DnsName myip.opendns.com -Server resolver1.opendns.com -ErrorActio
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:\))'
Write-Output ("Q:\ accessible: " + (Test-Path Q:\))
Write-Output ("company file visible: " + (Test-Path "Q:\schoonerQB2025.QBW"))'
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-Service | Where-Object{$_.Name -like "QBDBMgr*" -or $_.Name -like "QBCFMonitor*" -or $_.Name -eq "DNS" -or $_.Name -eq "NTDS"} | ForEach-Object{ Write-Output ($_.Name + ": " + $_.Status) }
Get-SmbShare | Where-Object{$_.Name -eq "Quickbooks"} | 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))'
@@ -63,11 +64,11 @@ 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"
echo; echo "##### TPS-SERVER (old, still the QB host) 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."
echo "[INFO] NETWORK-SWAP-ONLY pass criteria: GW ping True, internet True, DNS .125 + .135 OK,"
echo "[INFO] UNC \\\\tps-server\\Quickbooks True, Q: -> \\\\tps-server\\Quickbooks + company file True,"
echo "[INFO] QBDBMgr Running on TPS-SERVER, phones+NVR ping True, egress != 184.176.147.183."

View File

@@ -0,0 +1,79 @@
# 2026-07-14 — MSP360 expired-license fix + backup triage worklist
## User
- **User:** Howard Enos (howard)
- **Machine:** Howard-Home
- **Role:** tech
## Session Summary
Started from a license-expired error on VWP-FILES ("The license (LicenseID: 0a120352-...) assigned to the computer has expired"). Diagnosis: the 2026-07-01 monthly renewal left 4 Server seats expired, stranding VWP-FILES + WINFileSvr (Valleywide), CS-SERVER (Cascades of Tucson), and DESKTOP-BMBTQLI (Len's Auto), all in automatic license mode. The Licensing API (Grant/Release/Revoke) is feature-gated off (HTTP 400), so the fix was console-side: Howard bought 4 Server licenses in the MSP360 console.
Executed the swap on the 3 reachable machines: restart Online Backup service + force plan run via `cbb.exe plan -r` (service restart alone does NOT grab a new seat; the plan run does). All three verified backing up clean on new 8/1 seats (VWP-FILES 0.47GB, WINFileSvr 2.0GB, CS-SERVER 2.61GB). DESKTOP-BMBTQLI left to self-heal at next scheduled run (verify tomorrow via `msp360 licenses`).
Merged the triage backlog from the parallel session (`2026-07-14-howard-msp360-backup-list-discord.md`) and worked it by priority: fixed the msp360 skill CLI (`--license-id` now required on release/revoke — API rejects without it), diagnosed Blaster2 disk-full (decision package for Mike), restarted the crashed backup service on Hartman DESKTOP-EVA4H1A and re-ran its plan, and Howard fixed FSG-SRV-02's schedule in console.
Ran the stale-P2 sweep: root-caused IMC1's 628-day-stale Images plan (schedule `Enabled=false` in the plan XML — plan intact, Files/SQL plans fine), found LAB-SVR's RMM agent dead since 06-18 (SC service restarts did not reconnect it; Howard confirmed the box is offline — hands-on item), and confirmed GTI-INV-VMHOST, Tedards DESKTOP-SUFJR0J, TSAM-SERVER, and Desert RV DESKTOP-9T0UAON are unreachable by any remote path (not in RMM; SC absent or agent offline).
## Key Decisions
- License fix executed per Mike's "fix all"; Howard purchased 4 Server seats (console) because the Licensing API is feature-gated off.
- Plan force-run (`cbb.exe plan -r "<name>"`), not just service restart, is the trigger that makes an auto-mode agent grab a fresh seat.
- Monitoring feed lag pattern confirmed: a fresh LastStart with prior FAILED status + no error means a run is in flight — verify by re-poll, not by first read.
- Blaster2 deletion/retention decision deferred to Mike at end of session (Howard: "we will pass that decision to mike when we are done").
- No-plan clients ON HOLD per Howard: "we wont be deleting anyone just yet" — excluded from the Mike package.
- IMC1 Images plan NOT silently re-enabled — 224GB job, deliberate-looking disable; flagged for decision (going over it next).
- LAB-SVR marked needs-hands-on rather than chasing further blind SC commands.
## Problems Encountered
- `release-license --user-id` alone → HTTP 400 "LicenseID field is required" — fixed in CLI (`--license-id` now required for release/revoke); SKILL.md updated, errorlog'd.
- Licensing API gate: POST /api/Licenses/* → HTTP 400 "not enabled for your account" — console-only; errorlog'd.
- RMM dispatch: raw heredoc JSON with `\\` escapes rejected ("invalid escape") — build payloads with `jq -n --arg`.
- RMM quote-stripping: bash `'...''...'` concatenation collapsed the PS single quotes → `C:\Program` not recognized; use bash double-quoted strings with embedded PS single quotes.
- Service restart on stranded machines did not trigger license swap — force plan run did.
- Foreground `sleep` blocked by harness — poll loops in background Bash instead.
## Configuration Changes
- `.claude/skills/msp360/scripts/msp360.py` (+ user copy `C:\Users\Howard\.claude\skills\msp360\scripts\msp360.py`): `--license-id` required for release-license/revoke-license.
- `.claude/skills/msp360/SKILL.md` (+ user copy): usage line + gotchas (Licensing API gated, Release/Revoke need LicenseID).
- `errorlog.md`: Licensing API gate entry.
- Scratch (removed/ignorable): `./.lic.json`, `./.mon.json`, `./.bill.json`.
## Credentials & Secrets
- None new. MSP360 API creds from vault `msp-tools/msp360-api.sops.yaml`; RMM from `infrastructure/gururmm-server.sops.yaml`; SC from `msp-tools/screenconnect.sops.yaml`.
## Infrastructure & Servers
- New Server seats (bought 2026-07-14): VWP-FILES=fcc6c069..., WINFileSvr=5bf8d40c..., CS-SERVER=db511bb2... (all exp 2026-08-01); 4th reserved for DESKTOP-BMBTQLI self-heal.
- Blaster2 (Jimmy Company) E: 7.45TB FULL — MSP360 repo `E:\MSPBackup\MBS-d94b286b-d22e-49c3-8bb1-415848f448f4` = 6,728.9 GB; reclaimable: `E:\VeeamBackup` 542.9 GB (newest file 3/29/2024), `E:\My backups` 98 GB, FileHistory 80.6 GB.
- IMC1 (Instrumental Music, RMM id 88cbf7c0-abfa-4f12-846c-96274f718bff, online): plans Files dd1f1d8d / Images 2438483c (schedule Enabled=false, OnceDate 2020-03-18, last ran 2024-10-24) / SQL 2ede2a63 (Warning). Plan XMLs: `C:\ProgramData\Online Backup\<plan-guid>.cbb`.
- LAB-SVR (Len's Auto): RMM agent 8afb1430-c8f2-4fa2-8335-35b13d8a732f last_seen 2026-06-18, v0.6.66; SC session 8d111067-7246-4c91-8027-d0fbb8c3a2de. Box offline per Howard.
- Hartman DESKTOP-EVA4H1A (RMM 54ff7d66-8f3f-44a6-98a8-1419ffa78f6d): service crash mid-scan (net.pipe CBBPlanStatusMonitor gone); after restart the re-run was live at save time (log 2eff7410-70b5-468c-b17a-0440e3969283.log writing 20:55 local, deep repo sync).
- FSG-SRV-02: Image plan OK (8.9GB); Files plan FAILED 2026-07-15T01:46 UTC 0.0B after Howard's console fix — re-check pending.
- Unreachable stale machines: GTI-INV-VMHOST (no RMM/SC; SC has GTI-INV-DC/DC1/SQL only), DESKTOP-SUFJR0J (Tedards, none), TSAM-SERVER (SC a5845c99... agent offline since 2021 events), DESKTOP-9T0UAON (Desert RV, SC d2ecf021... offline).
## Commands & Outputs
- `py .claude/skills/msp360/scripts/msp360.py monitoring --company X` / `--stale 30` / `licenses --json` — primary reads.
- RMM dispatch pattern: `PAYLOAD=$(jq -n --arg cmd "$SCRIPT" '{command_type:"powershell", command:$cmd, timeout_seconds:120}')` then POST `/api/agents/<id>/command`; PS paths in single quotes inside a bash double-quoted string.
- cbb: `& 'C:\Program Files\Arizona Computer Guru\Online Backup\cbb.exe' plan -l` / `plan -r "<name>"`; logs `C:\ProgramData\Online Backup\Logs\<plan-guid>.log`.
- Plan schedule check: `[xml]$x = Get-Content '<plan-guid>.cbb'; $x.DocumentElement.Schedule` → IMC1 Images `Enabled: false`.
- SC blind restart: `sc.py send-command --session <id> --command "powershell ... Get-Service *guru*|Restart-Service" --confirm` → returns `{}`; verify by RMM last_seen poll (LAB-SVR: NOT reconnected).
## Pending / Incomplete Tasks
- Verify DESKTOP-BMBTQLI (Len's Auto) grabs the 4th new seat at next scheduled run (`msp360 licenses` tomorrow).
- Re-check Hartman DESKTOP-EVA4H1A run completion (was in-flight at save).
- Re-check FSG-SRV-02 Files plan (Howard fixed console-side; last poll FAILED 0.0B — may need log dig; box not in RMM, use SC).
- IMC1 Images plan re-enable decision — being discussed next.
- End-of-session Mike package: Blaster2 disk-full options (delete VeeamBackup 543GB / My backups 98GB / FileHistory 81GB + tighten MSP360 retention). No-plan clients EXCLUDED (on hold per Howard).
- Hands-on list: LAB-SVR (offline), GTI-INV-VMHOST, Tedards DESKTOP-SUFJR0J, TSAM-SERVER, Desert RV DESKTOP-9T0UAON. Deferred per Howard: Air Pros, Tucson Coin.
## Reference Information
- Stranded-machine user/license IDs + status/error codes: see `session-logs/2026-07/2026-07-14-howard-msp360-backup-list-discord.md` (companion session).
- MSP360 error codes: 1407 MBSLicense, 1506 dest-full, 1537 retention-without-full.
- "Consistency check" plans stuck Running = UI artifact, ignore.

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,7 @@ Run `/wiki-lint` to check for stale entries and broken backlinks.
| Article | Summary | Last Compiled |
|---|---|---|
| [Cascades of Tucson](clients/cascades-tucson.md) | Prepaid block $175/hr, **37.5 hrs remaining** (live 2026-07-10); senior living; active domain migration + HIPAA caregiver-lockdown project (GPOs deployed; Entra Hybrid Join + CA allow-list + ALIS SSO model proven); single DC (CS-SERVER) on aging R610 -- RAID **live-verified HEALTHY 2026-06-24** (the 6/15 "degraded" self-recovered; both mirrors Ok, 1:0:4 = global hot spare; consumer 320GB drives + lost-PSU-redundancy are planned follow-ups, NOT an emergency); cloud backup verified running; **Planned power outage 2026-06-23** clean self-shutdown executed + verified (bring-up ~09:00, John onsite); **Voice VLAN 30 migration COMPLETE 2026-06-19** (~38 devices: 29 Poly + 8 AudioCodes + desktop; awaiting Vertical to set Poly 5GHz-only); **UniFi RF optimized 2026-06-19** (77 U7-Pro APs/~587 clients: 2.4GHz power->Medium on 47 radios + 5GHz clean-DFS 40MHz channel plan -> 5GHz retry halved; 6GHz blocked by WPA3 on PPSK SSID); Syncro 0 open tickets (live EOD 2026-06-25), device-readiness audit done (5 PCs on Win Home need Home->Pro before join); **Alma Montt offboarded 2026-06-25** (Tenant Admin SP left holding a standing PAA role -- removal pending Mike); **CARF Technology & System Plan** deliverable in progress for Ashley Jensen; **endpoint security migration started 2026-06-25** (Datto EDR/AV replacing Bitdefender; 34 agents enrolled); **CS-SERVER: all Datto software removed 2026-06-26**, and the CS-SERVER "SMB error 67" proved to be an RMM-test artifact -- server is healthy, Karen share access verified interactively; **caregiver phone login LIVE 2026-07-01: roster reconciled to 35 (8 offboarded incl. Lassey dup, 4 new hires), two CA blockers fixed (MFA-exclude bug + compliance-block disabled), interim posture = desktops+phones on-network only; ALIS Email=UPN match + 3 new-hire ALIS records pending**; **CSC ENT->VLAN 20 migration (live 2026-07-01): 22 machines on VLAN 20 (only CS-SERVER + ~6 stragglers left on old LAN); printer shares lag at 4/15 repointed; P&P GPO still pilot-scoped**; `PSO-Caregivers` never-expire FGPP created 2026-07-02 (stops the 42-day cohort re-break); Shelby "Company Web Docs" share built 2026-07-02; Chris Knight granted FullAccess+SendAs on `accounting@` 2026-07-09; remaining-work plan: docs/REMAINING-WORK-PLAN.md | 2026-07-10 |
| [Dataforth Corporation](clients/dataforth.md) | Prepaid block ~$2,099/mo, **30.0 hrs remaining** (live 2026-07-04, 0 open tickets); signal-conditioning manufacturer; 64 DOS test stations; **new 2026-07-04: undocumented MYDATA TPSys SMT line controller (`myserver`, Fedora Core 3, VLAN2) discovered — root recovered via LILO single-user + vaulted; RMM agent ruled out (legacy glibc/kernel/no-systemd)**; test-data-chain audit 2026-07-01 (NWTOC v5.0 spec-copy gap = Syncro #32489); PBX inbound-SIP DNAT emergency fixed 2026-06-23; DFORTH-Ship 0x116 BSOD (aging G1 USDT); 2025 ransomware recovery + incomplete file restore; 2026-03 phishing + MFA; test-datasheet pipeline (Hoffman API + testdatadb on AD2); mail stack INKY->Mailprotector->EXO; shares-ACL project (all open to staff; Phase 2 strawman 2026-06-22); GuruRMM fleet ~45; Bitdefender phase-off | 2026-07-04 |
| [Dataforth Corporation](clients/dataforth.md) | Prepaid block ~$2,099/mo, **24.75 hrs remaining** (live 2026-07-14, 4 open tickets); signal-conditioning manufacturer; DOS test stations (NWTOC v5.1 deployed fleet-wide 2026-07-05); MYDATA TPSys SMT line controller (`myserver`, Fedora Core 3, VLAN2 — root recovered + DR backup); **2026-07-14: PBX SIP DNAT durable fix (native UniFi Port Forwarding rule, #32553) + Sage printing fix (stale RDP sessions on SAGE-SQL, #32552; Sage `guru` credential vaulted at `clients/dataforth/sage`)**; Sage Pro 200 ERP runs on SAGE-SQL RDS only (Easy Print redirection — native drivers not installed, watch item); 2025 ransomware recovery + incomplete file restore; 2026-03 phishing + MFA; test-datasheet pipeline (Hoffman API + testdatadb on AD2); mail stack INKY->Mailprotector->EXO; shares-ACL project (Phase 2 strawman 2026-06-22); GuruRMM fleet ~50; Bitdefender phase-off | 2026-07-14 |
| [Desert RV Center](clients/desert-rv-center.md) | Break-fix + $213.35/mo recurring; RV dealership, Huachuca City AZ; 6 managed devices; DESERTRV.local domain (LAN 10.0.0.0/24); remote users RDP into on-site VMs over **ZeroTier** ("Desert RV" net 172.29.0.0/16); **2026-07-08: restored Alicia's RDP to DRV-BECKY** (stopped ZeroTierOneService = RDP 0x204; started + auto-restart; BECKY + DESKTOP-LBO396F enrolled in GuruRMM); DRV-BECKY firewall locked to RDP-only (no silent RMM push); BECKY slowness pending; 0 open tickets | 2026-07-08 |
| [Instrumental Music Center](clients/instrumental-music-center.md) | Prepaid block $175/hr; music retail/repair; AIMsi POS on IMC1\SQLEXPRESS (SQL 2019 Std, misleading name); phantom DC (ServerIMC) slow logons; **two locations split into GuruRMM Main + MOO sites 2026-07-07** (Main 14 agents / MOO 3: BigMom, GHG12G3, IMC-LUIS); full fleet enrolled; AV = Datto EDR (not Bitdefender); IMC1 SQL max-memory caps applied 2026-07-07 | 2026-07-10 |
| [Jimmy Company](clients/jimmy.md) | Break-fix, $150/hr; single aging workstation BLASTER2 (Win10 22H2 EOL, i5-3470/3.8GB — replace); backups the recurring theme (QuickBooks data); onboarded to GuruRMM 2026-06-19 (RDP NLA + Kaseya removal + cleanup); MSP360 local backup drive full, 90-day retention set, space reclaim pending in console (cloud B2 healthy) | 2026-06-19 |