Skip to content

-Command values containing pipes/quotes are mangled by the cmd.exe /d /c wrapper #7

Closed

Description

@soroshsabz

Summary

-Command values that contain cmd.exe metacharacters (|, &, <, >, ^) or embedded quotes are mangled by the cmd.exe /d /c "{0}" wrapper in Get-BsnRecordingCommandLine: cmd.exe's /c quote processing strips the outer quotes and then interprets the metacharacters as its own syntax. The recorded session then runs the wrong command and the cast captures the resulting cmd errors.

Environment

  • Bsn.Host 0.1.0 (PowerShell Gallery)
  • Windows 11 10.0.26300 (the Windows engine always wraps through cmd.exe)

Repro

Start-InteractiveTranscript -Command "powershell -NoProfile -Command 'Write-Output A | Write-Host -NoNewline'"

What cmd.exe actually executes after quote stripping is powershell -NoProfile -Command 'Write-Output A piped to Host -NoNewline' (two commands), and the cast records:

'Write-Host' is not recognized as an internal or external command,
operable not recognized as an internal or external command, ...

I hit this in my first test recording (a PowerShell pipeline inside single quotes inside -Command); the recording "succeeded" with the cmd error captured as session output.

Root cause

src/Bsn.Host/Private/Get-BsnRecordingCommandLine.ps1:

if ($Command) {
    return ('cmd.exe /d /c "{0}"' -f $Command)
}

cmd.exe /c processing strips the first and last quote when the quoted string does not name an executable (the classic cmd /? quote rules). After stripping, any | & < > ^ in the user's command belongs to cmd.exe, and inner double quotes disappear. The same applies to the interactive-shell branch, which embeds Import-Module Bsn.Host; function prompt { ... } (with quotes and braces) inside pwsh ... -Command "{1}".

Suggested fix

Options, roughly in order of robustness:

  1. Do not route through cmd.exe when avoidable - CreateProcess already accepts an arbitrary command line, and the engine could resolve executables itself ($Command as a raw command line, like Start-Process).
  2. Escape cmd metacharacters (^|, ^&, ...) and use cmd.exe /d /c ""...""-style nested quoting correctly.
  3. At minimum, document that -Command must be cmd.exe-safe, and reject values containing metacharacters with an explanatory error instead of recording a broken session.

This is easy to trap in a Pester test against Get-BsnRecordingCommandLine (assert the round-trip through cmd.exe executes the intended command).

Activity

  1. soroshsabz commented on Nov 6, 2026

    @soroshsabz
    MemberAuthor

    Evidence artifact: https://gist.github.com/soroshsabz/19353e0745044a4d7dba78d61b80a8a0

    • issue7_cmdmangle.cast - a fresh non-redirected-console recording of the exact repro command. The cast records cmd.exe eating the pipe - event [0.041573, o, ...] contains:
    'Write-Host' is not recognized as an internal or external command,
    operable program or batch file.
    

    Recorded process exit code: 255.

  2. self-assigned this
    on Nov 6, 2026
  3. added theissue type on Nov 6, 2026
  4. added 2 commits that reference this issue on Nov 6, 2026
  5. added 3 commits that reference this issue on Nov 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions