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

---

## Session Summary

The session focused on verifying and extending the GuruScan pipeline for the GuruRMM platform. The GURUSCAN_RESULT_JSON pipeline was confirmed end-to-end: the launcher script reads results.json after the scan, compresses it into a single-line JSON, and emits it as `GURUSCAN_RESULT_JSON:<json>` to stdout. The GuruRMM agent captures this in `command.stdout`. This had been implemented in a prior session and was verified working with scan 2c531967.

AdwCleaner integration was thoroughly tested and found to be incompatible with both GuruRMM dispatch contexts. Dispatching in `user_session` context failed with `ERROR_CANCELLED` — the WTS token from `WTSQueryUserToken` is a non-elevated standard user token, and AdwCleaner's manifest requests administrator; CreateProcess returns the error immediately without showing a UAC dialog. Dispatching in `system` context caused the process to hang indefinitely before the scan started — AdwCleaner initializes its GUI framework before accepting CLI args, and in Session 0 (SYSTEM, no window station) that initialization blocks forever. Both paths were tested directly against the VM. AdwCleaner was removed from `scanners.json` pending a future `schtasks InteractiveToken + HighestAvailable` dispatch mechanism.

A critical 3-hour pipe hang bug was discovered via a background task notification. A full GuruScan command dispatched at 05:51 UTC (scan `RMM-TEST-MACHIN-20260526-225146`) completed its scan work in 6.5 minutes — results.json was written at 05:58 — but the GuruRMM command stayed `running` for 3 hours until the server-side reaper killed it. Root cause: `NoNewWindow = [bool]$Headless` in `Invoke-ScanPass` caused all scanner processes to share the parent PowerShell's console when running headless. Sharing the console means child processes inherit the parent's stdout/stderr pipe handles. AdwCleaner started (or partially started) in Session 0, inherited the pipe handle, then hung. After PowerShell exited, AdwCleaner still held the write end of the stdout pipe open, so the GuruRMM agent's read side never saw EOF and waited indefinitely.

The fix was to replace `NoNewWindow = [bool]$Headless` with `WindowStyle = 'Hidden'` when `$Headless` is set. This gives each scanner its own window/console, preventing pipe handle inheritance entirely. Any scanner that hangs will be killed by `Wait-ProcessWithTimeout` at its configured timeout; the overall GuruScan process exits normally regardless. Verification scan `84059ee7` (dispatched post-fix) completed in 7.5 minutes with EICAR test file detected and removed by Emsisoft, `GURUSCAN_RESULT_JSON` captured in stdout, no pipe hang. Documentation was updated to reflect the 3-scanner chain and the corrected headless behavior description.

---

## Key Decisions

- **Removed AdwCleaner from scanners.json**: AdwCleaner needs elevated token AND interactive desktop simultaneously. `system` context provides elevation but no desktop (Session 0). `user_session` provides desktop but a non-elevated WTS token. Neither context satisfies both requirements. Will be re-added when a `schtasks` `InteractiveToken + HighestAvailable` dispatch path is implemented in GuruScan.psm1.

- **`WindowStyle = 'Hidden'` instead of `NoNewWindow`**: `NoNewWindow` shares the parent console and causes child processes to inherit the PowerShell pipe handles. `WindowStyle = 'Hidden'` creates an independent process with its own window/console — no handle inheritance. The only visible behavioral difference is that scanners no longer write their output to the RMM agent's pipe (which was never used anyway — GuruScan collects output via log files).

- **AdwCleaner re-add path is schtasks with `InteractiveToken`**: From SYSTEM context, create a task XML with `<LogonType>InteractiveToken</LogonType>` and `<RunLevel>HighestAvailable</RunLevel>`. This creates the process as the currently-logged-in user at their highest privilege level, in their desktop session. If the user is a local admin this gets an elevated token with a visible window — no UAC prompt because Task Scheduler handles the elevation internally.

- **Kept AdwCleaner exit-code mappings in GuruScan.psm1**: The `Get-ExitCodeThreats` and `Get-ExitCodeReboot` functions retain AdwCleaner cases. No harm in keeping them, and they'll be needed when AdwCleaner is re-added.

---

## Problems Encountered

- **AdwCleaner `user_session` dispatch: `ERROR_CANCELLED`**: PowerShell's `&` operator uses `CreateProcess`, which cannot handle elevation requests from a non-elevated token. Returns `ERROR_CANCELLED` (0x800704C7) immediately, no UAC dialog. Resolution: documented as architecture limitation; using `Start-Process -Verb RunAs` would allow the UAC prompt to appear on the user's desktop, but requires user interaction. Removed AdwCleaner for now.

- **AdwCleaner `system` context: process hung indefinitely**: Even with `WindowStyle = 'Hidden'` (tested directly), AdwCleaner enters its GUI initialization loop before processing CLI args. In Session 0 there is no window station; the initialization blocks forever. Confirmed by checking VM process list and scan logs — no `[S01].txt` created during today's system-context attempts, and the only existing log (`[S00].txt` from 2026-05-26) was from a prior non-SYSTEM run. Resolution: same as above.

- **3-hour pipe hang on GuruRMM command `0d05681f`**: Background monitor reported the command ran for 180 minutes before server-side reaper. Scan itself completed in 6.5 min (verified via results.json timestamps). Root cause: `NoNewWindow = [bool]$Headless` caused pipe handle inheritance; AdwCleaner (or a residual process from it) held the write end of the stdout pipe after PowerShell exited. Fix: `WindowStyle = 'Hidden'`. Verified with next scan (`84059ee7`), completed in 7.5 min with no hang.

