# Session Log: 2026-05-26

## User
- **User:** Howard Enos (howard)
- **Machine:** Howard-Home
- **Role:** tech

## Session Summary

This session covered three main areas: Cascades PSA billing, a Cascades connectivity investigation, and a full GuruScan module refactor.

The session opened with billing 0.5h onsite labor for Howard on Cascades ticket #32324 (Syncro #111060920) — a meeting with an access control vendor to discuss network requirements. Mike had already billed his 0.5h; Howard's charge was added separately bringing the total to 1.0h. Cascades is a prepaid customer (28.5h block), so the invoice correctly posted at $0.00 and the block decremented to 28.0h.

The Cascades connectivity work investigated why devices in room 343 (a Surface Laptop and IoT devices) were dropping connectivity. The AP serving that area (in room 347, mislabeled as "335") had been offline since the March 2026 audit with no uplink — likely still cabled to the old powered-off floor switch rather than the new Pro switch. Remote diagnosis via Tailscale, GuruRMM, and pfSense SSH was exhausted without live access to the UniFi controller; onsite instructions were provided instead. AP 341 client drops were assessed as likely overflow from the dead AP's coverage gap.

The bulk of the session was a GuruScan module refactor. The existing suite was five loose .ps1 files with significant code duplication — the main scan loop was copy-pasted verbatim for the `-AutoRemediate` pass, helper functions were duplicated across three files, and `scanners.json` (required by `Invoke-Remediation.ps1` and `Download-Scanners.ps1`) was not committed to the repo. The refactor converted the suite to a proper PowerShell module (`GuruScan.psm1` + `GuruScan.psd1`) with all shared helpers in one place, a private `Invoke-ScanPass` function eliminating the loop duplication, and `scanners.json` committed as the single source of truth for scanner definitions. All .ps1 files were reduced to thin launchers that import the module.

During the same pass: ESET was removed (no true silent/auto-EULA CLI support), ClamAV was briefly added then removed at user request, and the temp-user forced-reboot flow (`GuruRMM-Temp` account + autologon + WPF splash) was replaced with a scheduled task approach — when `reboot_required` is true, `Register-ScannerCleanupTask` writes `Invoke-ScannerCleanup.ps1` to disk and registers a SYSTEM logon task with a 30-minute delay. The task removes scanner installation files and unregisters itself after running. The session ended with the Phase 2 identity migration (`migrate-identity.sh`) completing successfully on HOWARD-HOME, adding Ollama/Python/platform fields to `identity.json`.

## Key Decisions

- **GuruScan: module vs. expanded scripts** — converted to psm1 module rather than expanding individual .ps1 files. Module approach gives one copy of all shared logic, eliminates drift between `Invoke-GuruScan.ps1` and `Invoke-Remediation.ps1` which previously had subtly different exit-code handling for ESET and a missing `WaitForExit(5000)` flush in the remediation version.
- **ESET removed** — ESET Online Scanner's `/silent` mode still prompts for EULA acceptance on first run; not reliable for unattended RMM dispatch. Removed rather than worked around.
- **ClamAV added then removed** — added with freshclam pre-scan update step, then removed at user request. The `installer_args` / `run_update_after_install` schema fields added to support it remain in scanners.json for future use.
- **Reboot cleanup via scheduled task, not temp user** — the `GuruRMM-Temp` autologon approach was fragile (required creating/hiding a local admin account, WPF splash, guaranteed reboot). Replaced with a SYSTEM logon task + 30-min delay: no user account created, no forced reboot, scanner files removed silently in background after next natural login.
- **`installer_args` added to scanner schema** — Emsisoft's NSIS installer needs `/S`; future scanners with different install patterns (e.g. freshclam with no args) can specify their own. Backward-compatible: null defaults to `["/S"]`.
- **Cascades remote diagnosis declared impossible** — exhausted Tailscale, GuruRMM REST (commands are WebSocket-only, no REST endpoint), pfSense SSH (timeout — relay mode blocks inbound). No path to UniFi controller without onsite access or a deployed GuruRMM agent on a machine inside the network.

## Problems Encountered

