Search code examples
powershellvisual-studio-codevscode-tasks

How to keep double quote in here-string for powershell in vscode task


Steps to Reproduce:

  1. add the task below to task.json
  2. Run task
  3. The expected output is abcd "abcd", howerever, it print abcd abcd in task terminal

Actually, I want to use $selectedtext in task. So I can't modified or escapte the quotes in the selectedtext.

  • task:
    {
      "label": "Run test powershell here-string",
      "type": "shell",
      "windows": {
        "options": {
          "shell": {
            "executable": "powershell.exe",
            "args": ["-NoLogo", "-Command"]
          }
        },
        "command": "$stext=\n@'\nabcd \"abcd\"\n'@\n ; echo $stext "
      },
      "options": {
        "cwd": "${workspaceFolder}"
      },
      "problemMatcher": []
    }
  • task with selectedtext if there are double quotes ("):
    {
      "label": "Run test powershell here-string",
      "type": "shell",
      "windows": {
        "options": {
          "shell": {
            "executable": "powershell.exe",
            "args": ["-NoLogo", "-Command"]
          }
        },
        "command": "$stext=\n@'\n${selectedText}\n'@\n ; echo $stext "
      },
      "options": {
        "cwd": "${workspaceFolder}"
      },
      "problemMatcher": []
    }

Here is the output:

*  Executing task: $stext=
                           @'
                             abcd "abcd"
                                        '@
                                           ; echo $stext  

abcd abcd
 *  Terminal will be reused by tasks, press any key to close it. 

Solution

  • The problem is your use of a "shell"-type task, whose "command" property value isn't escaped for you, so that any " chars. end up un-escaped on the PowerShell process command line, where they are removed during the initial command line parsing in -Command (-c) invocations.

    Switch to a "process"-type task, which allows you to invoke the PowerShell CLI directly, with the PowerShell code passed in the final "args" argument:

    • On Windows, Visual Studio Code automatically \-escapes any embedded " chars. in the elements of "args", and automatically encloses elements with spaces in "...", which ensures that the PowerShell CLI sees embedded " chars. as \" and therefore retains them as part of the PowerShell code to execute.

    Here's a simplified example (note that -NoLogo is implied with -Command, so it needn't be specified; you may choose to pass -NoProfile instead, so as to bypass profile loading):

    {
      "label": "Run Powershell here-string test",
      "type": "process",
      "command": "powershell.exe",
      "args": [
          "-Command",
          "$selectedText = @'\n${selectedText}\n'@; '»' + $selectedText + '«'",
      ]
      "options": {
          "cwd": "${workspaceFolder}"
      },
      "problemMatcher": []
    }
    

    However, there's an arguably simpler (and fully robust) alternative: use an aux. environment variable to pass arbitrary unknown-in-advance values:

    {
      "label": "Run Powershell here-string test",
      "type": "process",
      "command": "powershell.exe",
      "args": [
          "-Command",
          "$selectedText = $env:__selectedText; '»' + $selectedText + '«'",
      ],
      "options": {
          "env": {
              "__selectedText": "${selectedText}"
          },
          "cwd": "${workspaceFolder}"
      },
      "problemMatcher": []
    }