Files
claudetools/projects/msp-tools/guru-scan

GuruScan

Multi-engine malware scan orchestrator for GuruRMM. Runs a sequenced chain of portable security scanners, captures all logs, and writes structured JSON results for downstream processing by the RMM agent.


Deploy Layout

Path Purpose
C:\GuruScan\ Base directory — module files, whitelist, state files
C:\GuruScan\downloads\ Scanner EXEs (populated by Download-Scanners.ps1)
C:\GuruScan\reports\ Per-scan zip archives
C:\ScanLogs\ Per-scan log folders (<HOSTNAME>-<YYYYMMDD-HHmmss>\)

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.


Scanner Chain

Scanners run in this order. Each stage hands off to the next regardless of findings.

# 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.
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.
5 ESET Online Scanner antimalware Skipped automatically when running as SYSTEM (requires interactive desktop).

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.


Exit Code Semantics

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
ESET Clean Threats found Incomplete removal, reboot may help
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, ESET 2.


Autologon / Cleanup Lifecycle

When any scanner exits with a reboot-required code (exit 2), the following sequence runs:

  1. Invoke-RebootCleanupSetup writes cleanup-state.json with the original user, scan ID, and log path.
  2. A hidden GuruRMM-Temp administrator account is created with a random password.
  3. One-time autologon (AutoLogonCount=1) is configured for GuruRMM-Temp. Windows clears the password after the first use.
  4. The account is hidden from the login screen via the SpecialAccounts\UserList registry key.
  5. A logon-triggered scheduled task (GuruRMM-PostRebootCleanup) is registered for GuruRMM-Temp.
  6. The machine reboots after a 15-second warning.
  7. On next boot, Windows auto-logs in as GuruRMM-Temp. The WPF splash appears immediately (full-screen, black, cursor hidden).
  8. Invoke-PostRebootCleanup runs: verifies pending operations cleared, removes scanner files, writes logs-ready.json, restores the original user's login name, clears autologon, removes the cleanup task.
  9. A SYSTEM scheduled task (GuruRMM-TempUserDelete) is registered to delete the GuruRMM-Temp account 2 minutes later (cannot delete your own account while logged in).
  10. The splash closes, logoff is called, and the machine returns to the normal login screen.

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.
  • ESET is automatically skipped when the script detects it is running as the SYSTEM account ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem). Pass -SkipEset explicitly to skip it under other accounts.

Licensing

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.
ESET Online Scanner Free for personal and commercial use

Always verify current licensing terms with each vendor before large-scale deployment.


Stand-alone Usage

# Run all scanners in clean mode (default)
.\Invoke-GuruScan.ps1

# Detect only, then auto-remediate if threats found
.\Invoke-GuruScan.ps1 -ScanOnly -AutoRemediate

# Skip ESET (e.g. unattended run)
.\Invoke-GuruScan.ps1 -SkipEset

# Suppress scanner windows (RMM dispatch)
.\Invoke-GuruScan.ps1 -Headless

# View the latest scan results
.\Get-ScanSummary.ps1

# View with AI analysis (requires Ollama)
.\Get-ScanSummary.ps1 -AI

# Re-run clean pass against a prior scan
.\Invoke-Remediation.ps1 -LogRoot "C:\ScanLogs\DESKTOP-20260523-143000"

# Download/refresh scanner EXEs
.\Download-Scanners.ps1

Module Usage

The launcher scripts are thin wrappers. Import the module directly for scripted/pipeline use:

Import-Module .\GuruScan.psd1

# Disk sink (default) — writes results.json + CSV + zip
Invoke-GuruScan

# RMM sink — returns result object to the pipeline, no disk writes
$result = Invoke-GuruScan -OutputSink RMM -Headless
if ($result.total_threats -gt 0) { ... }

# Remediation from a prior scan
Invoke-Remediation -LogRoot "C:\ScanLogs\DESKTOP-20260523-143000"

# Summary report
Get-ScanSummary -AI

# Post-reboot cleanup (called by Invoke-PostRebootCleanup.ps1)
Invoke-PostRebootCleanup -StateFile "C:\GuruScan\cleanup-state.json"

Module Structure

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 # WPF splash + logoff; delegates cleanup to module
  Download-Scanners.ps1       # Downloads scanner EXEs from scanners.json URLs
  downloads\                  # Scanner EXEs (gitignored)