BlueStaggo
BlueStaggo

Reputation: 191

How do I get Visual Studio Developer Powershell working in Visual Studio Code's integrated terminal?

I am trying to create a Visual Studio Developer Powershell profile for Visual Studio Code. Here is what I tried:

"Developer Powershell": {
    "path": "pwsh",
    "args": [
        "-noe",
        "-c",
        "\"&{$vsPath = &(Join-Path ${env:ProgramFiles(x86)} '\\Microsoft Visual Studio\\Installer\\vswhere.exe') -property installationpath; Import-Module (Join-Path $vsPath 'Common7\\Tools\\Microsoft.VisualStudio.DevShell.dll'); Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation}\""
    ],
    "icon": "terminal-powershell"
}

I copied and pasted the arguments from my Windows Terminal profile, which works:

{
    "commandline": "pwsh.exe -noe -c \"&{$vsPath = &(Join-Path ${env:ProgramFiles(x86)} '\\Microsoft Visual Studio\\Installer\\vswhere.exe') -property installationpath; Import-Module (Join-Path $vsPath 'Common7\\Tools\\Microsoft.VisualStudio.DevShell.dll'); Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation}\"",
    "icon": "C:\\powershell\\713\\assets\\Square44x44Logo.png",
    "name": "Developer PowerShell",
    "startingDirectory": "%USERPROFILE%",
}

However, terminal output looks like this:

&{ = &(Join-Path C:\Program Files (x86) '\Microsoft Visual Studio\Installer\vswhere.exe') -property installationpath; Import-Module (Join-Path  'Common7\Tools\Microsoft.VisualStudio.DevShell.dll'); Enter-VsDevShell -VsInstallPath  -SkipAutomaticLocation}
  StaggoSTD   

Note: I am using Oh My Posh here. That's why the last line looks weird without a nerd font.

So how do I make the Developer Powershell work? I tried using powershell instead of pwsh and removing the escaped double quotes but that did nothing.

Upvotes: 2

Views: 4042

Answers (4)

alxcraciun
alxcraciun

Reputation: 1

Update on what mklement0 previously said (March 2023)

This worked for me. Modify last argument according to where your Powershell Developer is. I used Windows Terminal Settings to look up the proper path and args for my system.

        "Developer PowerShell": {
        "path": "powershell",
        "color": "terminal.ansiMagenta",
        "args": [
            "-NoExit",
            "-Command",
            "$vsPath = & \"${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe\" -property installationpath; Import-Module \"${env:ProgramFiles(x86)}/Microsoft Visual Studio/2022/BuildTools/Common7/Tools/Microsoft.VisualStudio.DevShell.dll\"; Enter-VsDevShell cc62515d -SkipAutomaticLocation -DevCmdArguments '-arch=x64 -host_arch=x64'"
            ]
    },

Upvotes: 0

mklement0
mklement0

Reputation: 437238

tl;dr

The following - which can be used as a property inside the "terminal.integrated.profiles.windows" property of your settings.json file in order to define a terminal profile named Developer PowerShell - fixes the problems with your original attempt.

"Developer Powershell": {
  "path": "pwsh",
  "args": [
    "-noexit",
    "-c",
    "$vsPath = & \"${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe\" -property installationpath; Import-Module \"$vsPath/Common7/Tools/Microsoft.VisualStudio.DevShell.dll\"; Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation"
  ],
  "icon": "terminal-powershell"
}

Note:

  • Do not use this shell profile as your default profile - unless you've also configured explicitly configured an automation shell to be used for tasks and debugging, via a "terminal.integrated.automationProfile.windows" property - see Terminal Profiles.

    • The problem is that automation operations pass additional command(s) to execute, and Visual Studio Code passes them by blindly appending -Command <command> to the shell command line (/d /c <command> if cmd.exe is the shell), which breaks if the shell profile itself already defines commands (rather than mere options) to execute on startup.
  • Given that the assumption that environment variable ProgramFiles(x86) expands to C:\Program Files (x86) is pretty safe (though it is possible for it to expand to a different path on unusually configured systems), your own solution, which avoids use of ${env:ProgramFiles(x86)}, should typically work just fine.

  • The solution above still uses ${env:ProgramFiles(x86)}, and makes it work by including it in an embedded expandable string (\"...\") that constructs the path strings directly, not via Join-Path. This not only simplifies the command, it avoids one of the original problems: use of ${env:ProgramFiles(x86)} outside of a (PowerShell) string literal; the next section explains why that is a problem.

  • Another simplification is the use of / as the path separator - which PowerShell accepts interchangeably with \ - which doesn't require escaping inside a JSON string.


Background information:

  • Since you're passing the PowerShell CLI arguments as an array, via the "args" property, you should not additionally enclose the string passed to the -c parameter in an embedded, escaped "..." string (\"...\"), because with "args" it is Visual Studio Code that performs any necessary escaping when stitching together the command line ultimately invoked behind the scenes.

    • If you do use enclosure in \"...\", PowerShell ultimately sees your commands as a single, expandable string literal, whose expanded value is implicitly echoed - that is the symptom you saw; in simple terms, PowerShell ended up executing something like "$vsPath = ...", which attempts to expand (interpolate) variable $vsPath, and since no such variable exists, it evaluates to the empty string, causing the following verbatim string to be output: = ...

    • To put it differently: With "args", you needn't worry about quoting for the command line: You simply formulate what each argument should be verbatim, and let VS Code do the escaping - however, there is JSON-related escaping you do need to perform, and there's the pitfall of VS Code rather than PowerShell potentially up-front expanding variable references such as ${env:ProgramFiles(x86)}:

      • JSON-escaping: Escape embedded " as \", \ as \\; note that the pain of the latter can be eased by using / as the path separator instead, which PowerShell accepts interchangeably with \.
      • VS Code up-front variable expansion pitfall:
        • VS Code only considers references of the form ${someName} and ${someNameSpace:someName} candidates for up-front expansion - not also $someName and $someNameSpace:someName
        • Therefore, typical PowerShell variable references such as $vsPath or $env:USERNAME are not subject to potential up-front expansion, but it may happen in cases where enclosure in {...} is syntactically required in PowerShell, due to a nonstandard name such as ${env:ProgramFiles(x86)}.
        • With the env: namespace, specifically, up-front expansion always happens (as with command:, config:, and input:, but these aren't typically defined in PowerShell): VS Code expands a reference such as ${env:ProgramFiles(x86)} to the verbatim value of that environment variable. That is, ${env:ProgramFiles(x86)} is replaced with verbatim C:\Program Files (x86) in the command string before PowerShell sees the string, and the lack of quoting around the value then causes a syntax error.
        • While this up-front expansion cannot be suppressed, a simple solution is to enclose the reference in quotes: '${env:ProgramFiles(x86)}' or \"${env:ProgramFiles(x86)}\". Note that this assumes that the value itself contains no ' or ", respectively; in cases where this assumption cannot be made, use the following workaround:
          (Get-Content 'env:ProgramFiles(x86)')
  • As an aside: It is unnecessary to enclose statements passed to -c (-Command) in & { ... } - just use ... (the statements) directly.

    • Older versions of the CLI documentation erroneously suggested that & { ... } is required, but this has since been corrected.

Upvotes: 4

elika kohen
elika kohen

Reputation: 157

There are a couple of challenges to customizing PowerShell Integrated Terminal Profiles to work together with Microsoft.VisualStudio.DevShell.dll:

  • Use the latest version of PowerShell, (not PowerShell.exe, but pwsh.exe).
  • There is a "defect" in Visual Studio Code that injects a -Command when using the "terminal.integrated.automationProfile.windows" in settings.json. So, don't use it. Instead...
  • Directly configure Visual Studio Code's Task with Microsoft.VisualStudio.DevShell.dll. Kind of a pain, but it will have to do until the "terminal.integrated.automationProfile.windows" works as expected.

Configuring the integrated terminal profile:

    "terminal.integrated.defaultProfile.windows": "Developer PowerShell",
    "terminal.integrated.shellIntegration.enabled": false,
    "terminal.integrated.shellIntegration.decorationsEnabled": "both",
    "terminal.integrated.profiles.windows": {

    "PowerShell": {
        "source": "PowerShell",
        "icon": "terminal-powershell"
    },
    "Command Prompt": {
        "path": [
            "${env:windir}\\Sysnative\\cmd.exe",
            "${env:windir}\\System32\\cmd.exe"
        ],
        "args": [],
        "icon": "terminal-cmd"
    },
    "Git Bash": {
        "source": "Git Bash"
    },
    "Developer PowerShell": {
        "path": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
        "icon": "terminal-powershell",
        "args": [
            "-noexit",
            "-Command",
            "Import-Module 'C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/Common7/Tools/Microsoft.VisualStudio.DevShell.dll'; Enter-VsDevShell -VsInstallPath 'C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools' -SkipAutomaticLocation;"
        ]
        
    }

Configuring Microsoft.VisualStudio.DevShell.dll for Specific Tasks:

{
    "version": "2.0.0",
    "tasks": [

 {
            "type": "shell",
            "label": "MyApp.API - Debug",
            "detail": "Clean and Precompile API.",
            "dependsOn": "MyApp.API - Clean",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "presentation": {
                "clear": false,
                "echo": true,
                "panel": "shared"
            },
            "problemMatcher": [
                "$msCompile"
            ],
            "options": {
                "shell": {
                    "executable": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
                    "args": [
                        "-NoProfile",
                        "-ExecutionPolicy",
                        "Bypass",
                        "-Command",
                        "Import-Module 'C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/Common7/Tools/Microsoft.VisualStudio.DevShell.dll'; Enter-VsDevShell -VsInstallPath 'C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools' -SkipAutomaticLocation;"
                    ]
                }
            },
            "command": "cl.exe",
            "args": [
                "/c",
                "/std:c++20",
                "/permissive-",
                "/await",
                "/bigobj",
                "/utf-8",
                "/MTd",
                "/sdl",
                "/Gr",
                "/GL",
                "/Zo",
                "/Z7",
                "/EHsc",
                "/FC",
                "/Fd:",
                "Build/Debug/pch.pdb",
                "/Fo:",
                "Build/Debug/",
                "Include/pch.cpp",
                "/Ycpch.h",
                "/FpBuild/Debug/pch.pch"
            ]
        }
    ]
}
}

Upvotes: 1

BlueStaggo
BlueStaggo

Reputation: 191

I have figured it out. Firstly, I would like to give credit to mklement0, who has submitted an answer on simplifying the arguments, however it has been deleted. Using this, I replaced ${env:ProgramFiles(x86)} with 'C:\\Program Files (x86)' and everything went smoothly. To check if everything was properly working, I ran gcm fsi, which told me that F# Interative was there, even though it is not on my normal PATH. Here is my profile now for anybody who wants Developer Powershell in VSCode:

"Developer Powershell": {
    "path": "pwsh",
    "args": [
        "-noe",
        "-c",
        "$vsPath = &(Join-Path 'C:\\Program Files (x86)' '\\Microsoft Visual Studio\\Installer\\vswhere.exe') -property installationpath; Import-Module (Join-Path $vsPath 'Common7\\Tools\\Microsoft.VisualStudio.DevShell.dll'); Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation"
    ],
    "icon": "terminal-powershell"
}

As for why the environment variable was there, I copied and pasted from a Microsoft blog. Because it worked for Windows Terminal, I thought it worked for VSCode too. However, every other place I looked for a Developer Powershell profile, the environment variable wasn't used. Later on, I found out that I can just copy from the shortcut at C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio 2019\Visual Studio Tools.

Upvotes: 2

Related Questions