We have a new version of Visual Studio coming soon so I did the work to update my WintellectPowerShell module to support it. And, what a huge adventure that turned out to be! I will discuss why its support for Visual Studio 2017 was hard a bit later in this blog entry. For those of you who are new to WintellectPowerShell, it is a module that brings a number of useful cmdlets for setting up symbol and source servers for Visual Studio 2013-2017 as well as WinDBG. Other cmdlets automatically download and extract all the lovely goodness of the SysInternal tools, automate the analysis of lots of minidump files, and so on. The module has been helpful to me over the years. You can look at all the source code on GitHub: https://github.com/Wintellect/WintellectPowerShell. To install WintellectPowerShell directly, execute the following command in PowerShell:
If you have a previous version of WintellectPowerShell installed, you will see an ‘Authenticode issuer’ error when you try to update. The error is because since I last released a WintellectPowerShell build, my code signing certificate needed to be renewed. When PowerShellGet does checks a signed module, it checks all the certificate fields. Because the issuer was different, even though version 126.96.36.199 is correctly digitally signed, you get the error. Add the –SkipPublisherCheck switch to Install-Module to allow the installation.
When I first sat down to add Visual Studio 2017 support, I thought it would be a day or two at most. It turned out to be several weeks. Why? Because Visual Studio 2017 changed a huge amount under the hood. At first I was frustrated because of the extra work for me, but all of those changes are actually very good for performance. Prior versions of Visual Studio dumped everything in the global registry so for those cmdlets, such as Set-SymbolServer and Set-SourceServer, I would directly manipulate the appropriate Visual Studio version keys in the registry to configure Visual Studio options.
With Visual Studio 2017, almost nothing is in the registry. With previous versions, you could head to HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\14.0 and you had access to pretty much every option. Now with Visual Studio 2017, the registry key is HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\15.0_XXXXXXXX, where the X’s are a bunch of numbers and there’s nothing but a single entry about licensing in the registry. Looking at the startup of DEVENV.EXE with the amazing Process Monitor, showed a lot of reading from “\REGISTRY\A” for all registry operations. A short bit of internet searching revealed that Process Monitor is showing “private registry hives”, which are per process registries opened with a call to the RegLoadAppKey API in Windows. Here is where I realized I probably needed to spend some quality time with the Visual Studio 2017 extensibility documentation. The most important page is the Changes in Visual Studio 2017 extensibility page, which discusses the good number of breaking changes. They are all good changes, because now Visual Studio 2017 uses Registration-Free Activation for COM components and private registry hives for better performance.
The registry changes made a lot of sense to me, but after installing Visual Studio 2017 on a couple of virtual machines, I noticed that the registry keys were different on each installation. Both in the regular registry, and the private registry hives, Visual Studio accesses \Software\Microsoft\VisualStudio\15.0_XXXXXXXX and each installation had their own set of special numbers. After reading the breaking changes documentation a couple of times I realized the statement “External components can find the Visual Studio location by following the guidance here.” was super important. That lead to a blog entry by Heath Stewart that was probably the most important discussion of Visual Studio 2017 changes. With the new lightweight installer and the fact that you can install multiple editions without conflicting, determining what is installed with Visual Studio 2017 is so complicated it needs its own API. The only documentation on this change is Heath’s blog, which happens to point to a GitHub repository with samples for the new Setup Configuration API. You would think that an API this important the Visual Studio extensibility documentation would have called this out right at the beginning, instead of linking to a random blog entry. With this new API, you can now deduce what the installed versions of Visual Studio 2017 are on a user’s machine, which answers the question what those extra digits (called the Instance ID) on the registry access mean.
After a lot of poking around with prototypes, I saw that having two approaches, one a standard registry access for Visual Studio 2015 and prior with a different API-based registry access for Visual Studio 2017, I thought I needed to simplify code that would work with multiple versions. A little trial and error lead me down the route of working with the %HOME%\Documents\Visual Studio <version>\Settings\CurrentSettings.vssettings would be the way I could have a consistent and future proof code base for WintellectPowerShell. Therefore, I tackled the Symbol and Source Server cmdlets with this in mind. With a little testing, I proved it was the way to go for these common settings no matter if you have Visual Studio 2015 Community or Visual Studio 2017 Enterprise. Because I only have Visual Studio 2013 and newer installed on my various computer and virtual machines, I decided to drop support for earlier versions.
After completely rewriting all the symbol and source management cmdlets as well as all the testing for them, I thought I was home free. I next turned to my Remove-IntelliTraceFiles cmdlet, which clears out any extra IntelliTrace files left behind if you have set a the “IntelliTrace\Advanced\Store IntelliTrace recordings into this directory” Options setting, which I highly recommend if you are using Visual Studio Enterprise because that is the only way you have access to those files after you close Visual Studio. But, with the changes to Visual Studio 2017, the IntelliTrace settings are not stored in the CurrentSettings.vssettings file. That seems to only contain the common settings across the different Visual Studio editions. The IntelliTrace settings are stored in the private registry file, which resides at %HOME%\AppData\Local\Microsoft\VisualStudio\15.0_XXXXXXXX\privateregistry.bin. I needed to determine if the Enterprise edition is installed, because this cmdlet only makes sense for that edition, and read that private registry file. While I could have written the private registry access code and the COM Setup Configuration API code in PowerShell, I thought it best to do that work in C#. As you look at the code, you will see a WintellectPowerShellHelper DLL that handles all of this for the WintellectPowerShell module. Check out the DumpVSInstalls test harness as an example of using the new Visual 2017 setup configuration API to show enumerating your installed instances of Visual Studio and all their individual features. The C# wrapper on the COM Setup Configuration API can make consuming the information easier. Feel free to borrow this code for your own tools that need to know about Visual Studio installs.
After dealing with all those changes because of Visual Studio 2017, I thought I was done. Not so fast, because of my Import-VisualStudioEnvironment cmdlet, which sets up a PowerShell instance with the environment variables in the Developer Command Prompt batch files. For those of us command line folks, we need those environment variables in PowerShell, too! There have been major changes to the batch files in Visual Studio 2017. In prior versions, the batch files were relatively simple but now they quite complicated. The new installation scheme in Visual Studio 2017 means you have much more control over what you install, the environment batch files must account for that and bring in the environment variables for whatever the user installed. Basically, the new environment batch files are big plug and play system. Start reading <VS Install Directory>\Common7\Tools\VsDevCmd.bat and you will see that Microsoft has a full-time person just writing batch files. They are some of the most complicated I’ve ever seen. It was not too hard to change my Import-VisualStudioEnvironment cmdlet, but I do feel for the person tasked with debugging those batch files.
That was the bulk of the work on WintellectPowerShell, but I also decided to ensure the code was clean by running PSScriptAnalyzer with all rules enabled. I fixed all the warnings reported, but I had to suppress a few PSUseSingularNouns warnings. The rule states that you should not use plurals in cmdlet names, like Set-Signatures. Because I named these cmdlets long before PSScriptAnalyzer was released, I was worried that someone using WintellectPowerShell in their scripts would break if I changed my cmdlet names. I could have set a config file to ignore this rule, but I want to follow it in the future.
Thanks to all of you that are using WintellectPowerShell. Please report any issues on GitHub and let me know if you need any cmdlets written as I am happy to be your personal PowerShell developer.