powershell

pwsh -Command is removing quotation marks


In pwsh call the following:

Write-Host '{"drop_attr": "name"}' 

Result ok:

{"drop_attr": "name"}

Now do the same via pwsh:

pwsh -Command Write-Host '{"drop_attr": "name"}'

Result is missing quotation marks and square brackets?

drop_attr: name

Solution

  • Update:


    Unfortunately, PowerShell's handling of passing arguments with embedded " chars. to external programs - which includes PowerShell's own CLI (pwsh) - is fundamentally broken (and always has been), up to at least PowerShell 7.2.x, as well as in Windows PowerShell (the legacy, ships-with-Windows, Windows-only edition of PowerShell whose latest and last version is 5.1)

    You need to manually \-escape " instances embedded in your arguments in order for them to be correctly passed through to external programs (which happens to be PowerShell in this case as well):

    # Note: The embedded '' sequences are the normal and expected
    #       way to escape ' chars. inside a PowerShell '...' string.
    #       What is *unexpected* is the need to escape " as \"
    #       even though " can normally be used *as-is* inside a '...' string.
    pwsh -Command ' ''{\"drop_attr\": \"name\"}'' '
    

    Note that I'm assuming your intent is to pass a JSON string, hence the inner '' ... '' quoting (escaped single quotes), which ensures that pwsh ultimately sees a single-quoted string ('...'). (No need for an explicit output command; PowerShell implicitly prints command and expression output).

    Another way to demonstrate this on Windows is via the standard choice.exe utility, repurposed to simply print its /m (message) argument (followed by verbatim [Y,N]?Y):

    # This *should* preserve the ", but doesn't as of v7.2
    PS> choice /d Y /t 0 /m '{"drop_attr": "name"}'
    {drop_attr: name} [Y,N]?Y      # !! " were REMOVED
    
    # Only the extra \-escaping preserves the "
    PS> choice /d Y /t 0 /m '{\"drop_attr\": \"name\"}'
    {"drop_attr": "name"} [Y,N]?Y  # OK
    

    Note that from inside PowerShell, you can avoid the need for \-escaping, if you call pwsh with a script block ({ ... }) - but that only works when calling PowerShell itself, not other external programs:

    # NOTE: Works from PowerShell only.
    pwsh -Command { '{"drop_attr": "name"}' }
    

    Background info on PowerShell's broken handling of arguments with embedded " in external-program calls, as of PowerShell 7.2.1: