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:
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user