- **Vault path resolution for JWT token**: First attempt used `projects/gururmm/api.sops.yaml` which doesn't exist. Correct path is `infrastructure/gururmm-server.sops.yaml`, field `credentials.gururmm-api.admin-password`. Used login endpoint `/api/auth/login` with `claude-api@azcomputerguru.com` to obtain JWT.

---

## Configuration Changes

- `projects/msp-tools/guru-scan/GuruScan.psm1` — 5 changes:
  - `NoNewWindow = [bool]$Headless` → `WindowStyle = 'Hidden'` when `$Headless` (pipe hang fix)
  - `Headless` param docstring corrected ("WindowStyle=Hidden", not "NoNewWindow")
  - Whitelist comment: removed AdwCleaner ("Emsisoft and HitmanPro only")
  - `$defenderExclusions`: removed `'C:\AdwCleaner'`
  - `Invoke-Remediation` example: `AdwCleaner,MSERT` → `Emsisoft,MSERT`
- `projects/msp-tools/guru-scan/scanners.json` — AdwCleaner entry removed entirely
- `projects/msp-tools/guru-scan/README.md` — full rewrite for 3-scanner chain; added GuruRMM integration section with `GURUSCAN_RESULT_JSON` structure; fixed Headless description; removed AdwCleaner from all tables; added note on AdwCleaner re-add path

---

## Credentials & Secrets

No new credentials created or discovered. GuruRMM API access used existing vault entry:
- Vault: `infrastructure/gururmm-server.sops.yaml` → `credentials.gururmm-api.admin-email` / `admin-password`
- Login endpoint: `POST http://172.16.3.30:3001/api/auth/login`

---

## Infrastructure & Servers

- **GuruRMM server**: `172.16.3.30:3001`
- **RMM-TEST-MACHINE**: agent ID `7d3456f5-d811-4eac-8629-d88e9d1c594a`, VM at `172.20.12.192`, online
- **HTTP deploy server**: `172.20.0.1:8888` (Python, serving `C:/claudetools/projects/msp-tools/guru-scan/`)

---

## Commands & Outputs

```powershell
# GuruRMM dispatch (system context, post-fix)
C:\GuruScan\Invoke-GuruScan.ps1 -Headless
# → completed in 7.5 min, GURUSCAN_RESULT_JSON captured, no pipe hang
# → EICAR test file C:\Users\User\Downloads\eicar.com_.txt detected by Emsisoft, removed
```

Verify fix deployed on VM:
```powershell
Get-Content 'C:\GuruScan\GuruScan.psm1' | Select-String 'WindowStyle|NoNewWindow'
# Output: WindowStyle = 'Hidden'  (no NoNewWindow line in scanner launch block)
```

Scan result from verification run (command `84059ee7`):
```json
{
  "scan_id": "RMM-TEST-MACHIN-20260527-015912",
  "total_threats": 1,
  "scanners": [
    { "name": "RKill",    "status": "completed", "exit_code": 1, "duration_min": 0.09 },
    { "name": "AdwCleaner","status": "SKIPPED (requires user session)" },
    { "name": "Emsisoft", "status": "completed", "exit_code": 1, "duration_min": 4.86 },
    { "name": "HitmanPro","status": "completed", "exit_code": 0, "duration_min": 2.25 }
  ]
}
```
(AdwCleaner was still in scanners.json at time of this scan; removed immediately after.)

---

## Pending / Incomplete Tasks

- **AdwCleaner re-add via schtasks `InteractiveToken`**: Implement in `GuruScan.psm1`. When `session0_compatible: false` and running as SYSTEM, instead of skipping, create a task XML with `<LogonType>InteractiveToken</LogonType>` + `<RunLevel>HighestAvailable</RunLevel>`, register + trigger, poll for log file as completion signal, unregister. No GuruRMM agent changes required.
- **GuruRMM dashboard UI**: Parse `GURUSCAN_RESULT_JSON` from `command.stdout` and display per-scanner results on the agent detail page. Separate GuruRMM feature.
- **GURUSCAN_RESULT_JSON when SYSTEM detection causes old version mismatch**: The 2026-05-26 22:51 scan showed AdwCleaner as `FAILED` (not `SKIPPED`), suggesting the VM had a module version without the `session0_compatible` check at that time. Monitor for recurrence; current deployed version is correct.

---

## Reference Information

- Commits this session:
  - `a980ef1` — fix: use WindowStyle=Hidden instead of NoNewWindow in headless scanner dispatch
  - `a655b52` — chore: remove AdwCleaner from scanner chain
  - `47517e9` — docs: update GuruScan README and module comments for current state
- GuruRMM API base: `http://172.16.3.30:3001/api`
- GuruRMM login endpoint: `POST /api/auth/login` (body: `email`, `password`)
- Test machine agent ID: `7d3456f5-d811-4eac-8629-d88e9d1c594a`
- Scan log dir: `C:\ScanLogs\` on VM
- EICAR test file on VM: `C:\Users\User\Downloads\eicar.com_.txt`
- AdwCleaner CLI reference: https://help.malwarebytes.com/hc/en-us/articles/31589247152027-Command-line-options-for-AdwCleaner
- `Wait-ProcessWithTimeout` in GuruScan.psm1:69 — timeout-kills processes exceeding `timeout_min`
- `Test-RunningAsSystem` in GuruScan.psm1:684 — uses `WindowsIdentity.IsSystem`
