docs: update GuruScan README and module comments for current state

- README: remove AdwCleaner from scanner chain and exit code/licensing
  tables; add AdwCleaner note explaining why it is temporarily excluded;
  fix Headless description (WindowStyle=Hidden, not NoNewWindow); add
  GuruRMM integration section with example JSON output structure
- GuruScan.psm1: fix Headless param docstring; update whitelist comment
  (Emsisoft + HitmanPro only); remove C:\AdwCleaner from Defender
  exclusion list; fix Invoke-Remediation example (-Scanners Emsisoft,MSERT)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 06:55:38 -07:00
parent d5614ce558
commit 47517e93bf
2 changed files with 72 additions and 34 deletions

View File

@@ -377,7 +377,8 @@ function Invoke-ScanPass {
.PARAMETER TimeoutMinOverride
If > 0, overrides the per-scanner timeout_min for all scanners.
.PARAMETER Headless
When set, suppress scanner UI windows (NoNewWindow).
When set, launches scanner processes with WindowStyle=Hidden so no UI
windows appear. Use when dispatching from an RMM agent with no desktop.
.OUTPUTS
[System.Collections.Generic.List[pscustomobject]] of result objects.
#>
@@ -771,7 +772,7 @@ function Invoke-GuruScan {
)
# Whitelist -- written to C:\GuruScan\whitelist.txt before any scanner runs.
# Emsisoft and HitmanPro honour this; RKill and AdwCleaner do not.
# Emsisoft (/wl=) and HitmanPro (/excludelist=) honour this; RKill does not.
$whitelist = @('C:\GuruScan')
# ForceRemove blacklist -- items removed after all scanners complete.
@@ -849,7 +850,7 @@ function Invoke-GuruScan {
# Add Windows Defender exclusions for scanner paths so Defender does not
# quarantine scanner EXEs or log files mid-run.
$defenderExclusions = @($script:Base, $script:LogRoot, 'C:\EmsisoftCmd', 'C:\AdwCleaner')
$defenderExclusions = @($script:Base, $script:LogRoot, 'C:\EmsisoftCmd')
try {
Add-MpPreference -ExclusionPath $defenderExclusions -ErrorAction SilentlyContinue
Write-Host "[INFO] Windows Defender exclusions added for scanner paths" -ForegroundColor Cyan
@@ -1014,7 +1015,7 @@ function Invoke-Remediation {
successfully are re-run.
.EXAMPLE
Invoke-Remediation -LogRoot "C:\ScanLogs\DESKTOP-20260523-143000"
Invoke-Remediation -LogRoot "C:\ScanLogs\DESKTOP-20260523-143000" -Scanners AdwCleaner,MSERT
Invoke-Remediation -LogRoot "C:\ScanLogs\DESKTOP-20260523-143000" -Scanners Emsisoft,MSERT
#>
[CmdletBinding()]
param(

View File

@@ -17,7 +17,7 @@ for downstream processing by the RMM agent.
The module files (`GuruScan.psm1`, `GuruScan.psd1`, `scanners.json`) live in the
same directory as the launcher scripts (`Invoke-GuruScan.ps1`, etc.). This is
typically `C:\GuruScan\` or the RMM deployment path — wherever the scripts are placed.
typically `C:\GuruScan\` or the RMM deployment path.
---
@@ -28,12 +28,16 @@ Scanners run in this order. Each stage hands off to the next regardless of findi
| # | Scanner | Category | Notes |
|---|---------|----------|-------|
| 1 | **RKill** | process-killer | Kills malware-related processes before scanners run. Exit 1 = processes were killed (not a threat indicator). |
| 2 | **AdwCleaner** | adware | Removes adware, PUPs, and browser hijackers. **Requires an interactive user session** (GUI app; no headless/SYSTEM mode). Skipped automatically when running as SYSTEM with no desktop. To include AdwCleaner, dispatch via GuruRMM with `context: user_session`. |
| 3 | **Emsisoft Command Line Scanner** | antimalware | Two-step: NSIS installer extracts to `C:\EmsisoftCmd\`, then `/update` fetches latest definitions, then scans. |
| 4 | **HitmanPro** | antimalware | Cloud-assisted second-opinion scanner. Trial registry is reset before each run via `Invoke-HitmanProTrialReset`. |
| 2 | **Emsisoft Command Line Scanner** | antimalware | Two-step: NSIS installer extracts to `C:\EmsisoftCmd\`, then `/update` fetches latest definitions, then deep-scans `C:\`. |
| 3 | **HitmanPro** | antimalware | Cloud-assisted second-opinion scanner. Trial registry is reset before each run via `Invoke-HitmanProTrialReset`. Runs with `/quiet` (no GUI). |
MSERT (Microsoft Safety Scanner) is excluded from the default chain — it is too slow
for routine remediation runs. Add it back to `scanners.json` if needed.
**AdwCleaner** is not currently in the chain. It requires both elevated privileges
and an interactive desktop session simultaneously — SYSTEM context is elevated but
Session 0 (no desktop), user_session has a desktop but a non-elevated WTS token.
It will be re-added once a scheduled-task `InteractiveToken` dispatch is implemented.
MSERT (Microsoft Safety Scanner) is also excluded from the default chain — too slow
for routine runs. Add it to `scanners.json` if needed.
---
@@ -42,29 +46,29 @@ for routine remediation runs. Add it back to `scanners.json` if needed.
| Scanner | Exit 0 | Exit 1 | Exit 2 | Exit 3 | Other |
|---------|--------|--------|--------|--------|-------|
| RKill | Clean run | Processes killed (not a threat) | — | — | — |
| AdwCleaner | Clean | Cleaned, no reboot needed | Cleaned, reboot required | Found but not cleaned (scan-only) | — |
| Emsisoft | Clean | Threats found/cleaned | Cleaned, reboot required | — | — |
| HitmanPro | Clean | Cleaned | Cleaned, reboot required | — | — |
| MSERT | Clean | Threats found/cleaned | — | — | Non-zero = threats |
| TDSSKiller | Clean | Threats found | — | — | — |
| Stinger | Clean | — | — | — | 13 = threats |
Reboot-required exit codes: AdwCleaner 2, HitmanPro 2, Emsisoft 2.
Reboot-required exit codes: HitmanPro 2, Emsisoft 2.
---
## Post-Scan Cleanup Lifecycle
When any scanner exits with a reboot-required code (exit 2), the following sequence runs automatically — no forced reboot, no temp user account:
When any scanner exits with a reboot-required code (exit 2), the following sequence
runs automatically — no forced reboot:
1. `Register-ScannerCleanupTask` writes `cleanup-state.json` (scan ID + log path) to `C:\GuruScan\`.
2. `Invoke-ScannerCleanup.ps1` is written to `C:\GuruScan\`.
3. A SYSTEM scheduled task (`GuruRMM-ScannerCleanup`) is registered with an **at-logon + 30-minute delay** trigger.
4. The scan completes and prints a message to reboot at your convenience.
5. After the next natural reboot and user login, the task fires 30 minutes later (silently, in the background as SYSTEM).
6. The cleanup script removes all scanner installation paths (`C:\EmsisoftCmd`, `C:\AdwCleaner`, `C:\ProgramData\HitmanPro*`, `C:\GuruScan\downloads\`), writes `logs-ready.json` for GuruRMM to pick up, and unregisters itself.
5. After the next natural reboot and user login, the task fires 30 minutes later (silently, as SYSTEM).
6. The cleanup script removes all scanner installation paths (`C:\EmsisoftCmd`, `C:\ProgramData\HitmanPro*`, `C:\GuruScan\downloads\`), writes `logs-ready.json` for GuruRMM to pick up, and unregisters itself.
To run cleanup immediately without waiting (e.g. if the task was missed):
To run cleanup immediately without waiting:
```powershell
.\Invoke-PostRebootCleanup.ps1
```
@@ -73,13 +77,47 @@ To run cleanup immediately without waiting (e.g. if the task was missed):
## Headless / SYSTEM Behavior
- `-Headless` passes `NoNewWindow` to all scanner launches, suppressing UI windows.
Use this when dispatching from an RMM agent that has no interactive desktop.
- Scanners with `session0_compatible: false` in `scanners.json` are automatically skipped
when the module detects it is running as SYSTEM (Session 0). Currently: **AdwCleaner**.
The result record shows `SKIPPED (requires user session)` rather than a failure.
- To run AdwCleaner via GuruRMM, dispatch with `context: user_session` so it runs in
the active user's desktop session (requires a logged-in user on the target machine).
- `-Headless` launches all scanner processes with `WindowStyle=Hidden`, suppressing
UI windows and preventing child processes from inheriting the PowerShell pipe
handles. Use this when dispatching from an RMM agent with no interactive desktop.
- Scanners with `session0_compatible: false` in `scanners.json` are automatically
skipped when the module detects it is running as SYSTEM (Session 0). The result
record shows `SKIPPED (requires user session)` rather than a failure.
- The whitelist (`C:\GuruScan\whitelist.txt`) is honoured by Emsisoft (`/wl=`) and
HitmanPro (`/excludelist=`). RKill does not support a whitelist.
---
## GuruRMM Integration
When dispatched via GuruRMM in `system` context with `-Headless`, the launcher
emits a `GURUSCAN_RESULT_JSON:<compressed-json>` line to stdout at the end of the
run. The GuruRMM agent captures this in `command.stdout` for structured result
reporting on the dashboard.
```powershell
# GuruRMM dispatch command (system context, elevated):
C:\GuruScan\Invoke-GuruScan.ps1 -Headless
```
The JSON structure matches `results.json` written to disk:
```json
{
"scan_id": "HOSTNAME-20260527-010203",
"machine": "HOSTNAME",
"started_at": "...",
"completed_at": "...",
"total_threats": 0,
"reboot_required": false,
"scan_mode": "clean",
"scanners": [
{ "name": "RKill", "status": "completed", "exit_code": 1, "threats_found": 0, "duration_min": 0.09 },
{ "name": "Emsisoft", "status": "completed", "exit_code": 0, "threats_found": 0, "duration_min": 4.8 },
{ "name": "HitmanPro","status": "completed", "exit_code": 0, "threats_found": 0, "duration_min": 2.2 }
]
}
```
---
@@ -88,7 +126,6 @@ To run cleanup immediately without waiting (e.g. if the task was missed):
| Scanner | License for MSP use |
|---------|---------------------|
| RKill | Free (BleepingComputer) |
| AdwCleaner | Free for personal and commercial use |
| Emsisoft Command Line Scanner | Free for personal and MSP remediation use |
| HitmanPro | Commercial license required. Each scan uses trial mode; `Invoke-HitmanProTrialReset` resets the trial window. Verify current licensing terms at https://www.hitmanpro.com before deploying at scale. |
@@ -154,14 +191,14 @@ Invoke-PostRebootCleanup
```
guru-scan\
GuruScan.psm1 # Core module — all helpers + exported cmdlets
GuruScan.psd1 # Module manifest
scanners.json # Scanner definitions (single source of truth)
Invoke-GuruScan.ps1 # Thin launcher -> Invoke-GuruScan
Invoke-Remediation.ps1 # Thin launcher -> Invoke-Remediation
Get-ScanSummary.ps1 # Thin launcher -> Get-ScanSummary
Invoke-PostRebootCleanup.ps1 # Thin launcher -> Invoke-PostRebootCleanup (manual cleanup trigger)
Invoke-ScannerCleanup.ps1 # Post-reboot cleanup script; copied to C:\GuruScan\ when reboot is needed
Download-Scanners.ps1 # Downloads scanner EXEs from scanners.json URLs
downloads\ # Scanner EXEs (gitignored)
GuruScan.psm1 # Core module — all helpers + exported cmdlets
GuruScan.psd1 # Module manifest
scanners.json # Scanner definitions (single source of truth)
Invoke-GuruScan.ps1 # Thin launcher -> Invoke-GuruScan
Invoke-Remediation.ps1 # Thin launcher -> Invoke-Remediation
Get-ScanSummary.ps1 # Thin launcher -> Get-ScanSummary
Invoke-PostRebootCleanup.ps1 # Thin launcher -> Invoke-PostRebootCleanup
Invoke-ScannerCleanup.ps1 # Post-reboot cleanup; copied to C:\GuruScan\ when reboot is needed
Download-Scanners.ps1 # Downloads scanner EXEs from scanners.json URLs
downloads\ # Scanner EXEs (gitignored)
```