- **GuruScan `Expand-TokenizedArgs` used `-Args` parameter name** in `Invoke-Remediation.ps1` — PowerShell 5.1 reserved word, silently broken. Fixed to `-ArgList` in the module.
- **`Wait-ProcessWithTimeout` missing `WaitForExit(5000)` flush** in `Invoke-Remediation.ps1` — `ExitCode` property on fast-exit processes returns null without this call. Fixed in module.
- **`Get-ExitCodeThreats` ESET inconsistency** — original `Invoke-Remediation.ps1` treated any non-zero ESET exit as a threat; `Invoke-GuruScan.ps1` correctly treated only exits 1 and 2 as threats. Standardized on the correct behavior in module (moot since ESET was removed, but normalized for any future scanner additions).
- **Coord API message POST failed with `There was an error parsing the body`** — caused by special characters in the JSON body when passed via `-d` flag to curl. Fixed by using `--data-binary @-` with a heredoc.

## Configuration Changes

- **`C:\claudetools\.claude\identity.json`** — Phase 2 migration added: `python.command`, `ollama.endpoint`, `ollama.fallback`, `ollama.prose_model`, `platform`, `architecture`, `last_updated`
- **`projects/msp-tools/guru-scan/GuruScan.psm1`** — NEW: full module, 1500 lines, all exported and private functions
- **`projects/msp-tools/guru-scan/GuruScan.psd1`** — NEW: module manifest, PS 5.1, exports 4 cmdlets
- **`projects/msp-tools/guru-scan/scanners.json`** — NEW: 4 scanners (RKill, AdwCleaner, Emsisoft, HitmanPro); ESET removed
- **`projects/msp-tools/guru-scan/README.md`** — NEW: deploy layout, scanner chain, exit codes, autologon lifecycle, licensing
- **`projects/msp-tools/guru-scan/Invoke-GuruScan.ps1`** — rewritten as thin launcher (param block + module import + call)
- **`projects/msp-tools/guru-scan/Invoke-Remediation.ps1`** — rewritten as thin launcher
- **`projects/msp-tools/guru-scan/Get-ScanSummary.ps1`** — rewritten as thin launcher
- **`projects/msp-tools/guru-scan/Invoke-PostRebootCleanup.ps1`** — rewritten as thin launcher (WPF splash removed, delegates to module)

## Credentials & Secrets

None created or discovered this session.

## Infrastructure & Servers

- **Cascades UniFi controller** — not accessible remotely; no Tailscale route, no GuruRMM agent inside network
- **Cascades pfsense-2** — Tailscale IP 100.119.153.74, FreeBSD, relay mode, SSH inbound blocked
- **Coord API** — http://172.16.3.30:8001 (reachable, used for messaging)
- **Ollama HOWARD-HOME** — http://localhost:11434 (local); fallback http://100.101.122.4:11434

## Commands & Outputs

```powershell
# Phase 2 identity migration
bash .claude/scripts/migrate-identity.sh
# Output: python=py, ollama=localhost:11434, fallback=100.101.122.4:11434, prose_model=qwen3:14b, platform=windows, arch=amd64

# Cascades prepaid check (before billing)
GET https://computerguru.syncromsp.com/api/v1/customers/20149445
# prepay_hours: 28.5 → billed 0.5h → 28.0h after

# Syncro line item posted
POST /tickets/111060920/add_line_item
# product_id 26118 (Labor-Onsite-Business), quantity 0.5, taxable false
# Result: invoice $0.00 (prepaid deduction applied correctly)
```

## Pending / Incomplete Tasks

- **GuruScan signing** — confirm `.ps1`-vs-MSI approach with Mike, then wire `sign.ps1` on Pluto (172.16.3.36) into the GuruScan build. Azure Trusted Signing creds in vault: `services/azure-trusted-signing.sops.yaml`
- **Cascades AP room 347** — physical check needed: verify cable from AP (labeled "335", in room 347) was moved from powered-off old floor switch to the new USW-Pro-24-PoE at 192.168.3.134
- **Cascades wiki review** — Mike asked Howard to review the Cascades wiki article and flag anything wrong or missing based on onsite context
- **GuruScan README** — needs update to remove ESET and ClamAV references (both were written in, then removed from the scanner chain)

## Reference Information

- Cascades Syncro customer ID: 20149445
- Cascades ticket: #32324 (Syncro #111060920) — access control vendor meeting, 0.5h Howard + 0.5h Mike
- GuruScan commit: f844054 (module refactor pushed 2026-05-26 21:58)
- Phase 2 migration commit: f844054 (identity.json changes in same auto-sync)
- Coord message to Mike confirming Phase 2: ID 6ee65b3e
- GuruScan deploy path: `C:\GuruScan\` (base), `C:\GuruScan\downloads\` (EXEs), `C:\ScanLogs\` (per-scan logs)
- GuruScan scanner chain: RKill → AdwCleaner → Emsisoft (installer+update) → HitmanPro
