A new way to add Visual Studio tools to your PowerShell environment with Enter-VsDevShell

PowerShell All the Things

For many years I’ve enjoyed using a PowerShell console as my go-to CLI for interacting with .NET projects and solutions. One of the first things I do when provisioning a new developer machine is grab a copy of my PowerShell profile from my GitHub repository. Even though I’ve been using Ubuntu as my main platform for development, and have consequently gotten into ZSH and BASH scripting, I still use PowerShell daily, but now with a new cmdlet: Enter-VsDevShell.

PowerShell + Visual Studio == Awesome

Up until the 16.2.1 release1 of Visual Studio 2019, I used the inimitable PowerShell Community Extensions (PSCX) module to execute batch files to alter the current environment variables (PATH, etc.). I would use the Invoke-BatchFile cmdlet in my profile to execute the VsDevCmd.bat file in the Common7\Tools folder of the current Visual Studio installation. This command required a bit of maintenance over time since the path was specific to the installed edition and major version of Visual Studio. Upon upgrading to the 16.2.1 release, my profile began coughing up an error:

Then things like MSBuild quit working. Bad, bad, not good.

Watson, the Game is Afoot!

I initially thought something might have happened to the Invoke-BatchFile implementation in PSCX, prompting me to raise an issue to that team2. The Invoke-BatchFile command executes the specified batch file with cmd.exe, then calls set to dump the new environment table to file for parsing. The problem arose because the combined outputs from the batch file and resulting environment variable list exceeded the 8191 character limit3 established back in the hoary days of “Ye Olde Windows XP.” After this diversion down memory lane, I knew why it was breaking but didn’t know what I could do to fix it.

In trying to isolate the naughty command prompt behavior, I happened to discover the new Developer PowerShell for VS 2019 console. This console didn’t throw errors, and everything appeared to be working. However, after a bit of casting about for the location of the actual shortcut, I discovered that it loads a PowerShell module and calls a cmdlet (Enter-VsDevShell) within to achieve the same result as the batch file does for the regular cmd.exe console.

Further Down the Rabbit Hole

The shortcut for the “Developer PoserShell for VS 2019” item lives in the folder C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio 2019\Visual Studio Tools and executes the following command:

The relative path to the module works because the “Start in” value of the shortcut is set to C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\. These shortcut properties are all good and proper for most folks: copy the command section of the shortcut into your profile, make the path absolute to where you have installed Visual Studio, and continue merrily on your way. You will have to change the path and the InstanceId4 as you change editions or upgrade, but that’s not much of an onus for most people.

Peace Falls Over the Hidden Valley… Or Does It?

At this point, I was getting MSBuild in my path, and things were working again. I had previously noticed that new PowerShell consoles ended up in my “Projects location” folder in Visual Studio options, as seen in the screenshot below:

Visual Studio 2019 Options dialog

This location isn’t an issue for most. It’s probably handy to get new consoles opening in the location where you do your work. That wasn’t the case for me.

Trouble Returneth

After a few days, I switched back to working on a client’s large application. Using PowerShell, the solution launched a fleet of IISExpress instances to stand up every site in their web app suite. The launch scripts for this application were failing because they expected a new PowerShell console to remain in its working directory. Because of this new behavior, that wasn’t the case: the IISExpress instances would start, but crash silently on receiving the first HTTP request.

This problem was complicated to debug, especially since the behavior followed me between environments. I was eventually able to add the -NoProfile argument to the launch scripts and get back to being productive. I still wanted to understand how it actually worked. In my curiosity,  I cracked open Microsoft’s new PowerShell module with JetBrains’ dotPeek and went hunting.

The Land of the Overworld is Saved Again

I discovered a parameter to the Enter-VsDevShell cmdlet called -SkipAutomaticLocation. This optional SwitchParameter suppresses the behavior that changes the current working directory to the repository location specified in the Visual Studio settings. At the time of this writing, I haven’t found any documentation on the cmdlets contained within Microsoft.VisualStudio.DevShell; I hope this is remedied soon.

There are two different ParameterSets for calling the Enter-VsDevShell cmdlet. One set that requires the InstanceId referenced in the shortcut, and one for providing the InstallationPath to Visual Studio itself. Both tell the cmdlet where to start looking for things to add into your environment. Using this insight, I discovered a blog post by Jason Tucker that explains how to use vswhere.exe to derive the installation path. I needed a future-proof and non-harmful way to add Visual Studio environment variables to my PowerShell consoles. The key was in combining these two approaches:

Coda

There are some other interesting parameters you can pass to Enter-VsDevShell:

CommandDescription
-TestAppears to load all the batch files and report back the locations. This parameter might be useful if you have multiple versions of Visual Studio installed.
-DevCmdDebugLevel [None, Basic, Detailed, Trace]Changes the verbosity and frequency of the messages it spews out during execution.
-SkipExistingEnvironmentVariables,
-StartInPath,
-DevCmdArguments,
-SetDefaultWindowTitle
These also exist, but I haven’t yet determined their utility.

In retrospect, I’m glad I was curious enough to dig into this new functionality shipping with Visual Studio. I wrote this post to highlight things that I found useful to me. Hopefully, better documentation is forthcoming!

Here is the current anemic help output from the cmdlet:

Please feel free to steal anything from my profiles in the repository above, or offer up alternatives or improvements. I will also try to answer any questions left in the comments.

Important note about Enter-VsDevShell:

The Enter-VsDevShell cmdlet in the Microsoft module does not yet work with PowerShell Core, please up-vote this issue to raise it’s visibility if you are interested.

Footnotes

  1. Release notes here.
  2. PSCX issue #66.
  3. Discussed in this KB article.
  4. I have no idea where this value comes from. Its source in the cmdlet is obscured by a call out to an unmanaged type.

Leave a comment

Your email address will not be published. Required fields are marked *