sync: auto-sync from GURU-5070 at 2026-06-15 11:20:33

Author: Mike Swanson
Machine: GURU-5070
Timestamp: 2026-06-15 11:20:33
This commit is contained in:
2026-06-15 11:20:52 -07:00
parent 5f4a2b1eca
commit 6e1c65877f
14 changed files with 585 additions and 7 deletions

View File

@@ -0,0 +1,25 @@
---
name: rmm-search
description: Cleanly find machines in the GuruRMM fleet with a flexible, client-aware search (no more grepping /api/agents and hitting the wrong client's box). Front door for locating an agent before acting on it via /rmm.
---
# /rmm-search — find GuruRMM machines on the first try
Thin entry point to the `rmm-search` skill. Engine: `.claude/scripts/rmm-search.sh`.
## Usage
```
/rmm-search <words...> [-c <client>] [--online] [--json] [-n N]
/rmm-search -c <client> List ALL machines for a client
/rmm-search --list-clients Show distinct client names
```
Every query word must match some field (hostname/client/site/OS/id), so words
**narrow**`hyperv valleywide` returns only Valley Wide's hyperv host, never
Dataforth's. Matching is normalized (case/space/hyphen-insensitive) with
prefix/substring/subsequence ranking; `-c` is an explicit hard client scope and
refuses to guess when the client name is ambiguous.
Use this to *find* an agent; pass the resulting hostname/id to `/rmm` to *act*.
Full matching rules + examples: `.claude/skills/rmm-search/SKILL.md`.

View File

@@ -12,6 +12,7 @@
- [Community Forum (Flarum)](reference_community_forum.md) — Flarum forum at community.azcomputerguru.com, API access, database, posting workflow. - [Community Forum (Flarum)](reference_community_forum.md) — Flarum forum at community.azcomputerguru.com, API access, database, posting workflow.
- [Radio Show Website](reference_radio_website.md) — Astro static site at radio.azcomputerguru.com on IX server. - [Radio Show Website](reference_radio_website.md) — Astro static site at radio.azcomputerguru.com on IX server.
- [IX Server Access](reference_ix_server_access.md) — `ix.azcomputerguru.com` / 172.16.3.10. Reachable when Tailscale is on (no VPN). SSH currently uses sshpass with root password; key auth from GURU-5070 not configured yet (was CachyOS, now Win11 — verify). - [IX Server Access](reference_ix_server_access.md) — `ix.azcomputerguru.com` / 172.16.3.10. Reachable when Tailscale is on (no VPN). SSH currently uses sshpass with root password; key auth from GURU-5070 not configured yet (was CachyOS, now Win11 — verify).
- [Cloudflare access](reference_cloudflare_access.md) — Cloudflare API creds in SOPS `services/cloudflare.sops.yaml` (full DNS + account tokens; azcomputerguru zone_id 1beb9917...). azcomputerguru.com DNS is on Cloudflare (not IX) — edit via Cloudflare API, not whmapi1.
- [Matomo Analytics](reference_matomo_analytics.md) — Self-hosted analytics at analytics.azcomputerguru.com, site IDs, tracking for all 3 sites. - [Matomo Analytics](reference_matomo_analytics.md) — Self-hosted analytics at analytics.azcomputerguru.com, site IDs, tracking for all 3 sites.
- [TickTick Integration](reference_ticktick_integration.md) — OAuth API integration, MCP server, SOPS vault creds, project/task CRUD. - [TickTick Integration](reference_ticktick_integration.md) — OAuth API integration, MCP server, SOPS vault creds, project/task CRUD.
- [Client Docs Structure](reference_client_docs_structure.md) — clients/<name>/docs/ layout (overview, network, servers, cloud, security, rmm). Template: clients/_client_template/. - [Client Docs Structure](reference_client_docs_structure.md) — clients/<name>/docs/ layout (overview, network, servers, cloud, security, rmm). Template: clients/_client_template/.
@@ -39,6 +40,7 @@
- [Verify committed state before push](feedback_verify_committed_state_before_push.md) — webhook builds from origin/main: verify the COMMITTED build (git stash + build), not the working tree; bad git-add pathspec silently aborts staging. Stage by directory. - [Verify committed state before push](feedback_verify_committed_state_before_push.md) — webhook builds from origin/main: verify the COMMITTED build (git stash + build), not the working tree; bad git-add pathspec silently aborts staging. Stage by directory.
- [Scheduling = coord todo, not schedulers](feedback_scheduling_via_coord_todo.md) — Defer future work as a coord todo (POST /api/coord/todos; needs text + created_by_user + created_by_machine) for a later session to pick up. NOT /schedule remote CCR agents (no vault/creds there) or local scheduled tasks. - [Scheduling = coord todo, not schedulers](feedback_scheduling_via_coord_todo.md) — Defer future work as a coord todo (POST /api/coord/todos; needs text + created_by_user + created_by_machine) for a later session to pick up. NOT /schedule remote CCR agents (no vault/creds there) or local scheduled tasks.
- [DMARC rua INKY only when onboarded](feedback_dmarc_rua_inky_onboarded_only.md) — Don't point a client's DMARC rua at reports-sg.inkydmarc.com unless that client is onboarded to INKY (most aren't). Use plain `p=none` with no rua otherwise. - [DMARC rua INKY only when onboarded](feedback_dmarc_rua_inky_onboarded_only.md) — Don't point a client's DMARC rua at reports-sg.inkydmarc.com unless that client is onboarded to INKY (most aren't). Use plain `p=none` with no rua otherwise.
- [Use rmm-search to find machines](feedback_rmm_search_skill.md) — Find GuruRMM agents via the `rmm-search` skill (`rmm-search.sh <words> [-c client]`), never hand-grep /api/agents (it bleeds across clients). Then hand hostname/id to `/rmm`.
- [DM wrapped command lines to Mike](feedback_dm_wrapped_command_lines.md) — Long single-line output (consent links, URLs, one-liners) gets DM'd to Mike via the `discord-dm` skill so it's copy-pasteable, not terminal-wrapped. `discord-dm.sh mike "<link>"`. - [DM wrapped command lines to Mike](feedback_dm_wrapped_command_lines.md) — Long single-line output (consent links, URLs, one-liners) gets DM'd to Mike via the `discord-dm` skill so it's copy-pasteable, not terminal-wrapped. `discord-dm.sh mike "<link>"`.
- [Attribution is read, never inferred](feedback_attribution_from_identity.md) — Who-did-what (user+machine) comes ONLY from identity.json + users.json + git authorship. Never infer from hostname patterns, the userEmail hint, or memory. The "5070" box is Mike's. sync.sh reconciles git config to identity.json; /save renders the User block via whoami-block.sh. - [Attribution is read, never inferred](feedback_attribution_from_identity.md) — Who-did-what (user+machine) comes ONLY from identity.json + users.json + git authorship. Never infer from hostname patterns, the userEmail hint, or memory. The "5070" box is Mike's. sync.sh reconciles git config to identity.json; /save renders the User block via whoami-block.sh.
- [D2TESTNAS SSH Access](feedback_d2testnas_ssh.md) — Use root@192.168.0.9 with Paper123!@#, not sysadmin. - [D2TESTNAS SSH Access](feedback_d2testnas_ssh.md) — Use root@192.168.0.9 with Paper123!@#, not sysadmin.

View File

@@ -0,0 +1,12 @@
---
name: feedback-rmm-search-skill
description: Use the rmm-search skill to find GuruRMM machines, never grep /api/agents by hand
metadata:
type: feedback
---
To locate a machine/agent in GuruRMM, use the **`rmm-search`** skill (`bash .claude/scripts/rmm-search.sh <words> [-c <client>]`) — do NOT pull `/api/agents` and grep client-side.
**Why:** Hand-grepping bleeds across clients and picks the wrong box — e.g. searching `hyperv` returns both Valley Wide's and Dataforth's hyperv hosts, and it's easy to act on the wrong one. Mike built the UI Omnibox for this and asked for a CLI equivalent (2026-06-15). rmm-search treats every query word as a required filter across hostname/client/site/OS (so `hyperv valleywide` can only return Valley Wide's box), is normalized (case/space/hyphen-insensitive) with typo tolerance, and `-c <client>` hard-scopes (refuses to guess on ambiguous client names).
**How to apply:** `rmm-search.sh hyperv valleywide` or `... hyperv -c valleywide` to find; `--json | jq -r '.[0].id'` to get the agent id; then hand hostname/id to the [[reference_gururmm]] `rmm` skill to actually run commands. Online state is from last_seen (<5min), not the unreliable `is_connected` flag. Engine: `rmm-search.sh` + `rmm-search.py`.

View File

@@ -0,0 +1,14 @@
---
name: reference-cloudflare-access
description: Where the Cloudflare API credentials live (SOPS vault) — azcomputerguru.com DNS is on Cloudflare, not the IX nameservers
metadata:
type: reference
---
Cloudflare API access is in the SOPS vault at **`services/cloudflare.sops.yaml`** (account "Mike@azcomputerguru.com Account", account_id `44594c346617d918bd3302a00b07e122`). Fields under `credentials`:
- `api_token_full_account` — full-account token (`solitary-rain-773d`, added 2026-05-10, expires 2027-05-10)
- `api_token_full_dns` — full DNS-edit token (use this for DNS record changes)
- `api_token_legacy` — legacy token
- `zone_id_azcomputerguru` = `1beb9917c22b54be32e5215df2c227ce`
**azcomputerguru.com DNS is hosted on Cloudflare** (ns mckinley/amir.ns.cloudflare.com), NOT the IX/cPanel nameservers (ns1/ns2.acghosting.com) that most CLIENT domains use. So azcomputerguru.com zone edits go through the Cloudflare API, not `whmapi1`. Pattern: `curl -H "Authorization: Bearer <api_token_full_dns>" https://api.cloudflare.com/client/v4/zones/<zone_id>/dns_records`. (Used 2026-06-15 to add the cross-domain DMARC report-authorization record `cryoweave.com._report._dmarc.azcomputerguru.com TXT "v=DMARC1;"` so client DMARC reports can be sent to rua@azcomputerguru.com.) See [[reference_ix_server_access]] for client-domain DNS (cPanel).

View File

@@ -0,0 +1,138 @@
#!/usr/bin/env python3
"""rmm-search engine. Reads the GuruRMM agents JSON array on stdin; reads
QUERY/CLIENT/ONLINE/JSON/LISTC/LIMIT from the environment. Flexible, forgiving
multi-field search — see rmm-search.sh for usage. Kept as a sidecar (not a
heredoc) because the agents payload is too large to pass as a CLI argument."""
import sys, os, json, re
from datetime import datetime, timezone
raw = sys.stdin.read()
agents = json.loads(raw) if raw.strip() else []
query = os.environ.get("QUERY", "").strip()
client = os.environ.get("CLIENT", "").strip()
online_only = os.environ.get("ONLINE") == "1"
as_json = os.environ.get("JSON") == "1"
list_clients = os.environ.get("LISTC") == "1"
try:
limit = int(os.environ.get("LIMIT", "0") or 0)
except ValueError:
limit = 0
def norm(s):
return re.sub(r'[^a-z0-9]', '', (s or '').lower())
def is_subseq(t, v):
it = iter(v)
return all(c in it for c in t)
def field_score(val, term, allow_subseq):
"""How well a single query word matches one normalized field value."""
if not val or not term:
return 0
if val == term:
return 100
if val.startswith(term):
return 80
if term in val:
return 60
if allow_subseq and len(term) >= 3 and is_subseq(term, val):
return 25
return 0
# field -> (key, weight, allow_subsequence)
FIELDS = [
('hostname', 1.00, True),
('client_name', 0.75, False),
('site_name', 0.60, False),
('os_type', 0.55, False),
('id', 0.40, False),
]
def fresh(last_seen):
if not last_seen:
return False
try:
dt = datetime.fromisoformat(last_seen.replace('Z', '+00:00'))
return (datetime.now(timezone.utc) - dt).total_seconds() < 300
except Exception:
return False
if list_clients:
for n in sorted({(a.get('client_name') or 'Unassigned') for a in agents}):
print(n)
sys.exit(0)
# --- explicit hard client scope (normalized; "valleywide" -> "Valley Wide Plastering") ---
if client:
cn = norm(client)
matched = sorted({(a.get('client_name') or '') for a in agents
if cn and cn in norm(a.get('client_name'))} - {''})
if not matched:
print(f"[ERROR] no client matches '{client}'. Try: rmm-search.sh --list-clients", file=sys.stderr)
sys.exit(2)
if len(matched) > 1:
exact = [m for m in matched if norm(m) == cn]
if len(exact) == 1:
matched = exact
else:
print(f"[AMBIGUOUS] '{client}' matches {len(matched)} clients - narrow --client:", file=sys.stderr)
for m in matched:
print(" - " + m, file=sys.stderr)
sys.exit(3)
agents = [a for a in agents if (a.get('client_name') or '') == matched[0]]
if online_only:
agents = [a for a in agents if fresh(a.get('last_seen'))]
terms = [t for t in (norm(x) for x in query.split()) if t]
joined = norm(query)
def score_agent(a):
if not terms:
return 1 # no query (e.g. "all machines for client X")
nf = [(norm(a.get(k)), w, sub) for k, w, sub in FIELDS]
total = 0.0
for term in terms:
best = max(field_score(val, term, sub) * w for val, w, sub in nf)
if best == 0:
return 0 # AND: every word must hit some field
total += best
if joined and joined in norm(a.get('hostname')):
total += 60 # whole query lands in hostname -> clearly THE machine
return total
results = sorted(((score_agent(a), a) for a in agents),
key=lambda t: (-t[0], (t[1].get('hostname') or '').lower()))
results = [(s, a) for s, a in results if s > 0]
if limit > 0:
results = results[:limit]
if as_json:
print(json.dumps([{
'hostname': a.get('hostname'), 'id': a.get('id'), 'client': a.get('client_name'),
'site': a.get('site_name'), 'os': a.get('os_type'),
'online': fresh(a.get('last_seen')), 'last_seen': a.get('last_seen'), 'score': round(s, 1),
} for s, a in results], indent=2))
sys.exit(0)
scope = f" in '{(agents[0].get('client_name') if (client and agents) else client)}'" if client else ""
if not results:
print(f"No machines match '{query}'{scope}. (try fewer/looser words, or --list-clients)")
sys.exit(0)
hdr = f"{'HOSTNAME':<22} {'CLIENT':<26} {'SITE':<16} {'OS':<8} {'STAT':<7} ID"
print(f"{len(results)} match(es) for '{query}'{scope} (best first):")
print(hdr)
print("-" * len(hdr))
for s, a in results:
st = 'online' if fresh(a.get('last_seen')) else 'offline'
print(f"{(a.get('hostname') or '')[:21]:<22} {(a.get('client_name') or '?')[:25]:<26} "
f"{(a.get('site_name') or '')[:15]:<16} {(a.get('os_type') or '')[:7]:<8} {st:<7} {a.get('id')}")

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env bash
# rmm-search.sh — find machines in the GuruRMM fleet on the first try.
#
# Flexible, forgiving search: normalizes case/spaces/hyphens, matches across
# HOSTNAME + CLIENT + SITE + OS, and treats every query word as a required
# filter (AND). So a query naturally narrows and can't bleed across clients:
# rmm-search.sh hyperv valleywide -> only Valley Wide's hyperv host
# rmm-search.sh hyperv -> every hyperv box, each labeled by client
# rmm-search.sh hyperv -c valleywide -> hard-scope to one client, then search
#
# Usage:
# rmm-search.sh <words...> [-c|--client <name>] [--online] [--json] [-n N]
# rmm-search.sh -c <client> # list ALL machines for a client
# rmm-search.sh --list-clients # show distinct client names
#
# Online state is derived from last_seen recency (<5 min); the API is_connected
# flag is currently unreliable (null fleet-wide). Engine: rmm-search.py.
set -u
ROOT="${CLAUDETOOLS_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
QUERY=""; CLIENT=""; ONLINE=0; JSON=0; LISTC=0; LIMIT=0
while [ $# -gt 0 ]; do
case "$1" in
-c|--client) CLIENT="${2:-}"; shift 2;;
-n|--limit) LIMIT="${2:-0}"; shift 2;;
--online) ONLINE=1; shift;;
--json) JSON=1; shift;;
--list-clients) LISTC=1; shift;;
-h|--help) sed -n '2,20p' "$0"; exit 0;;
*) QUERY="${QUERY:+$QUERY }$1"; shift;;
esac
done
if [ -z "$QUERY" ] && [ -z "$CLIENT" ] && [ "$LISTC" -eq 0 ]; then
echo "[ERROR] give <words>, a --client, or --list-clients" >&2
sed -n '12,17p' "$0" >&2; exit 1
fi
eval "$(bash "$ROOT/.claude/scripts/rmm-auth.sh" 2>/dev/null)" >/dev/null
if [ -z "${TOKEN:-}" ] || [ -z "${RMM:-}" ]; then echo "[ERROR] RMM auth failed (see rmm-auth.sh)" >&2; exit 1; fi
AGENTS=$(curl -s "$RMM/api/agents" -H "Authorization: Bearer $TOKEN")
if [ -z "$AGENTS" ] || [ "${AGENTS:0:1}" != "[" ]; then echo "[ERROR] could not fetch agents: ${AGENTS:0:160}" >&2; exit 1; fi
# Pipe agents on stdin (payload too large for argv on Windows); flags via env.
printf '%s' "$AGENTS" | QUERY="$QUERY" CLIENT="$CLIENT" ONLINE="$ONLINE" JSON="$JSON" LISTC="$LISTC" LIMIT="$LIMIT" \
python3 "$ROOT/.claude/scripts/rmm-search.py"

