Skip to content

gwmi backend runs the user's PowerShell profile on every poll #192

Description

@Shmuel3

What happens

On Windows, lib/gwmi.js spawns PowerShell through Node's shell option:

bin('gwmi', args, { windowsHide: true, windowsVerbatimArguments: true, shell: 'powershell.exe' }, ...)

Node turns that into powershell.exe -c <pipeline>. Neither -NoProfile nor -NonInteractive is passed, so every stats poll loads and executes the user's PowerShell profile.

Why it matters

  1. Arbitrary user startup code runs on every poll.
  2. The profile's startup cost (oh-my-posh, module imports — often hundreds of ms) is added to every call.
  3. Any profile that writes to stderr fails the poll outright: lib/bin.js treats non-empty stderr as a fatal error.
  4. A profile that blocks hangs the poll forever and leaks the spawned powershell.

(4) is not hypothetical. On a machine whose profile execs wsl.exe for interactive-looking consoles, an app polling via pidusage every 3 minutes accumulated ~330 orphaned WSL sessions. The leaked Hyper-V socket channels eventually exhausted Windows socket buffer space, and every new WSL terminal failed with Wsl/Service/0x80072747 until reboot. Observed leaked command line:

powershell.exe -c gwmi win32_process -Filter 'ProcessId=8816 or ProcessId=24328 or ...' | select CreationDate,KernelModeTime,ParentProcessId,ProcessId,UserModeTime,WorkingSetSize | format-table

This is the same class of failure as the 4.0.1 fix ("fix spawned wmic processes not exiting after wmic/gwmi detection … leading to infinite build up").

Scope: every Windows user on 4.x, not only machines without wmic

The backend picker in lib/stats.js is:

child = spawn('wmic', function (err) { ... })

spawn() requires its second argument to be an array or an options object. A function throws ERR_INVALID_ARG_TYPE synchronously, on every platform, before anything is spawned — so the catch always runs and gwmi is always selected on Windows, leaving lib/wmic.js unreachable. (Separate issue; noting it because it means the profile-loading path is the only Windows path in 4.x.)

Suggested fix

Spawn powershell.exe directly with -NoProfile -NonInteractive -Command <pipeline> instead of going through the shell option, leaving the query and format-table output — and therefore the parser — unchanged.

Version: 4.0.1 / behaviour introduced with the gwmi fallback added for #183.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions