From 6e1c65877ff15e5288071cea87a7c97a7bc762b6 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Mon, 15 Jun 2026 11:20:52 -0700 Subject: [PATCH] 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 --- .claude/commands/rmm-search.md | 25 ++++ .claude/memory/MEMORY.md | 2 + .claude/memory/feedback_rmm_search_skill.md | 12 ++ .claude/memory/reference_cloudflare_access.md | 14 ++ .claude/scripts/rmm-search.py | 138 ++++++++++++++++++ .claude/scripts/rmm-search.sh | 46 ++++++ .../remediation-tool/references/tenants.md | 1 + .claude/skills/rmm-search/SKILL.md | 74 ++++++++++ ...6-15-mike-russo-sharepoint-storage-eval.md | 77 ++++++++++ ...-15-mike-vwp-files-single-home-scan-fix.md | 69 +++++++++ wiki/clients/cryoweave.md | 12 +- wiki/clients/russo-law.md | 96 ++++++++++++ wiki/clients/valleywide.md | 25 +++- wiki/index.md | 1 + 14 files changed, 585 insertions(+), 7 deletions(-) create mode 100644 .claude/commands/rmm-search.md create mode 100644 .claude/memory/feedback_rmm_search_skill.md create mode 100644 .claude/memory/reference_cloudflare_access.md create mode 100644 .claude/scripts/rmm-search.py create mode 100644 .claude/scripts/rmm-search.sh create mode 100644 .claude/skills/rmm-search/SKILL.md create mode 100644 clients/russo-law/session-logs/2026-06/2026-06-15-mike-russo-sharepoint-storage-eval.md create mode 100644 clients/valleywide/session-logs/2026-06/2026-06-15-mike-vwp-files-single-home-scan-fix.md create mode 100644 wiki/clients/russo-law.md diff --git a/.claude/commands/rmm-search.md b/.claude/commands/rmm-search.md new file mode 100644 index 0000000..691684e --- /dev/null +++ b/.claude/commands/rmm-search.md @@ -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 [-c ] [--online] [--json] [-n N] +/rmm-search -c 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`. diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md index dd60fce..e54d1a2 100644 --- a/.claude/memory/MEMORY.md +++ b/.claude/memory/MEMORY.md @@ -12,6 +12,7 @@ - [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. - [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. - [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//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. - [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. +- [Use rmm-search to find machines](feedback_rmm_search_skill.md) — Find GuruRMM agents via the `rmm-search` skill (`rmm-search.sh [-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 ""`. - [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. diff --git a/.claude/memory/feedback_rmm_search_skill.md b/.claude/memory/feedback_rmm_search_skill.md new file mode 100644 index 0000000..80656ec --- /dev/null +++ b/.claude/memory/feedback_rmm_search_skill.md @@ -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 [-c ]`) — 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 ` 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`. diff --git a/.claude/memory/reference_cloudflare_access.md b/.claude/memory/reference_cloudflare_access.md new file mode 100644 index 0000000..2a7364d --- /dev/null +++ b/.claude/memory/reference_cloudflare_access.md @@ -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 " https://api.cloudflare.com/client/v4/zones//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). diff --git a/.claude/scripts/rmm-search.py b/.claude/scripts/rmm-search.py new file mode 100644 index 0000000..4f51f95 --- /dev/null +++ b/.claude/scripts/rmm-search.py @@ -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')}") diff --git a/.claude/scripts/rmm-search.sh b/.claude/scripts/rmm-search.sh new file mode 100644 index 0000000..ae9fd47 --- /dev/null +++ b/.claude/scripts/rmm-search.sh @@ -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 [-c|--client ] [--online] [--json] [-n N] +# rmm-search.sh -c # 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 , 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" diff --git a/.claude/skills/remediation-tool/references/tenants.md b/.claude/skills/remediation-tool/references/tenants.md index b265b8e..5110c35 100644 --- a/.claude/skills/remediation-tool/references/tenants.md +++ b/.claude/skills/remediation-tool/references/tenants.md @@ -23,6 +23,7 @@ that will fail the next email task; fix it with `assign-exchange-role.sh + 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 in RMM", "'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 [-c|--client ] [--online] [--json] [-n N] +bash .claude/scripts/rmm-search.sh -c # 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. diff --git a/clients/russo-law/session-logs/2026-06/2026-06-15-mike-russo-sharepoint-storage-eval.md b/clients/russo-law/session-logs/2026-06/2026-06-15-mike-russo-sharepoint-storage-eval.md new file mode 100644 index 0000000..636f31f --- /dev/null +++ b/clients/russo-law/session-logs/2026-06/2026-06-15-mike-russo-sharepoint-storage-eval.md @@ -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. diff --git a/clients/valleywide/session-logs/2026-06/2026-06-15-mike-vwp-files-single-home-scan-fix.md b/clients/valleywide/session-logs/2026-06/2026-06-15-mike-vwp-files-single-home-scan-fix.md new file mode 100644 index 0000000..54ef1d5 --- /dev/null +++ b/clients/valleywide/session-logs/2026-06/2026-06-15-mike-vwp-files-single-home-scan-fix.md @@ -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\` 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\` (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). diff --git a/wiki/clients/cryoweave.md b/wiki/clients/cryoweave.md index 01935d5..42addc6 100644 --- a/wiki/clients/cryoweave.md +++ b/wiki/clients/cryoweave.md @@ -62,8 +62,16 @@ CryoWeave manufactures custom cryogenic cable assemblies (millikelvin to 300K) f ### Email & Identity - **Domain:** cryoweave.com -- **Email:** Hosted externally [unverified — mail provider not documented] -- **Greg's email:** greg@cryoweave.com +- **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. +- **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 diff --git a/wiki/clients/russo-law.md b/wiki/clients/russo-law.md new file mode 100644 index 0000000..4bc2e14 --- /dev/null +++ b/wiki/clients/russo-law.md @@ -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. diff --git a/wiki/clients/valleywide.md b/wiki/clients/valleywide.md index 317cb5c..f7fcf1f 100644 --- a/wiki/clients/valleywide.md +++ b/wiki/clients/valleywide.md @@ -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. | | 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-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`. | | 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 - **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:** - - `172.16.9.0/24` — primary internal network (new servers, VWP-QBS, UDM, iLO, HYPERV1, VWP-FILES primary NIC); 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.]** + - `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 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.4.0/24` — OpenVPN client pool - **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-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 @@ -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 | 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-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`). | --- diff --git a/wiki/index.md b/wiki/index.md index 8d29f1c..aeaebde 100644 --- a/wiki/index.md +++ b/wiki/index.md @@ -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 | | [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 | +| [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