From 324c3b94a4cb1db9e8d05faaa7bb6899da1a8a06 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Fri, 29 May 2026 08:40:54 -0700 Subject: [PATCH] feat(birth-biologic): KSTEEN SmartBadge daily watch + remediation scripts Corrected the 2026-05-28 SmartBadge fix on KSTEENBB2025: the older Datto Workplace Desktop v8 had been left in place (diverged from the fleet, which runs Datto Workplace v10.53.4 / Workplace2). Removed v8, installed v10, aligned the SmartBadge _CC add-in + CLSID to the EVO-X1 reference, and cleared Kristin's stuck per-user LoadBehavior=2. - ksteen-smartbadge-verify.ps1: PASS/FAIL verdict vs fleet reference - ksteen-smartbadge-fix.ps1: machine + per-user remediation - check-ksteen-smartbadge.sh: daily runner (RMM -> verdict -> #bot-alerts, coord message to Mike on drift); driven by a 7-day scheduled task on GURU-5070 - wiki: agents table, dual-Workplace SmartBadge known issue + fleet standard, 2026-05-28/29 history Syncro #32339. Coord todo 4a5b09b3 (watch expires 2026-06-05). Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/scripts/check-ksteen-smartbadge.sh | 62 +++++++++++++++++++ .claude/scripts/ksteen-smartbadge-fix.ps1 | 65 ++++++++++++++++++++ .claude/scripts/ksteen-smartbadge-verify.ps1 | 44 +++++++++++++ wiki/clients/birth-biologic.md | 9 ++- 4 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 .claude/scripts/check-ksteen-smartbadge.sh create mode 100644 .claude/scripts/ksteen-smartbadge-fix.ps1 create mode 100644 .claude/scripts/ksteen-smartbadge-verify.ps1 diff --git a/.claude/scripts/check-ksteen-smartbadge.sh b/.claude/scripts/check-ksteen-smartbadge.sh new file mode 100644 index 0000000..2976477 --- /dev/null +++ b/.claude/scripts/check-ksteen-smartbadge.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# Daily verification that KSTEENBB2025 (Birth Biologic) Datto SmartBadge config +# still matches the EVO-X1 fleet reference. Posts a #bot-alerts heartbeat each run; +# on drift also sends a coord message to Mike. Intended to run once/day for ~1 week +# via the "ClaudeTools - KSTEEN SmartBadge Daily" scheduled task on GURU-5070. +set -uo pipefail + +REPO_ROOT="${CLAUDETOOLS_ROOT:-/d/claudetools}" +[ -d "$REPO_ROOT" ] || REPO_ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel 2>/dev/null)" +VAULT="$REPO_ROOT/.claude/scripts/vault.sh" +RMM="http://172.16.3.30:3001" +COORD="http://172.16.3.30:8001/api/coord" +KSTEEN="ee3c6aea-e9cc-4d2f-9e79-a38dd0eb129e" +VERIFY_PS="$REPO_ROOT/.claude/scripts/ksteen-smartbadge-verify.ps1" +LOG="$REPO_ROOT/.claude/logs/ksteen-smartbadge.log" +mkdir -p "$(dirname "$LOG")" +ts() { date '+%Y-%m-%d %H:%M:%S %Z'; } + +alert() { bash "$REPO_ROOT/.claude/scripts/post-bot-alert.sh" "$1" >/dev/null 2>&1; } +fail_exit() { echo "$(ts) [ERROR] $1" >> "$LOG"; alert "[SMARTBADGE-WATCH] ERROR on KSTEENBB2025 check: $1"; exit 1; } + +EMAIL=$(bash "$VAULT" get-field infrastructure/gururmm-server.sops.yaml credentials.gururmm-api.admin-email 2>/dev/null) +PASS=$(bash "$VAULT" get-field infrastructure/gururmm-server.sops.yaml credentials.gururmm-api.admin-password 2>/dev/null) +[ -z "$EMAIL" ] && fail_exit "could not read RMM creds from vault" + +TOKEN=$(curl -s -X POST "$RMM/api/auth/login" -H "Content-Type: application/json" \ + --data-binary "{\"email\":\"$EMAIL\",\"password\":\"$PASS\"}" | jq -r '.token // empty') +[ -z "$TOKEN" ] && fail_exit "RMM login failed" + +# Is the agent connected? If offline, note and exit cleanly (will catch it tomorrow). +ONLINE=$(curl -s "$RMM/api/agents" -H "Authorization: Bearer $TOKEN" | jq -r --arg id "$KSTEEN" '.[] | select(.id==$id) | .status') +if [ "$ONLINE" != "online" ]; then + echo "$(ts) [SKIP] agent offline ($ONLINE)" >> "$LOG" + alert "[SMARTBADGE-WATCH] KSTEENBB2025 offline - SmartBadge check skipped, will retry next run" + exit 0 +fi + +PAYLOAD=$(jq -n --rawfile cmd "$VERIFY_PS" '{command_type:"powershell", command:$cmd, timeout_seconds:60}') +CID=$(curl -s -X POST "$RMM/api/agents/$KSTEEN/command" -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" -d "$PAYLOAD" | jq -r '.command_id // empty') +[ -z "$CID" ] && fail_exit "command dispatch failed" + +for i in $(seq 1 20); do + ST=$(curl -s "$RMM/api/commands/$CID" -H "Authorization: Bearer $TOKEN" | jq -r '.status') + case "$ST" in completed|failed|cancelled|interrupted) break;; esac + sleep 4 +done +OUT=$(curl -s "$RMM/api/commands/$CID" -H "Authorization: Bearer $TOKEN" | jq -r '.stdout') +RESULT=$(printf '%s' "$OUT" | grep -m1 'RESULT:') + +if printf '%s' "$RESULT" | grep -q 'RESULT: PASS'; then + echo "$(ts) PASS" >> "$LOG" + alert "[SMARTBADGE-WATCH] KSTEENBB2025 PASS - Datto Workplace v10 + SmartBadge _CC add-in aligned" +else + REASON=$(printf '%s' "$RESULT" | sed 's/^RESULT: //') + [ -z "$REASON" ] && REASON="no RESULT line returned: ${OUT:0:200}" + echo "$(ts) FAIL | $REASON" >> "$LOG" + alert "[SMARTBADGE-WATCH] *** DRIFT *** KSTEENBB2025 FAIL | $REASON" + curl -s -X POST "$COORD/messages" -H "Content-Type: application/json" --data-binary @- </dev/null 2>&1 +{"from_session":"GURU-5070/smartbadge-watch","to_user":"mike","subject":"KSTEENBB2025 SmartBadge drift detected","body":"Daily watch found drift on Kristin Steen's machine: $REASON. Re-run the SmartBadge remediation (.claude/scripts ksteen-smartbadge-verify.ps1 + datto-fix.ps1).","priority":"high"} +JSON +fi diff --git a/.claude/scripts/ksteen-smartbadge-fix.ps1 b/.claude/scripts/ksteen-smartbadge-fix.ps1 new file mode 100644 index 0000000..e7053bc --- /dev/null +++ b/.claude/scripts/ksteen-smartbadge-fix.ps1 @@ -0,0 +1,65 @@ +$ErrorActionPreference = 'SilentlyContinue' +$SID = 'S-1-12-1-4150293861-1139320743-1956584882-216650436' # kristinsteen +$wp2x64 = 'C:\Program Files\Datto\Workplace2\SmartBadge\DattoSmartBadgeShim_x64.dll' +$wp2x86 = 'C:\Program Files\Datto\Workplace2\SmartBadge\DattoSmartBadgeShim_x86.dll' + +# --- Guard: Excel must be closed (it rewrites per-user add-in state on exit) --- +$xl = Get-Process EXCEL -ErrorAction SilentlyContinue +if ($xl) { Write-Output "[ABORT] EXCEL.EXE is running (pid $($xl.Id)). Close Excel before running the per-user fix."; exit 2 } + +Write-Output "=== MACHINE-WIDE: remove v8 leftovers (match EVO-X1) ===" +# Drop the Workplace Desktop CLSID {2B96EDC1} (x64 + WOW64) +foreach ($k in @( + 'HKLM:\Software\Classes\CLSID\{2B96EDC1-FDF3-47E1-B177-F205E7B98DF4}', + 'HKLM:\Software\WOW6432Node\Classes\CLSID\{2B96EDC1-FDF3-47E1-B177-F205E7B98DF4}')) { + if (Test-Path $k) { Remove-Item $k -Recurse -Force; Write-Output " removed $k" } else { Write-Output " absent $k" } +} +# Drop the non-_CC Datto.SmartBadgeShim add-in keys (EVO-X1 only has _CC) +foreach ($k in @( + 'HKLM:\Software\Microsoft\Office\Excel\Addins\Datto.SmartBadgeShim', + 'HKLM:\Software\WOW6432Node\Microsoft\Office\Excel\Addins\Datto.SmartBadgeShim', + 'HKLM:\Software\Microsoft\Office\Word\Addins\Datto.SmartBadgeShim', + 'HKLM:\Software\Microsoft\Office\PowerPoint\Addins\Datto.SmartBadgeShim')) { + if (Test-Path $k) { Remove-Item $k -Recurse -Force; Write-Output " removed $k" } else { Write-Output " absent $k" } +} + +Write-Output "" +Write-Output "=== MACHINE-WIDE: verify _CC CLSID -> Workplace2 DLLs ===" +$cc = '{3C639243-95A2-400D-B4B4-4384DA7F61D3}' +foreach ($pair in @(@("HKLM:\Software\Classes\CLSID\$cc\InprocServer32",$wp2x64), @("HKLM:\Software\WOW6432Node\Classes\CLSID\$cc\InprocServer32",$wp2x86))) { + $path = $pair[0]; $want = $pair[1] + $cur = (Get-Item $path -ErrorAction SilentlyContinue) + $val = if ($cur) { $cur.GetValue('') } else { $null } + if ($val -ne $want) { + if (-not (Test-Path $path)) { New-Item $path -Force | Out-Null } + Set-ItemProperty $path -Name '(default)' -Value $want + Set-ItemProperty $path -Name 'ThreadingModel' -Value 'Apartment' + Write-Output " set $path -> $want" + } else { Write-Output " ok $path -> $val" } +} + +Write-Output "" +Write-Output "=== PER-USER ($SID): clear stuck disabled state ===" +$xlAddins = "Registry::HKEY_USERS\$SID\Software\Microsoft\Office\Excel\Addins" +# Remove non-_CC leftover in user hive (match EVO-X1 = no per-user Datto entries) +if (Test-Path "$xlAddins\Datto.SmartBadgeShim") { Remove-Item "$xlAddins\Datto.SmartBadgeShim" -Recurse -Force; Write-Output " removed HKCU Datto.SmartBadgeShim" } +# Reset _CC per-user override to 3 (Excel had set it to 2 = disabled) +if (Test-Path "$xlAddins\Datto.SmartBadgeShim_CC") { + Set-ItemProperty "$xlAddins\Datto.SmartBadgeShim_CC" -Name 'LoadBehavior' -Value 3 -Type DWord + Write-Output " set HKCU Datto.SmartBadgeShim_CC LoadBehavior=3" +} +# Clear Excel Resiliency DisabledItems + crash records +$res = "Registry::HKEY_USERS\$SID\Software\Microsoft\Office\16.0\Excel\Resiliency" +foreach ($sub in @('DisabledItems','CrashingAddinList','DocumentRecovery')) { + if (Test-Path "$res\$sub") { + $i = Get-Item "$res\$sub" + $i.GetValueNames() | ForEach-Object { Remove-ItemProperty "$res\$sub" -Name $_ -Force } + Write-Output " cleared values under Resiliency\$sub" + } +} +# Keep add-in protected from auto-disable +$dnd = "$res\DoNotDisableAddinList" +if (-not (Test-Path $dnd)) { New-Item $dnd -Force | Out-Null } +Set-ItemProperty $dnd -Name 'Datto.SmartBadgeShim_CC' -Value 1 -Type DWord +Write-Output " ensured DoNotDisableAddinList Datto.SmartBadgeShim_CC=1" +Write-Output "=== FIX COMPLETE ===" diff --git a/.claude/scripts/ksteen-smartbadge-verify.ps1 b/.claude/scripts/ksteen-smartbadge-verify.ps1 new file mode 100644 index 0000000..856b94b --- /dev/null +++ b/.claude/scripts/ksteen-smartbadge-verify.ps1 @@ -0,0 +1,44 @@ +# Verdict check: KSTEENBB2025 Datto SmartBadge alignment vs EVO-X1 fleet reference. +# Emits a single line: "RESULT: PASS" or "RESULT: FAIL | reason1; reason2; ..." +$ErrorActionPreference = 'SilentlyContinue' +$fail = @() +$SID = 'S-1-12-1-4150293861-1139320743-1956584882-216650436' # kristinsteen +$cc = '{3C639243-95A2-400D-B4B4-4384DA7F61D3}' # _CC (Workplace2) +$desk = '{2B96EDC1-FDF3-47E1-B177-F205E7B98DF4}' # Workplace Desktop (must be absent) +$wp2x64 = 'C:\Program Files\Datto\Workplace2\SmartBadge\DattoSmartBadgeShim_x64.dll' +$wp2x86 = 'C:\Program Files\Datto\Workplace2\SmartBadge\DattoSmartBadgeShim_x86.dll' + +# 1. Product: Datto Workplace v10.x present, Workplace Desktop absent +$prods = Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' -ErrorAction SilentlyContinue +if (-not ($prods | Where-Object { $_.DisplayName -eq 'Datto Workplace' -and $_.DisplayVersion -like '10.*' })) { $fail += 'Datto Workplace v10 not installed' } +if ($prods | Where-Object { $_.DisplayName -like '*Workplace Desktop*' }) { $fail += 'Workplace Desktop (v8) is back' } + +# 2. DLLs present +if (-not (Test-Path $wp2x64)) { $fail += 'Workplace2 x64 SmartBadge DLL missing' } +if (-not (Test-Path $wp2x86)) { $fail += 'Workplace2 x86 SmartBadge DLL missing' } + +# 3. HKLM _CC add-in LoadBehavior=3 (HKLM + WOW64), and non-_CC absent +foreach ($base in @('HKLM:\Software\Microsoft\Office\Excel\Addins','HKLM:\Software\WOW6432Node\Microsoft\Office\Excel\Addins')) { + $lb = (Get-ItemProperty "$base\Datto.SmartBadgeShim_CC" -ErrorAction SilentlyContinue).LoadBehavior + if ($lb -ne 3) { $fail += "HKLM _CC add-in LoadBehavior=$lb (want 3) at $base" } + if (Test-Path "$base\Datto.SmartBadgeShim") { $fail += "stale non-_CC add-in present at $base" } +} + +# 4. _CC CLSID -> Workplace2 DLLs; Desktop CLSID absent +$x64 = (Get-Item "HKLM:\Software\Classes\CLSID\$cc\InprocServer32" -ErrorAction SilentlyContinue) +if (-not $x64 -or $x64.GetValue('') -ne $wp2x64) { $fail += '_CC x64 CLSID not pointing to Workplace2 x64 DLL' } +$x86 = (Get-Item "HKLM:\Software\WOW6432Node\Classes\CLSID\$cc\InprocServer32" -ErrorAction SilentlyContinue) +if (-not $x86 -or $x86.GetValue('') -ne $wp2x86) { $fail += '_CC WOW64 CLSID not pointing to Workplace2 x86 DLL' } +if (Test-Path "HKLM:\Software\Classes\CLSID\$desk") { $fail += 'Workplace Desktop CLSID {2B96EDC1} reappeared' } + +# 5. Per-user _CC not disabled (LoadBehavior must not be 2; if key absent, HKLM governs = OK) +$ua = "Registry::HKEY_USERS\$SID\Software\Microsoft\Office\Excel\Addins\Datto.SmartBadgeShim_CC" +if (Test-Path $ua) { + $ulb = (Get-ItemProperty $ua -ErrorAction SilentlyContinue).LoadBehavior + if ($ulb -eq 2 -or $ulb -eq 0) { $fail += "per-user _CC LoadBehavior=$ulb (Excel disabled it)" } +} +# 6. Disabled-items check +$res = "Registry::HKEY_USERS\$SID\Software\Microsoft\Office\16.0\Excel\Resiliency\DisabledItems" +if (Test-Path $res) { if ((Get-Item $res).ValueCount -gt 0) { $fail += 'Excel Resiliency DisabledItems has entries' } } + +if ($fail.Count -eq 0) { Write-Output 'RESULT: PASS' } else { Write-Output ("RESULT: FAIL | " + ($fail -join '; ')) } diff --git a/wiki/clients/birth-biologic.md b/wiki/clients/birth-biologic.md index 3b6757d..b0d6a6b 100644 --- a/wiki/clients/birth-biologic.md +++ b/wiki/clients/birth-biologic.md @@ -85,7 +85,10 @@ Site IDs are hardcoded in `$SITE_MAP` hashtable in the migration script. | Agent | Host | OS | Agent ID | Notes | |---|---|---|---|---| -| BB-SERVER | BB-SERVER | Windows Server 2016 | [unverified — not captured in session log] | Installed 2026-04-21; used as command channel throughout Datto→SP migration | +| BB-SERVER | BB-SERVER | Windows Server 2016 | `6c02baa7-0f1c-4990-b466-c9ab9eaefd3b` | Installed 2026-04-21; used as command channel throughout Datto→SP migration; runs Datto Workplace **Server** | +| KSTEENBB2025 | KSTEENBB2025 | Windows 11 | `ee3c6aea-e9cc-4d2f-9e79-a38dd0eb129e` | Kristin Steen's workstation | +| EVO-X1 | EVO-X1 | Windows 11 | `9595f002-5cfe-4db6-b7aa-1df4a20e9f9b` | Vicki Fountain's workstation; used as SmartBadge fleet reference | +| BB-Office2 | BB-Office2 | Windows 11 | `48763401-4859-49f9-b64a-7a50d0148b23` | Shared/office workstation | ## Access @@ -99,6 +102,8 @@ Site IDs are hardcoded in `$SITE_MAP` hashtable in the migration script. ## Patterns & Known Issues +- **Datto Workplace fleet standard = "Datto Workplace" v10.53.4 (installs to `C:\Program Files\Datto\Workplace2\`).** EVO-X1 and BB-Office2 run this version only. **Never** run the older "Datto Workplace **Desktop**" v8.50.13 (folder `…\Workplace Desktop\`) alongside it — having both installed breaks the Excel SmartBadge add-in (see below). Note the confusing naming: despite "Desktop" sounding newer, v8 Desktop is the *older* product; plain "Datto Workplace" v10 is current. +- **SmartBadge Excel add-in failure from dual Datto Workplace installs:** When both Workplace2 (v10) and Workplace Desktop (v8) are present, the `_CC` COM class `{3C639243-95A2-400D-B4B4-4384DA7F61D3}` gets a 64-bit InprocServer32 pointing at the wrong DLL (or only a 32-bit WOW64 entry), so 64-bit Excel can't load the shim and silently drops the SmartBadge ribbon tab. Excel then auto-disables the add-in (per-user `LoadBehavior=2`). **Fix = align to fleet:** remove Workplace Desktop v8 (Revo for a full leftover sweep), install Workplace v10.53.4, ensure only the `_CC` add-in (HKLM+WOW64, `LoadBehavior=3`) with the `_CC` CLSID → `…\Workplace2\SmartBadge\DattoSmartBadgeShim_x64/x86.dll`, and reset the user's `LoadBehavior` to 3 + clear Excel Resiliency. Reference machine: EVO-X1. Scripts: `.claude/scripts/ksteen-smartbadge-verify.ps1`, `.claude/scripts/ksteen-smartbadge-fix.ps1`. - **Windows Server 2016 TLS:** BB-SERVER defaults to TLS 1.0. PowerShell scripts must include `[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12` at the top or Graph API calls will fail. - **GuruRMM command timeout on long-running processes:** The RMM command channel times out on operations running longer than ~300 seconds. An 8 MB PDF upload at ~77 KB/s exceeded this limit during the migration. Workaround: base64-encode file on server, capture stdout, decode and upload locally. - **SharePoint 409 Conflict on retry:** If a chunked upload session is interrupted, a partial item remains in SharePoint. Subsequent upload sessions against the same path return 409 Conflict. Fix: DELETE the item before creating a new upload session. @@ -123,6 +128,8 @@ Site IDs are hardcoded in `$SITE_MAP` hashtable in the migration script. | Date | Event | |---|---| +| 2026-05-29 | Mike: Corrected the SmartBadge fix — Kristin's machine had been left on the *older* Workplace Desktop v8 (diverged from fleet). Revo-removed v8, installed Workplace v10.53.4 (Workplace2), aligned SmartBadge `_CC` add-in/CLSID to EVO-X1, cleared her stuck per-user `LoadBehavior=2`. Verified working. Public tech notes + 1hr warranty on Syncro #32339. Stood up a 7-day daily verification (scheduled task on GURU-5070 + coord todo `4a5b09b3`, expires 2026-06-05). | +| 2026-05-28 | Mike: Initial Kristin Steen SmartBadge remediation (Syncro #32339) — diagnosed dual Workplace2/Workplace Desktop install; **uninstalled the wrong one (Workplace2 v10)**, leaving v8 Desktop (corrected 2026-05-29). | | 2026-04-21 | Mike: New client onboarded to GuruRMM (client + site created, vault entry saved). Tenant Admin app consented. sysadmin@birthbiologic.com assigned M365 Business Premium. GuruRMM agent installed on BB-SERVER. Custom Datto→SharePoint migration script built. Supply Management (160 files) migrated via script. SPMT launched for 4 remaining folders. Syncro ticket #109277420 opened. | ## Backlinks