# 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 (`-\`) | 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 ```powershell # 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: ```powershell 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) ```