sync: auto-sync from HOWARD-HOME at 2026-07-03 17:00:12
Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-07-03 17:00:12
This commit is contained in:
@@ -206,3 +206,5 @@
|
||||
- [Windows won't-boot / offline DISM repair playbook](windows-offline-dism-repair-gotchas.md) — Automatic Repair loop = boot-critical fault (disk/registry/wedged update), NOT shell/appx store corruption (that's a symptom); `FaultyPackageInProgress` + 100s of Install/Uninstall-Pending packages = wedged CU -> RevertPendingActions or clean install. Offline DISM rejects `wim:` source (0x800f082e) -> MOUNT the wim, source `\Windows`. Ventoy breaks WIM mount (0xc1420134) -> use Rufus. 25H2(26200)=24H2(26100)+enablement, so match 26100 media. First hit: Four Paws AvImark #32447.
|
||||
- [365 app suite — authoritative map + consent-drift fix](reference_365_app_suite.md) — full map in `.claude/skills/remediation-tool/references/app-suite.md`; per-tenant consent is NOT uniform (VWP had the app but no SharePoint role). Run `consent-audit.sh <tenant|--all>` to detect gaps; fix via adminconsent URL or direct appRoleAssignment grant.
|
||||
- [Remediation-tool has full M365 access (incl. SharePoint)](reference_remediation_tool_365_access.md) — the app suite covers Graph/EXO/Defender/SharePoint; don't declare "no access" on an accessDenied. SharePoint app-only needs a CERT (secret = "Unsupported app only token"); use get-token.sh `sharepoint`/`sharepoint-admin` tiers + CSOM admin API (Graph /admin/sharepoint/settings scope not held). Full map: skill references/app-permissions-and-sharepoint.md.
|
||||
- [AV migration: Bitdefender -> Datto EDR](project_av_migration_bitdefender_to_edr.md) — retire Bitdefender fleet-wide except Dataforth; end-state per machine = GuruRMM + Datto EDR
|
||||
- [RMM deploy via ScreenConnect](reference_rmm_deploy_via_screenconnect.md) — push GuruRMM agent to client workstations via SC send-command (SYSTEM), not DC remote-exec (DCOM/schtasks blocked on Win11 clients)
|
||||
|
||||
24
.claude/memory/project_av_migration_bitdefender_to_edr.md
Normal file
24
.claude/memory/project_av_migration_bitdefender_to_edr.md
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
name: project_av_migration_bitdefender_to_edr
|
||||
description: AV strategy — migrate all clients from Bitdefender to Datto EDR, except Glaztech and Dataforth
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
|
||||
Standing AV direction (set by Howard 2026-07-03): ACG is moving endpoint AV/security
|
||||
from **Bitdefender GravityZone -> Datto EDR** for **all clients EXCEPT Glaztech Industries
|
||||
and Dataforth Corp** (those two stay on Bitdefender / handled separately).
|
||||
|
||||
**Why:** consolidate on Datto EDR as the security plane; Bitdefender is being retired
|
||||
fleet-wide (Glaztech + Dataforth are the two exceptions — both have large established
|
||||
Bitdefender footprints: Glaztech ~242 endpoints, Dataforth managed separately).
|
||||
|
||||
**How to apply:** whenever setting up or reconciling a client's endpoints (e.g. the
|
||||
GPS->GuruRMM coverage audit), the target end-state per machine is: GuruRMM agent +
|
||||
Datto EDR agent, and Bitdefender **removed**. Do NOT deploy new Bitdefender coverage.
|
||||
Use existing Bitdefender inventory only as a discovery source for which machines exist
|
||||
(its company names carry the Syncro CID `_NNNNN`, handy for mapping). Deploy Datto EDR
|
||||
via `[[datto-edr]]` (create-group -> mint-key -> deploy-cmd, pushed through `/rmm`).
|
||||
|
||||
Related: GPS->RMM audit tracker `projects/gps-rmm-audit/tracker.md`. Exceptions = Glaztech +
|
||||
Dataforth (leave their existing AV alone; do not migrate them to EDR in this effort).
|
||||
30
.claude/memory/reference_rmm_deploy_via_screenconnect.md
Normal file
30
.claude/memory/reference_rmm_deploy_via_screenconnect.md
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: reference_rmm_deploy_via_screenconnect
|
||||
description: Best channel to mass-deploy the GuruRMM agent to client workstations = ScreenConnect send-command (not DC remote-exec)
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
|
||||
**To push the GuruRMM agent onto a client's existing machines, the reliable channel is
|
||||
ScreenConnect `send-command` (Backstage), NOT remote-exec from the domain controller.**
|
||||
|
||||
Discovered 2026-07-03 deploying to Instrumental Music Center (see
|
||||
`projects/gps-rmm-audit/tracker.md`). Remote-exec FROM the DC to Win10/11 workstations
|
||||
fails on default client settings:
|
||||
- WMI/`Win32_Process` over **DCOM** -> "RPC server unavailable" (DCOM firewalled on clients)
|
||||
- `schtasks /S` -> connects over SMB but Win11 **rejects the task definition** from an older
|
||||
(Server 2016) DC ("The request is not supported")
|
||||
- `New-PSDrive`/`sc.exe` admin-share from SYSTEM context -> access/parse failures
|
||||
- WinRM is off by default on workstations
|
||||
|
||||
**What works cleanly:** ScreenConnect. ACG endpoints already run the SC agent, and
|
||||
`send-command` runs on the guest **as SYSTEM** — no credentials, no firewall fight, no
|
||||
DA-password-in-logs concern. Pattern (via the `[[screenconnect]]` skill):
|
||||
1. `GetSessionsByName` with the EXACT hostname -> sessionID (no list-all method; must query by exact name).
|
||||
2. Build the site installer one-liner: `irm 'https://rmm.azcomputerguru.com/install/<SITE-CODE>/windows'|iex` (site code from the client's vault `gururmm-site-*.sops.yaml`).
|
||||
3. Encode it: `powershell -NoProfile -ExecutionPolicy Bypass -EncodedCommand <base64-UTF16LE>` (avoids all quoting; no /TR length limit like schtasks).
|
||||
4. `send-command --session <id> --command "<that>" --confirm`. Online guests install + enroll in ~1-3 min; offline guests QUEUE in SC and install on reconnect.
|
||||
5. Verify via GuruRMM `/api/agents` (hostname appears under the client, status online).
|
||||
|
||||
Note `iconv` is absent in this Git-Bash — compute the base64 with `py -c "import base64; ..."`.
|
||||
Related: `[[project_av_migration_bitdefender_to_edr]]` (same channel can push the Datto EDR agent + remove Bitdefender once RMM is on).
|
||||
63
.claude/scripts/gps-rmm-progress-check.sh
Normal file
63
.claude/scripts/gps-rmm-progress-check.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
# gps-rmm-progress-check.sh — daily GPS->GuruRMM enrollment progress check.
|
||||
#
|
||||
# Reads projects/gps-rmm-audit/targets.json (GPS device target per client),
|
||||
# pulls live GuruRMM /api/agents, computes per-client enrollment gaps, and DMs
|
||||
# Howard a one-message summary. When every tracked client has met its target it
|
||||
# reports "COMPLETE" so the scheduled task can be retired.
|
||||
#
|
||||
# Usage:
|
||||
# bash gps-rmm-progress-check.sh # check + DM Howard
|
||||
# bash gps-rmm-progress-check.sh --dry-run # check + print, no Discord
|
||||
#
|
||||
# Registered as a daily Windows scheduled task. Read-only against RMM.
|
||||
set -u
|
||||
ROOT="${CLAUDETOOLS_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
|
||||
TARGETS="$ROOT/projects/gps-rmm-audit/targets.json"
|
||||
DRY=0; [ "${1:-}" = "--dry-run" ] && DRY=1
|
||||
|
||||
[ -f "$TARGETS" ] || { echo "[ERROR] targets.json not found at $TARGETS" >&2; exit 1; }
|
||||
|
||||
# --- auth + fetch agents ---
|
||||
eval "$(bash "$ROOT/.claude/scripts/rmm-auth.sh" 2>/dev/null)" >/dev/null
|
||||
if [ -z "${TOKEN:-}" ] || [ -z "${RMM:-}" ]; then
|
||||
echo "[ERROR] RMM auth failed" >&2
|
||||
bash "$ROOT/.claude/scripts/log-skill-error.sh" "gps-rmm-progress-check" "RMM auth failed" >/dev/null 2>&1
|
||||
exit 1
|
||||
fi
|
||||
AGENTS=$(curl -s "$RMM/api/agents" -H "Authorization: Bearer $TOKEN" | tr -d '\000-\037')
|
||||
[ "${AGENTS:0:1}" = "[" ] || { echo "[ERROR] /api/agents not an array: ${AGENTS:0:100}" >&2; \
|
||||
bash "$ROOT/.claude/scripts/log-skill-error.sh" "gps-rmm-progress-check" "GET /api/agents non-array" >/dev/null 2>&1; exit 1; }
|
||||
|
||||
# --- per-client live agent counts (unique hostnames, to ignore dup agent rows) ---
|
||||
COUNTS=$(echo "$AGENTS" | jq -r '[.[] | {c:.client_name, h:(.hostname|ascii_downcase)}]
|
||||
| group_by(.c) | map({client:.[0].c, n:( [.[].h] | unique | length )}) | .[] | "\(.n)\t\(.client)"')
|
||||
|
||||
# --- compare targets vs live ---
|
||||
REPORT=""; DONE_ALL=1; TOTAL_TARGET=0; TOTAL_HAVE=0; GAP_CLIENTS=0
|
||||
while IFS=$'\t' read -r TGT NAME BUCKET; do
|
||||
[ -z "$NAME" ] && continue
|
||||
HAVE=$(echo "$COUNTS" | awk -F'\t' -v n="$NAME" '$2==n{print $1; found=1} END{if(!found)print 0}' | head -1)
|
||||
HAVE=${HAVE:-0}
|
||||
TOTAL_TARGET=$((TOTAL_TARGET + TGT))
|
||||
TOTAL_HAVE=$((TOTAL_HAVE + HAVE))
|
||||
if [ "$HAVE" -lt "$TGT" ]; then
|
||||
DONE_ALL=0; GAP_CLIENTS=$((GAP_CLIENTS+1))
|
||||
GAP=$((TGT - HAVE))
|
||||
STATE=$([ "$HAVE" -eq 0 ] && echo "NO ORG/AGENTS" || echo "short")
|
||||
REPORT="${REPORT} - ${NAME}: ${HAVE}/${TGT} in RMM (${STATE}, gap ${GAP}) [${BUCKET}]\n"
|
||||
fi
|
||||
done < <(jq -r '.clients[] | "\(.target)\t\(.client)\t\(.bucket)"' "$TARGETS")
|
||||
|
||||
DATE=$(date +%Y-%m-%d)
|
||||
if [ "$DONE_ALL" -eq 1 ]; then
|
||||
MSG="**GPS->RMM enrollment: COMPLETE (${DATE})** All tracked GPS clients meet their RMM device target (${TOTAL_HAVE}/${TOTAL_TARGET}). You can retire the daily check task (schtasks /Delete /TN GPS-RMM-Progress)."
|
||||
else
|
||||
MSG="**GPS->RMM enrollment check ${DATE}** — ${TOTAL_HAVE}/${TOTAL_TARGET} devices in RMM; ${GAP_CLIENTS} clients still short:\n${REPORT}(Glaz-Tech excluded pending billing review. Source: projects/gps-rmm-audit/targets.json)"
|
||||
fi
|
||||
|
||||
if [ "$DRY" -eq 1 ]; then
|
||||
echo -e "$MSG"
|
||||
exit 0
|
||||
fi
|
||||
echo -e "$MSG" | bash "$ROOT/.claude/scripts/discord-dm.sh" howard
|
||||
Reference in New Issue
Block a user