jsonpowershellvisual-studio-codebyte-order-mark

How to create VSCode task creating a file without BOM


I need to create a JSON file when launching an Angular e2e test, basing on gopass key. Unfortunately I'm getting JSON encoded as UTF-8 with BOM.

I created task in tasks.json launched by one of launch configuration, tried to configure it without success. Problem is caused by PowerShell, which by default write files with BOM characters. I was trying to change task type to process (run with key and output file as args too), but then I got problem with not selecting proper gopass key or with running command. I cannot make slight changes in my test code, so I need to set it by tasks.json/launch.json.

My current task configuration:

{
    "type": "shell",
    "label": "Get data",
    "command": "gopass \"somekey\" > \"myFile.json\""
},

I want to get JSON file without BOM character


Solution

  • Theo's answer shows you how to make Visual Studio Code's default shell on Windows, Windows PowerShell, create BOM-less UTF-8 files, which, unfortunately, is quite cumbersome, because it isn't supported with standard operators and cmdlets.

    The shortest formulation in your case would be to replace:

    "command": "gopass \"somekey\" > \"myFile.json\""
    

    with:

    "command": "[IO.File]::WriteAllLines(\"$pwd\myFile.json\", (gopass \"somekey\"))"
    

    To retain the convenience of defining your tasks.json tasks as unmodified PowerShell command strings that can use >, while also producing BOM-less UTF-8 output, you can make your task use PowerShell Core 7 as the shell instead, because its file-output cmdlets and redirection operators consistently default to BOM-less UTF8:

    Prerequisite:


    If you're OK with globally substituting PowerShell (Core) 7 for Windows PowerShell - which then requires no change to your task definition:

    Note: This means that the integrated terminal as well as all "shell"-type tasks in tasks.json will use PowerShell 7.

    Open setting.json (from the command palette, select > Preferences: Open Settings (JSON)) and add the following property:

        "terminal.integrated.defaultProfile.windows": "PowerShell",
    

    Note: If pwsh.exe is not in your system's PATH, specify the full path in the "executable" property; you can obtain it by opening a PowerShell 7 window and executing (Get-Process -Id $PID).Path.


    Alternatively, if you want to substitute PowerShell (Core) 7 for Windows PowerShell task-individually:

    Add an "option" object to your task-definition JSON to make it use PowerShell Core's CLI instead of Windows PowerShell's:

    {
        "type": "shell",
        "label": "Get data",
        "command": "gopass \"somekey\" > \"myFile.json\""
        "options": {
          "shell": {
             "executable": "pwsh.exe",
             "args": [ "-noprofile", "-command" ]
          }
        }
    }
    

    Automated on-demand installation of PowerShell (Core) 7 on Windows:

    Since it is easy to perform an automated user-level installation of PowerShell 7, you can fully automate the whole process as follows:

    {
        "label": "EnsurePsCoreInstalled",
        "type": "process",
        "command": "powershell.exe",
        "args": [
            "-noprofile",
            "-command",
            "if (gcm -ea ignore pwsh) { exit 0 }; Write-Verbose -vb 'Installing PowerShell Core...'; iex \"& { $(irm https://aka.ms/install-powershell.ps1) }\"; $dir = $env:LocalAppData + '\\Microsoft\\PowerShell'; $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') -split ';' -ne ''; if ($dir -notin $userPath) { [Environment]::SetEnvironmentVariable('Path', ($userPath + $dir) -join ';', 'User') }; $env:Path += ';' + $dir; if (gcm -ea ignore pwsh) { Throw 'PowerShell Core was just installed on demand. To make it usable, log off and on again or reboot, or restart Visual Studio Code from a new PowerShell window (run `code`).' } else { Throw 'Installation of PowerShell Core FAILED.' }"
        ],
        "problemMatcher": []
    }