* Checks for ForEach-Object -MemberName. Invokes a method by string name on * every piped object — semantically equivalent to `| % { $_.Method() }` but * without any ScriptBlockAst or InvokeMemberExpressionAst in the tree. * * PoC: `Get-Process | ForEach-Object -MemberName Kill` → kills all proc
( parsed: ParsedPowerShellCommand, )
| 497 | * COMMON_ALIASES. |
| 498 | */ |
| 499 | function checkForEachMemberName( |
| 500 | parsed: ParsedPowerShellCommand, |
| 501 | ): PowerShellSecurityResult { |
| 502 | for (const cmd of getAllCommands(parsed)) { |
| 503 | const lower = cmd.name.toLowerCase() |
| 504 | const resolved = COMMON_ALIASES[lower]?.toLowerCase() ?? lower |
| 505 | if (resolved !== 'foreach-object') { |
| 506 | continue |
| 507 | } |
| 508 | // ForEach-Object params starting with -m: only -MemberName. -m is unambiguous. |
| 509 | if (psExeHasParamAbbreviation(cmd, '-membername', '-m')) { |
| 510 | return { |
| 511 | behavior: 'ask', |
| 512 | message: |
| 513 | 'ForEach-Object -MemberName invokes methods by string name which cannot be validated', |
| 514 | } |
| 515 | } |
| 516 | // PS7+: `ForEach-Object Kill` binds a positional string arg to |
| 517 | // -MemberName via MemberSet parameter-set resolution (ScriptBlock args |
| 518 | // select ScriptBlockSet instead). Scan ALL args — `-Verbose Kill` or |
| 519 | // `-ErrorAction Stop Kill` still binds Kill positionally. Any non-dash |
| 520 | // StringConstant is a potential -MemberName; over-flagging is fail-safe. |
| 521 | for (let i = 0; i < cmd.args.length; i++) { |
| 522 | const argType = cmd.elementTypes?.[i + 1] |
| 523 | const arg = cmd.args[i] |
| 524 | if (argType === 'StringConstant' && arg && !arg.startsWith('-')) { |
| 525 | return { |
| 526 | behavior: 'ask', |
| 527 | message: |
| 528 | 'ForEach-Object with positional string argument binds to -MemberName and invokes methods by name', |
| 529 | } |
| 530 | } |
| 531 | } |
| 532 | } |
| 533 | return { behavior: 'passthrough' } |
| 534 | } |
| 535 | |
| 536 | /** |
| 537 | * Checks for dangerous Start-Process patterns. |
nothing calls this directly
no test coverage detected