View File

@@ -23,6 +23,7 @@ that will fail the next email task; fix it with `assign-exchange-role.sh <domain
| cascadestucson.com | cascadestucson.com | 207fa277-e9d8-4eb7-ada1-1064d2221498 | NO | Old app only; IdentityRiskyUser not consented | | cascadestucson.com | cascadestucson.com | 207fa277-e9d8-4eb7-ada1-1064d2221498 | NO | Old app only; IdentityRiskyUser not consented |
| cclac.net | cclac.net | e8a0fafc-21ee-41e8-a5ba-f3a250a8a30e | NO | | | cclac.net | cclac.net | e8a0fafc-21ee-41e8-a5ba-f3a250a8a30e | NO | |
| Cobalt Fine Arts | cobaltfinearts.com | 03c4d4ec-b6d3-4061-a75c-8a4250ba2b29 | NO | | | Cobalt Fine Arts | cobaltfinearts.com | 03c4d4ec-b6d3-4061-a75c-8a4250ba2b29 | NO | |
| Cryoweave | cryoweave.com | 44705a37-b5d8-4bb1-882d-e18775612ada | YES | All apps consented 2026-06-15 (Sec Inv + Exch Op Exchange Admin, User Mgr User Admin + Auth Admin, Tenant Admin CA Admin); no MDE. Onboarded for outbound-email deliverability investigation. ACG GA `sysadmin@cryoweave.com` created (vault clients/cryoweave/m365-sysadmin + 1Password Clients). |
| CUADRO LLC | cuadro.design | b68c7171-31d6-4b63-8243-7a2cade9caf8 | NO | | | CUADRO LLC | cuadro.design | b68c7171-31d6-4b63-8243-7a2cade9caf8 | NO | |
| Curtis Plumbing | cparizona.onmicrosoft.com | d2d7ea54-9146-42d1-b99e-0da098550bde | NO | | | Curtis Plumbing | cparizona.onmicrosoft.com | d2d7ea54-9146-42d1-b99e-0da098550bde | NO | |
| cwconcretellc.com | NETORGFT11452752.onmicrosoft.com | dfee2224-93cd-4291-9b09-6c6ce9bb8711 | NO | | | cwconcretellc.com | NETORGFT11452752.onmicrosoft.com | dfee2224-93cd-4291-9b09-6c6ce9bb8711 | NO | |

View File

@@ -0,0 +1,74 @@
---
name: rmm-search
description: >
Find machines/agents in the GuruRMM fleet cleanly and on the first try. Use
this ANY time you need to locate an RMM agent by name, role, client, site, or
OS before acting on it — instead of pulling /api/agents and grepping (which
bleeds across clients and picks the wrong box). Flexible, forgiving, multi-field
search with a client filter so a query like "hyperv valleywide" returns ONLY
Valley Wide's hyperv host, never Dataforth's. Invoke on: "find the X machine",
"which agent is", "look up <host> in RMM", "<client>'s server/DC/hyperv/file
server", "search RMM for", "what's the agent id for". After finding the agent,
hand its hostname/id to the `rmm` skill to run commands.
---
# rmm-search — clean machine lookup in GuruRMM
The `/rmm` skill resolves agents by grepping `/api/agents` client-side, which is
exactly where lookups go wrong: a bare term like `hyperv` matches every client's
hyperv box, and it's easy to act on the wrong one. This skill does a forgiving,
ranked, **client-aware** search instead. Use it as the front door for *finding*
an agent; use `/rmm` for *acting* on it.
## Usage
```bash
bash .claude/scripts/rmm-search.sh <words...> [-c|--client <name>] [--online] [--json] [-n N]
bash .claude/scripts/rmm-search.sh -c <client> # list ALL machines for a client
bash .claude/scripts/rmm-search.sh --list-clients # distinct client names
```
## How matching works (built for first-try correctness)
- **Normalized:** case, spaces, and hyphens are ignored — `valleywide`,
`valley wide`, and `Valley Wide Plastering` all match the same client.
- **Multi-field:** every query word is matched against `hostname`, `client_name`,
`site_name`, `os_type`, and `id`.
- **AND semantics:** *every* word must hit some field, so adding words **narrows**.
`hyperv valleywide` → only the box that is both a hyperv host AND Valley Wide.
This is why a query can't bleed across clients without `-c`.
- **Ranked:** exact > prefix > substring > subsequence (typo tolerance on
hostnames, e.g. `hyprv``HYPERV`). Hostname matches outrank client/site/OS.
Best result first; a whole-query hostname hit gets a boost.
- **`-c/--client`** is an explicit hard scope. If the client term is ambiguous
(matches >1 client and none exactly), it **lists the candidates and stops**
rather than guessing — narrow the value and retry.
- **`--online`** keeps only agents seen in the last 5 minutes. Online state is
derived from `last_seen`, NOT the API `is_connected` flag (currently null
fleet-wide — don't trust it).
## Output
A ranked table: `HOSTNAME | CLIENT | SITE | OS | STAT | ID` (best match first).
`--json` emits `{hostname,id,client,site,os,online,last_seen,score}` for piping
the `id` into a `/rmm` command. `-n N` caps the rows.
## Examples
```bash
rmm-search.sh hyperv valleywide # VWP-HYPERV1 only (not DF-HYPERV-B)
rmm-search.sh dc -c dataforth # Dataforth's domain controllers
rmm-search.sh vwp fil # VWP-FILES (partial words ok)
rmm-search.sh -c "peaceful spirit" # every Peaceful Spirit machine
rmm-search.sh files valleywide --json | jq -r '.[0].id' # id -> feed to /rmm
```
## Implementation
- Wrapper `.claude/scripts/rmm-search.sh` (arg parsing + auth via `rmm-auth.sh` +
fetch `/api/agents`), engine `.claude/scripts/rmm-search.py` (scoring/filter).
- The agents payload is piped to the engine on **stdin** — it's too large to pass
as a CLI argument on Windows ("Argument list too long").
- Read-only. To run a command on a found agent, pass its hostname/id to `/rmm`.
- Ranking heuristic mirrors the dashboard Omnibox (`scoreMatch`) in spirit but is
deliberately looser (multi-field + subsequence) to favor first-try hits.

View File

@@ -0,0 +1,77 @@
## User
- **User:** Mike Swanson (mike)
- **Machine:** GURU-5070
- **Role:** admin
## Session Summary
First documented ClaudeTools record for **Russo Law Firm** (Tucson personal-injury / law
practice). Triggered by a pre-sales question: the client wants to **move ~6.5 TB of data from
ACG-hosted Seafile into Microsoft 365 SharePoint**, and Mike needs the cost to quote them. A
phone meeting is being scheduled; as of 2026-06-15 the client has not responded to the meeting
request. Pulled their live Syncro record, evaluated the SharePoint storage economics, vaulted a
plaintext M365 admin credential found in the Syncro notes, and built the initial wiki article.
## Syncro snapshot (customer 23331699)
- **Business:** Russo Law Firm — 3505 N Campbell Ave, Tucson, AZ 85719 — main 520-529-1515
- **Account contact:** Shannon Trionfo (stever@rrs-law.com on the account; mobile 520-248-0244)
- **Contacts:** Steve Russo (520-975-9024), Carolyn Russo (520-591-4303),
Pat Broom (pebroom@rrs-law.com, 520-850-6832), Shannon Trionfo (520-248-0244)
- **Prepaid:** 12.0 hrs (notes: moved 13.5 hrs to Syncro 1/16/26; 17.5 hrs to AT 8/15/25)
- **Recurring billing:**
- Sched **509659** "GPS + AV / data backup / Hosting / Office subs" — Monthly, next 2026-06-24,
**$543.50/mo** (this is the managed bundle; the "Hosting" line is the ACG-hosted Seafile data store)
- Sched **499925** "OIT Phone bill" — Monthly, next 2026-07-01, **$45.44/mo** (OITVOIP/PacketDial)
- **Email:** Microsoft 365, tenant **rrs-law.com** (~3 seats, Exchange Online)
- Note: Russo schedule 224454 was deleted during Syncro API research 2026-05-26 and recreated as 509659.
## SharePoint storage cost evaluation (the deliverable for the call)
Client scenario: **3 M365 seats, ~6.5 TB of data, currently in Seafile**, wants to move to SharePoint.
M365 SharePoint pooled storage = 1 TB base + 10 GB/licensed user. At 3 seats that's only ~1.03 TB
included, so almost all 6.5 TB is billable overage.
Microsoft-only options (per client request to keep the comparison MS-only):
| Option | Rate | ~Monthly for 6.5 TB (3 seats) | Notes |
|---|---|---|---|
| **SharePoint Online "Extra File Storage"** | $0.20/GB/mo | **~$1,120/mo (~$13.4K/yr)** | live storage; ~5.47 TB billable after the ~1.03 TB pool. CSP-monthly +20% => ~$1,345/mo |
| **Microsoft 365 Archive** | ~$0.05/GB/mo | ~$333/mo + retrieval fees | cold/inactive sites only; not for live working data |
| **Self-hosted SharePoint Server (Subscription Edition)** | storage = disk (RBS) | licensing + infra + labor | storage escapes the $0.20/GB tax, but SharePoint Server + SQL + Windows licensing + SA + heavy ongoing ops is wildly disproportionate for 3 users (~$8-15K one-time licensing + hardware + setup + monthly maintenance). Not recommended. |
Context / alternatives (for ACG's internal read, not necessarily quoted MS-only):
- They already have what they need in **Seafile** (ACG-hosted, part of the $543.50/mo bundle).
- Backblaze B2 wholesale (~$0.006/GB) = ~$40/mo for 6.5 TB at ACG cost; a managed-archive resell
at e.g. $0.03/GB (~$200/mo) is ~5-6x cheaper than Microsoft and still healthy margin.
**Recommendation / talking points for the call:**
1. Ask **why SharePoint** — a specific feature (Office co-authoring, Teams), or just "we want SharePoint"? Decides everything.
2. Moving all 6.5 TB live into SharePoint is a **~$1,100/mo new line item (~$13.4K/yr)** — roughly
triples their current ACG monthly. Make sure they understand that before committing.
3. Better path if they want the SharePoint UX: put the **working subset in SharePoint Online**
(fits in/near the included pool) and **keep the 6.5 TB bulk in Seafile, linked** from SharePoint.
4. If they just want files-with-web-access, they already have Seafile — no change needed.
5. Self-hosting SharePoint Server is not worth it for 3 seats.
## Credentials & Secrets
- **M365 Global Admin (rrs-law.com tenant):** `guru@rrs-law.com` — found in PLAINTEXT in the Russo
Syncro customer note. **Vaulted** at `clients/russo-law/m365-admin.sops.yaml` (username/password
under `credentials:`; MFA/2FA held by Mike). **TODO: scrub the plaintext password from the Syncro
customer note** now that it's vaulted.
## Pending / Incomplete Tasks
- Client has **not responded** to the meeting request (phone meeting being scheduled).
- Scrub the M365 admin password from the Syncro customer 23331699 note (now vaulted).
- On the call: confirm the "why SharePoint", present the cost, steer toward the hybrid (SP Online
working set + Seafile bulk) unless a hard requirement forces a full move.
## Reference Information
- Syncro customer: https://computerguru.syncromsp.com/customers/23331699
- Schedules: 509659 (managed $543.50/mo), 499925 (OIT phone $45.44/mo)
- M365 tenant: rrs-law.com (~3 seats, Exchange Online)
- Generic MS storage pricing used: SharePoint pool = 1 TB + 10 GB/user; Extra File Storage
$0.20/GB/mo (CSP-monthly ~$0.24/GB); M365 Archive ~$0.05/GB + retrieval. Verify current MS pricing.

View File

@@ -0,0 +1,69 @@
## User
- **User:** Mike Swanson (mike)
- **Machine:** GURU-5070
- **Role:** admin
## Session Summary
Fixed Valley Wide Plastering's copier/scanner (Brother MFC-L3780CDW) scan-to-folder, which had
stopped working after the 2026-06-13 G: file-share migration. Root cause: **VWP-FILES was
multi-homed** (`192.168.0.20` on VLAN 2 + `172.16.9.132` on the new net), and a Windows host
realistically supports one default gateway — only the `.132` NIC had one (`172.16.9.1`). So
cross-VLAN traffic to `.20` arrived on the `.20` NIC but the reply egressed via the `.132`
default-gateway path, and the UDM dropped the asymmetric return. `.20` was therefore unreachable
from any other VLAN (proved: `.20` was silent from the VPN pool while `.25`/`.132` answered). The
copier reaches `\192.168.0.20\<share>` across a VLAN boundary, so it broke.
The previously-documented "VWP-FILES Dual-NIC / asymmetric-routing / same-VLAN-only" note was a
**flawed workaround, not a real constraint** — the UDM routes every VLAN natively (Mike's
correction). Fix: **single-home VWP-FILES on `.20`** and drop `.132`.
## What was done
Diagnostics (read-only): from ADSRVR (a VLAN-2 server) confirmed every VLAN was reachable, SMB
tcp/445 up on `.20`, the `scanner` AD account enabled/unlocked, and all 19 shares present
(`\.20\SCANS` + per-person scan shares). Confirmed the **real VLAN-2 gateway is `192.168.0.1`**
(ADSRVR's gateway) — the wiki said `172.16.9.1`, which was wrong.
Attempt 1 (in-guest via RMM): set `.20` gw `192.168.0.1` + DNS, disabled `.132`. Disabling the
NIC dropped the agent's own connection -> command came back `interrupted`, script killed before
confirming success, and the 7-minute **auto-rollback** task fired and re-enabled `.132` (box
healthy, but back to dual-homed). Lesson: an in-guest NIC change self-interrupts the RMM agent.
Final fix (host-side, per Mike's Hyper-V suggestion): via the **VWP-HYPERV1** RMM agent,
`Disconnect-VMNetworkAdapter` on VWP-FILES's `.132` vNIC (`Network Adapter`, MAC `00155D090501`),
keeping the `.20` vNIC (`OldNet-VLAN2`, MAC `00155D090502`). Completed cleanly (the host's RMM
connection is unaffected by the guest's NIC change). Then cleaned the guest's stale `.132`
IP/route and `ipconfig /registerdns`.
Verified: `.20` now **reachable cross-subnet from the VPN** (was failing pre-fix); single default
route `.20 -> 192.168.0.1`; `VWP-FILES` resolves to `.20` only; 19 shares intact.
## Key facts / corrections
- **VWP-FILES is now single-homed: `192.168.0.20`, gw `192.168.0.1`, DNS `172.16.9.2` + `192.168.0.25`.**
- The `.132` vNIC is **DISCONNECTED at the Hyper-V host (reversible), not removed.**
- **Old Net (VLAN 2, `192.168.0.0/24`) gateway is `192.168.0.1`** — the wiki's `172.16.9.1` was wrong.
- Scanner = **Brother MFC-L3780CDW** (vault `clients/vwp/brother-mfc-l3780cdw`); scans to
`\192.168.0.20\<share>` (shares map under `G:\SCANS\...`).
- RMM agents: VWP-FILES `8e02fbbc`, VWP-HYPERV1 `bdc3e142`.
## Gotchas learned
- **In-guest RMM NIC changes self-interrupt** (the change drops the agent connection). For VM NIC
changes, drive it **host-side** (`Disconnect-VMNetworkAdapter` / PowerShell Direct) so the host
connection survives. Keep an auto-rollback timer either way.
- `/rmm` hostname match `"hyperv"` hit **DF-HYPERV-B** (Dataforth) first — must resolve
`VWP-HYPERV1` explicitly. The script's guard aborted safely on the wrong host (no changes).
## Pending / Incomplete
- Have someone **confirm an actual scan** from the Brother copier (only thing not driveable remotely).
- Decide whether to **fully remove** the disconnected `.132` vNIC or leave it (currently left, reversible).
- Harmless leftover on VWP-FILES: `C:\Windows\Temp\vwp-net-rollback.ps1` (from attempt 1).
## Reference
- VWP-FILES: single-homed `192.168.0.20`, gw `192.168.0.1`. RMM agent `8e02fbbc`.
- VWP-HYPERV1: `172.16.9.184`, RMM agent `bdc3e142`. VWP-FILES vNICs: `Network Adapter`(.132,
disconnected) / `OldNet-VLAN2`(.20).

View File

@@ -62,8 +62,16 @@ CryoWeave manufactures custom cryogenic cable assemblies (millikelvin to 300K) f
### Email & Identity ### Email & Identity
- **Domain:** cryoweave.com - **Domain:** cryoweave.com
- **Email:** Hosted externally [unverified — mail provider not documented] - **Email:** **Microsoft 365 / Exchange Online** (confirmed 2026-06-15 — MX `cryoweave-com.mail.protection.outlook.com`, `autodiscover``autodiscover.outlook.com`). The IX/cPanel box only hosts the website, not mail.
- **Greg's email:** greg@cryoweave.com - **M365 tenant:** Cryoweave | Tenant ID `44705a37-b5d8-4bb1-882d-e18775612ada` | initial domain `cryoweave.onmicrosoft.com`
- **Remediation suite:** onboarded 2026-06-15 (all ComputerGuru apps consented + roles; no MDE). ACG Global Admin `sysadmin@cryoweave.com` created (creds: SOPS `clients/cryoweave/m365-sysadmin.sops.yaml` + 1Password Clients). MFA not yet registered on it.
- **Greg's email:** greg@cryoweave.com (Greg Schickling, owner/GA)
- **DNS (zone on ns1/ns2.acghosting.com / IX) as of 2026-06-15:**
- **SPF** OK: `v=spf1 +a +mx +ip4:72.194.62.5 +ip4:162.248.93.233 +ip4:162.248.93.81 +include:spf.protection.outlook.com -all` (authorizes M365, aligned).
- **DMARC** `_dmarc``v=DMARC1; p=quarantine; sp=quarantine; fo=1; rua=mailto:rua@azcomputerguru.com` (hardened from p=none to **p=quarantine** 2026-06-15; **promote to p=reject** after ~1 week of clean aggregate reports confirm all legit senders — incl. the IX website/contact form — align). Cross-domain report authorization published on the azcomputerguru.com Cloudflare zone: `cryoweave.com._report._dmarc.azcomputerguru.com TXT "v=DMARC1;"` (2026-06-15). `rua@azcomputerguru.com` **shared mailbox created** in ACG's tenant (DisplayName "DMARC Reports", GUID 46b898f8-cfac-4b81-8980-e681b13fb833, mike@ FullAccess+automap) — full reporting chain live; aggregate reports arrive within ~24h. (NB: a single `*._report._dmarc` wildcard does NOT cover a 2-label reported domain; add one per-client record on the azcomputerguru.com Cloudflare zone.)
- **DKIM** (M365 selector1/2): CNAMEs published + **signing ENABLED 2026-06-15** (`Get-DkimSigningConfig`: Enabled=True, Status=Valid, 2048-bit). Targets `selector1-cryoweave-com._domainkey.cryoweave.w-v1.dkim.mail.microsoft` (+ selector2).
- Stale `mail.cryoweave.com` CNAME → old Neptune (67.206.163.124) **removed**.
- **Outbound-email issue (open):** Greg reports mail not reaching recipients. SPF passes/aligns, so auth isn't hard-failing; pending **message trace** (EXO app-only access still propagating after onboarding) + Greg's NDR to pinpoint restriction/reject/junk. DKIM+DMARC gaps were the most likely junking cause.
### Network ### Network

96
wiki/clients/russo-law.md Normal file
View File

@@ -0,0 +1,96 @@
---
type: client
name: russo-law
display_name: Russo Law Firm
last_compiled: 2026-06-15
compiled_by: GURU-5070/claude-main
sources:
- clients/russo-law/session-logs/2026-06/2026-06-15-mike-russo-sharepoint-storage-eval.md
---
# Russo Law Firm
> Tucson law practice; ACG managed-services client (GPS + AV + backup + Seafile hosting + Office
> subs, $543.50/mo) + OITVOIP phone. First documented 2026-06-15 around a pre-sales question:
> moving ~6.5 TB of data from ACG-hosted Seafile into Microsoft 365 SharePoint.
## Overview
- **Business:** Russo Law Firm (law practice), Tucson AZ.
- **Address:** 3505 N Campbell Ave, Tucson, AZ 85719.
- **Main phone:** 520-529-1515.
- **Billing model:** managed services (recurring) + 12 prepaid hours on account.
- **Syncro customer ID:** 23331699.
## Contacts
| Name | Phone | Email | Role |
|---|---|---|---|
| Steve Russo | 520-975-9024 | — | Principal (firm namesake) |
| Carolyn Russo | 520-591-4303 | — | — |
| Shannon Trionfo | 520-248-0244 | (account contact) | Account / billing contact |
| Pat Broom | 520-850-6832 | pebroom@rrs-law.com | — |
Account email on file: stever@rrs-law.com. (Email domain: rrs-law.com.)
## Cloud / M365
- **Microsoft 365** tenant **rrs-law.com**, ~3 seats, Exchange Online (email).
- **Global Admin:** `guru@rrs-law.com` — vaulted at `clients/russo-law/m365-admin.sops.yaml`
(MFA/2FA held by Mike). [WARNING] The password was found in plaintext in the Syncro customer
note; it is now vaulted and should be scrubbed from the Syncro note.
## Data / Storage
- **Primary data store:** ACG-hosted **Seafile** (~6.5 TB), billed under the "Hosting" line of the
managed bundle. This is the system the client is considering moving off of.
## Billing (Syncro recurring schedules)
| Schedule | What | Frequency | Amount |
|---|---|---|---|
| 509659 | GPS + AV + data backup + **Hosting (Seafile)** + Office subs | Monthly | **$543.50** |
| 499925 | OIT phone bill (OITVOIP / PacketDial) | Monthly | $45.44 |
Prepaid: 12.0 hrs on account. (History: 13.5 hrs moved to Syncro 1/16/26; 17.5 hrs to AT 8/15/25.)
Note: schedule 224454 was deleted during Syncro API research 2026-05-26 and recreated as 509659.
## Active Question — SharePoint storage move (2026-06)
The client wants to move **~6.5 TB from Seafile into Microsoft 365 SharePoint**. A phone meeting is
being scheduled (client had not responded as of 2026-06-15). Cost analysis, kept Microsoft-only at
the client's request:
SharePoint pooled storage = 1 TB base + 10 GB/licensed user. At **3 seats** only ~1.03 TB is
included, so nearly all 6.5 TB is billable overage.
| Option | Rate | ~Monthly for 6.5 TB | Notes |
|---|---|---|---|
| **SharePoint Online Extra File Storage** | $0.20/GB/mo | **~$1,120/mo (~$13.4K/yr)** | live storage; ~5.47 TB billable after the pool. CSP-monthly +20% -> ~$1,345/mo |
| **Microsoft 365 Archive** | ~$0.05/GB/mo | ~$333/mo + retrieval | cold/inactive sites only; not for live working data |
| **Self-hosted SharePoint Server** | storage -> disk via RBS | licensing + infra + labor | escapes the $0.20/GB tax but SharePoint Server + SQL + Windows + SA + heavy ops is disproportionate for 3 users (~$8-15K one-time + maintenance). Not recommended. |
For ACG's internal read (cheaper alternatives, not necessarily quoted MS-only): they already have
Seafile; Backblaze B2 wholesale (~$0.006/GB) is ~$40/mo for 6.5 TB at ACG cost, and a managed-archive
resell (~$0.03/GB ≈ $200/mo) would be ~5-6x cheaper than Microsoft with margin.
### Recommendation / call talking points
1. **Ask why SharePoint** (specific feature like Office co-authoring / Teams, or just "we want it"?).
2. A full live move is a **~$1,100/mo new line item (~$13.4K/yr)** — roughly triples their current
ACG monthly. Set that expectation before they commit.
3. Preferred path: **SharePoint Online for the working subset + keep the 6.5 TB bulk in Seafile,
linked** — gets the SharePoint UX without the storage tax.
4. If they only want files-with-web-access, Seafile already does it — no change needed.
5. Don't self-host SharePoint Server for 3 seats.
## Open Items
- Client has not responded to the meeting request (phone meeting pending).
- Scrub the M365 admin password from the Syncro customer note (now vaulted).
- Deliver the SharePoint cost picture on the call; steer toward the hybrid unless a hard
requirement forces a full move.
## Backlinks
- [[internal-infrastructure]] — ACG hosting infra (Seafile runs on Jupiter).
- [[msp-pricing]] — GPS / hosting pricing basis.

View File

@@ -61,7 +61,7 @@ Plastering / stucco subcontractor based in Arizona. Active ACG client. Primary w
| VWP-QBS | 172.16.9.169 | QuickBooks server + RDS/RemoteApp host | Windows Server 2022 Standard | **Physical Dell server** (NOT a VM). Has DRAC. Runs IIS (RD Web Access). WinRM on 5985. Reach from ADSRVR via `Invoke-Command -ComputerName VWP-QBS -Credential` with `vwp\sysadmin` PSCredential. | | VWP-QBS | 172.16.9.169 | QuickBooks server + RDS/RemoteApp host | Windows Server 2022 Standard | **Physical Dell server** (NOT a VM). Has DRAC. Runs IIS (RD Web Access). WinRM on 5985. Reach from ADSRVR via `Invoke-Command -ComputerName VWP-QBS -Credential` with `vwp\sysadmin` PSCredential. |
| Dell DRAC (VWP-QBS) | [undocumented] | Out-of-band management for VWP-QBS Dell | — | DRAC functional as of 2026-04-22. IP not yet documented. Vault: `clients/valleywide/quickbooks-server-idrac`. | | Dell DRAC (VWP-QBS) | [undocumented] | Out-of-band management for VWP-QBS Dell | — | DRAC functional as of 2026-04-22. IP not yet documented. Vault: `clients/valleywide/quickbooks-server-idrac`. |
| VWP-HYPERV1 | 172.16.9.184 | Hyper-V host — primary VM host for new infrastructure | Windows Server 2025 | Dell R740, 112 vCPU / 255 GB RAM, C: 10.7 TB. One external vSwitch on Intel 10G NIC. VHDs in `C:\VHD`. GuruRMM agent `bdc3e142-...`. Added 2026-06-13. | | VWP-HYPERV1 | 172.16.9.184 | Hyper-V host — primary VM host for new infrastructure | Windows Server 2025 | Dell R740, 112 vCPU / 255 GB RAM, C: 10.7 TB. One external vSwitch on Intel 10G NIC. VHDs in `C:\VHD`. GuruRMM agent `bdc3e142-...`. Added 2026-06-13. |
| VWP-FILES | 172.16.9.132 (primary) + 192.168.0.20 (VLAN 2) | G: file share server (19 SMB shares) | Windows Server 2019 Gen2 VM on VWP-HYPERV1 | Block-migrated from SERVER3 G: VDI (100 GB, ~88 GB used). Dual-homed: primary on 172.16.9.0/24; secondary vNIC tagged VLAN 2 holds 192.168.0.20 for IP-based stragglers (see Patterns). DNS registration disabled on the .20 NIC. GuruRMM enrolled (site Main Office, agent `8e02fbbc-...`). MSP360 backup running green. | | VWP-FILES | 192.168.0.20 (single-homed, VLAN 2; gw 192.168.0.1) | G: file share server (19 SMB shares) | Windows Server 2019 Gen2 VM on VWP-HYPERV1 | Block-migrated from SERVER3 G: VDI (100 GB, ~88 GB used). **Single-homed on 192.168.0.20 since 2026-06-15** — the former 172.16.9.132 vNIC was disconnected at the Hyper-V host to fix cross-VLAN scan-to-folder (the Brother copier hard-codes `\\192.168.0.20`; the multi-homed config had a gateway only on the .132 NIC, so replies to off-subnet clients were dropped — see Patterns). The .132 vNIC is DISCONNECTED at the host (reversible), not removed. DNS registers .20 only. GuruRMM enrolled (site Main Office, agent `8e02fbbc-...`). MSP360 backup running green. |
| XenServer | 192.168.0.104 | VM hypervisor — hosts remaining VMs | XenServer 7.6 (PowerEdge R720) | SERVER3 VM (the old "server 2003", upgraded in-place to 2008) is now **powered off and retired**; snapshots retained for rollback. Vault: `clients/vwp/xenserver`. | | XenServer | 192.168.0.104 | VM hypervisor — hosts remaining VMs | XenServer 7.6 (PowerEdge R720) | SERVER3 VM (the old "server 2003", upgraded in-place to 2008) is now **powered off and retired**; snapshots retained for rollback. Vault: `clients/vwp/xenserver`. |
| WINFileSvr | 192.168.0.35 | File server — serves **O:** (`Office_Archive`, ~570 GB / 138K files) + **P:** (`Estimating Archive` = F: root, ~545 GB / 142K files), both GPO-mapped to all staff; actively used daily | Windows Server 2019 | Old Net (VLAN 2). **VMware VM on the ESXi host (VMID 11, `WINFilrSrvr`)** — see ESXi inventory. ~1.1 TB live data. Holds `F:\Darv\Darv.rar` (51 GB Darv dev-machine backup) + `F:\Darv\Darv-rar` (extract, trimmed 135→26 GB on 2026-06-14). GuruRMM `62db0264-...`. Candidate to consolidate into VWP-FILES (retire the VM). Do not delete `Darv.rar` until VB6 source verified to compile. | | WINFileSvr | 192.168.0.35 | File server — serves **O:** (`Office_Archive`, ~570 GB / 138K files) + **P:** (`Estimating Archive` = F: root, ~545 GB / 142K files), both GPO-mapped to all staff; actively used daily | Windows Server 2019 | Old Net (VLAN 2). **VMware VM on the ESXi host (VMID 11, `WINFilrSrvr`)** — see ESXi inventory. ~1.1 TB live data. Holds `F:\Darv\Darv.rar` (51 GB Darv dev-machine backup) + `F:\Darv\Darv-rar` (extract, trimmed 135→26 GB on 2026-06-14). GuruRMM `62db0264-...`. Candidate to consolidate into VWP-FILES (retire the VM). Do not delete `Darv.rar` until VB6 source verified to compile. |
@@ -113,8 +113,8 @@ and let the VM be retired.
- **Firewall / Router:** UniFi Dream Machine at 172.16.9.1 - **Firewall / Router:** UniFi Dream Machine at 172.16.9.1
- **VPN:** OpenVPN on UDM. Client pool: `192.168.4.0/24`. Pushes routes for `172.16.9.0/24`, `192.168.0.0/24`, `192.168.3.0/24`. DNS pushed as `192.168.4.1` (UDM). - **VPN:** OpenVPN on UDM. Client pool: `192.168.4.0/24`. Pushes routes for `172.16.9.0/24`, `192.168.0.0/24`, `192.168.3.0/24`. DNS pushed as `192.168.4.1` (UDM).
- **Subnets:** - **Subnets:**
- `172.16.9.0/24` — primary internal network (new servers, VWP-QBS, UDM, iLO, HYPERV1, VWP-FILES primary NIC); untagged - `172.16.9.0/24` — primary internal network (new servers, VWP-QBS, UDM, iLO, HYPERV1); untagged
- `192.168.0.0/24`**"Old Net" = VLAN 2 on UDM** (gw 172.16.9.1, DHCP .100-.199, DNS → 192.168.0.25 + 8.8.8.8). Hosts: VWP_ADSRVR (.25), WINFileSvr (.35), XenServer (.104), Yealink phones (.17/.54/.130/.140/.222), VWP-FILES secondary NIC (.20). **[WARNING: conflicts with IMC's LAN — verify client context when switching VPNs.]** - `192.168.0.0/24`**"Old Net" = VLAN 2 on UDM** (gw 192.168.0.1, DHCP .100-.199, DNS → 192.168.0.25 + 8.8.8.8). Hosts: VWP_ADSRVR (.25), WINFileSvr (.35), XenServer (.104), Yealink phones (.17/.54/.130/.140/.222), VWP-FILES (.20, single-homed 2026-06-15). **[WARNING: conflicts with IMC's LAN — verify client context when switching VPNs.]**
- `192.168.3.0/24` — Management VLAN 99 - `192.168.3.0/24` — Management VLAN 99
- `192.168.4.0/24` — OpenVPN client pool - `192.168.4.0/24` — OpenVPN client pool
- **Static DNS (UDM):** `vwp-qbs.vwp.us``172.16.9.169` (typo `qwp-qbs` fixed 2026-04-16) - **Static DNS (UDM):** `vwp-qbs.vwp.us``172.16.9.169` (typo `qwp-qbs` fixed 2026-04-16)
@@ -190,9 +190,23 @@ Same double-hop constraint applies to GPMC (`Get-GPO`/`Set-GPO`) — fails `0x80
VWP's Old Net (VLAN 2, `192.168.0.0/24`) is the same RFC1918 range as IMC (another ACG client). When switching between client VPN contexts, verify which 192.168.0.x addresses are targeted. This is a silent risk. VWP's Old Net (VLAN 2, `192.168.0.0/24`) is the same RFC1918 range as IMC (another ACG client). When switching between client VPN contexts, verify which 192.168.0.x addresses are targeted. This is a silent risk.
### VWP-FILES Dual-NIC / Asymmetric Routing ### VWP-FILES single-homed on 192.168.0.20 (resolved 2026-06-15)
VWP-FILES is dual-homed: 172.16.9.132 (primary, new net) + 192.168.0.20 (VLAN 2, Old Net — for IP-based stragglers whose UNC paths hard-code `.20`). DNS registration is **disabled** on the .20 NIC so that name resolution always returns .132. Asymmetric routing applies: cross-subnet or VPN clients cannot reach .20 (VWP-FILES replies via its .132 NIC); only same-VLAN Old Net devices can use .20 directly. Use 172.16.9.132 for all management and file pulls from outside Old Net. VWP-FILES is **single-homed on 192.168.0.20** (VLAN 2 / Old Net, gw 192.168.0.1). The Brother
MFC-L3780CDW copier and other stragglers hard-code `\\192.168.0.20` for scan-to-folder, so the
server must own that address with a working gateway.
History / why this note exists: the server was briefly **dual-homed** (172.16.9.132 primary +
192.168.0.20 secondary). Only the .132 NIC had a default gateway, so the server could not reply
to off-subnet clients arriving on .20 — replies tried to egress via the .132 default route and
were dropped (multi-homed asymmetric routing). That silently broke scan-to-folder for the copier
after the 2026-06-13 cutover. **The UDM routes between all VLANs natively** — any host on any VLAN
can reach any other — so the earlier "only same-VLAN devices can reach .20" theory was wrong; the
real defect was the single-default-gateway asymmetry on a multi-homed host. Fix: drop to one NIC on
.20 with gw 192.168.0.1. Done host-side via `Disconnect-VMNetworkAdapter` on VWP-HYPERV1 (an
in-guest NIC change dropped the RMM agent and auto-rolled-back). The .132 vNIC is left
**disconnected** at the Hyper-V host (reversible — reconnect it in Hyper-V if .132 is ever needed),
not removed. Full procedure: 2026-06-15 session log.
### Syncro Billing for Prepaid Block Emergency ### Syncro Billing for Prepaid Block Emergency
@@ -265,6 +279,7 @@ Power outage caused HP ProLiant NVRAM corruption (BIOS/iLO factory reset). VWP-Q
| 2026-06-13 | SERVER3 (XenServer "server 2003" VM, upgraded to 2008 in-place) retired. G: file share (100 GB) block-migrated via VDI export→VHDX to new **VWP-FILES** (Gen2 Server 2019 on **VWP-HYPERV1** 172.16.9.184). 19 SMB shares recreated; **MappedDrives GPO** repointed to `\\VWP-FILES\G-drive`. IP takeover: VWP-FILES holds 192.168.0.20 (VLAN 2) for IP-based stragglers. SERVER3 snapshotted and powered off. VWP-FILES enrolled in GuruRMM (site Main Office) + MSP360 backup green. Billed 3.5 h on #32418 (prepay 24.0→20.5). | | 2026-06-13 | SERVER3 (XenServer "server 2003" VM, upgraded to 2008 in-place) retired. G: file share (100 GB) block-migrated via VDI export→VHDX to new **VWP-FILES** (Gen2 Server 2019 on **VWP-HYPERV1** 172.16.9.184). 19 SMB shares recreated; **MappedDrives GPO** repointed to `\\VWP-FILES\G-drive`. IP takeover: VWP-FILES holds 192.168.0.20 (VLAN 2) for IP-based stragglers. SERVER3 snapshotted and powered off. VWP-FILES enrolled in GuruRMM (site Main Office) + MSP360 backup green. Billed 3.5 h on #32418 (prepay 24.0→20.5). |
| 2026-06-13 | VB6 Orders source **fully recovered** from `F:\Darv\Darv.rar` on WINFileSvr (192.168.0.35). 12.2 MB staged to repo (`source-code/Orders-VWP_Current-2020/`). VB Decompiler Pro no longer needed. See [[projects/valleywide-orders-modernization]]. | | 2026-06-13 | VB6 Orders source **fully recovered** from `F:\Darv\Darv.rar` on WINFileSvr (192.168.0.35). 12.2 MB staged to repo (`source-code/Orders-VWP_Current-2020/`). VB Decompiler Pro no longer needed. See [[projects/valleywide-orders-modernization]]. |
| 2026-06-13 | **Syncro** and **Datto RMM Agent** deployment GPOs disabled (`AllSettingsDisabled`, flags=3) via LDAP on VWP_ADSRVR. Existing agents not yet uninstalled — awaiting direction. | | 2026-06-13 | **Syncro** and **Datto RMM Agent** deployment GPOs disabled (`AllSettingsDisabled`, flags=3) via LDAP on VWP_ADSRVR. Existing agents not yet uninstalled — awaiting direction. |
| 2026-06-15 | **VWP-FILES scan-to-folder fix.** Copier scan-to-`\\192.168.0.20` broke after the 2026-06-13 cutover — root cause was the dual-homed server having a default gateway only on the 172.16.9.132 NIC, so replies on the .20 NIC to off-subnet clients were dropped (not a VLAN-routing limit; the UDM routes all VLANs). Fix: single-homed VWP-FILES on 192.168.0.20 (gw 192.168.0.1) by disconnecting the .132 vNIC host-side via `Disconnect-VMNetworkAdapter` on VWP-HYPERV1 (in-guest change dropped the RMM agent + auto-rolled-back). .132 vNIC left disconnected (reversible), not removed. Scanner = Brother MFC-L3780CDW (vault `clients/vwp/brother-mfc-l3780cdw`). |
--- ---

View File

@@ -57,6 +57,7 @@ Run `/wiki-lint` to check for stale entries and broken backlinks.
| [Gonzvar Tax Services](clients/gonzvar-tax-services.md) | Tax services firm; Syncro 1830740 ("Gonzvar Tax Service", break-fix, ~$175/hr); 6 machines in GuruRMM (GTS.local AD, 2 servers + 4 workstations); open security findings from 2026-06-06 onboarding baseline; QuickBooks RemoteApp + Tailscale VPN pending | 2026-06-12 | | [Gonzvar Tax Services](clients/gonzvar-tax-services.md) | Tax services firm; Syncro 1830740 ("Gonzvar Tax Service", break-fix, ~$175/hr); 6 machines in GuruRMM (GTS.local AD, 2 servers + 4 workstations); open security findings from 2026-06-06 onboarding baseline; QuickBooks RemoteApp + Tailscale VPN pending | 2026-06-12 |
| [Tohono O'odham Nation DoIT](clients/tohono-oodham-doit.md) | Tribal government IT dept; Syncro 33069069; Starlink reseller client — 2x Check Point 1550 field sites on Starlink Roam (CGNAT); break-fix $175/hr; VPN design (IPsec vs Tailscale) pending | 2026-05-27 | | [Tohono O'odham Nation DoIT](clients/tohono-oodham-doit.md) | Tribal government IT dept; Syncro 33069069; Starlink reseller client — 2x Check Point 1550 field sites on Starlink Roam (CGNAT); break-fix $175/hr; VPN design (IPsec vs Tailscale) pending | 2026-05-27 |
| [Tucson Golden Corral](clients/tucson-golden-corral.md) | Restaurant (Tucson AZ); Syncro 3859123; prepaid block 12.75 hrs; email on Neptune Exchange; WS2016 single-box DC/RDS/Hyper-V/SQL + Sage 100 ERP (TGC-SERVER colocated at ACG main office); architecture concerns outstanding | 2026-05-26 | | [Tucson Golden Corral](clients/tucson-golden-corral.md) | Restaurant (Tucson AZ); Syncro 3859123; prepaid block 12.75 hrs; email on Neptune Exchange; WS2016 single-box DC/RDS/Hyper-V/SQL + Sage 100 ERP (TGC-SERVER colocated at ACG main office); architecture concerns outstanding | 2026-05-26 |
| [Russo Law Firm](clients/russo-law.md) | Tucson law practice; Syncro 23331699; managed $543.50/mo (GPS+AV+backup+Seafile hosting+Office) + OIT phone $45.44/mo; 12 prepaid hrs; M365 rrs-law.com (~3 seats, admin guru@ vaulted); **active pre-sales 2026-06: wants to move ~6.5 TB from Seafile to SharePoint — full live move ~$1,120/mo (~$13.4K/yr), recommend hybrid (SP Online working set + Seafile bulk); phone meeting pending, client not yet responded** | 2026-06-15 |
## Projects ## Projects