shadow1ng/fscan · error

local_pe_not_specified

Error message

local_pe_not_specified

What it means

WinWMIPlugin.Scan requires a local PE file path in session.Config.WinPEFile to compare against WMI persistence artifacts (e.g. event consumer payloads). If the field is empty, the plugin returns this localized error before doing any WMI queries. It is the same required-input guard used by the other local Windows plugins.

Source

Thrown at plugins/local/winwmi.go:31

	"github.com/shadow1ng/fscan/common"
	"github.com/shadow1ng/fscan/common/i18n"
	"github.com/shadow1ng/fscan/plugins"
)

type WinWMIPlugin struct {
	plugins.BasePlugin
}

func NewWinWMIPlugin() *WinWMIPlugin {
	return &WinWMIPlugin{
		BasePlugin: plugins.NewBasePlugin("winwmi"),
	}
}

func (p *WinWMIPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
	pePath := session.Config.WinPEFile
	if pePath == "" {
		return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
	}
	if _, err := os.Stat(pePath); err != nil {
		return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
	}

	absPath, _ := filepath.Abs(pePath)
	baseName := strings.TrimSuffix(filepath.Base(absPath), filepath.Ext(absPath))

	filterName := fmt.Sprintf("SysMon_%s", baseName)
	consumerName := fmt.Sprintf("SysExec_%s", baseName)

	ps := fmt.Sprintf(`$ok = 0
try {
  $f = ([wmiclass]"\\.\root\subscription:__EventFilter").CreateInstance()
  $f.Name = "%s"; $f.EventNameSpace = "root\cimv2"; $f.QueryLanguage = "WQL"
  $f.Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'"
  $f.Put() | Out-Null; $ok++; Write-Output "[OK] EventFilter"
} catch { Write-Output "[FAIL] EventFilter: $_" }

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Set session.Config.WinPEFile to the target PE path before invoking Scan.
  2. Confirm the CLI/config layer actually populates Config.WinPEFile for the winwmi plugin.
  3. Add a pre-run config validation that reports which required field is missing per plugin.

Example fix

// before
session.Config.WinPEFile = ""
p.Scan(ctx, host, session) // local_pe_not_specified
// after
session.Config.WinPEFile = "C:\\samples\\wmipersist.dll"
p.Scan(ctx, host, session)
Defensive patterns

Strategy: validation

Validate before calling

if strings.TrimSpace(cfg.WinPEFile) == "" {
    return errors.New("winwmi plugin requires Config.WinPEFile")
}

Type guard

func winPEConfigured(c *common.Config) bool { return c != nil && strings.TrimSpace(c.WinPEFile) != "" }

Prevention

When it happens

Trigger: Calling Scan with Config.WinPEFile left empty — the PE-file option was not supplied via CLI, config file, or programmatic Config construction when the winwmi plugin runs.

Common situations: Forgetting the PE-file flag while running the WMI persistence check; a config file missing the win-pe-file field; constructing ScanSession in code/tests without initializing WinPEFile; a rename in the config struct that silently drops the value.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/e70ce037c4b482ab. Report an issue: GitHub.