When I first heard that macros were being dropped from Dev 11 I was gobsmacked. (I just love that world!) While the macro story up to Visual Studio 2010 wasn’t great because we couldn’t write macros in our .NET language of choice, I expected the situation would start getting better and was saddened when the fix was to remove the easy customizability all together.

People at Microsoft said that the code behind macros was too brittle to update and their telemetry said macros are feature no one was using. My theory is the reason people skipped macros are because you had to do it in a different language. (VB people: I’m not criticizing VB but most of the developers who would write macros are C#/C++ developers). By dropping macros, the argument was that there was still a valid way to extend the development environment with .VSX files. That’s great but like I really want to install an SDK, write a VSX and have Dev 11 debugging Dev 11 just to enumerate my projects and add a new define to debug build configurations.

Readers of this blog know I’ve written many macros (examples here) that make debugging in particular easier. I use my macros on a daily basis so was not looking forward to porting them to an extension and all the junk that entails. As I was navigating the file system using the now built in NuGet Package Manager Console window, why not use PowerShell as the macro language? While this works, I’ll still be pestering Microsoft a lot during the Dev 12 development cycle for a real macro system that lets me program in any .NET language.

To use PowerShell as the macro language, you need access to the Visual Studio automation model. In macros and extensions the root of life is the DTE interface. A quick look at the variables defined in the Package Manager Console shows a $dte variable so once you have that, you’ve got everything! That’s nice when things are easy.

My goal was to port all my macros over to PowerShell and you can see the results of my porting efforts at the bottom of this blog entry. For the most part, it was simply a matter of porting VB to PowerShell, which wasn’t too onerous if you know PowerShell. The main drawback I encountered is that to debug any functions you write you have to use the old PowerShell 1.0 way of debugging with Set-PSDebug and all the fun of command line debugging. It’s a bit painful, but it does work.

There were two areas where I got stumped during the porting. The first was in converting interfaces. When accessing the breakpoints in PowerShell, you use $dte.Debugger.Breakpoints. However, that returns the original IBreakpoints interface defined back in Visual Studio 2003. However, if you want to access the Filterby property, you need the IBreakpoints2 interface defined in Visual Studio 2005. As PowerShell’s COM implementation only works with IDispatch, and not explicit interface members, I was not sure I could get everything to work if I couldn’t convert. Fortunately, the NuGet developers already thought of this and provided the Get-Interface cmdlet that allows easy conversion. The following snippet shows converting an IBreakpoints interface into the IBreakpoints2 interface.

  1. Get-Interface $dte.Debugger.Breakpoints[0] ([ENVDTE80.Breakpoint2])

The second problem in porting I encountered was trying to use a Visual Studio method like $dte.Breakpoints.Add, which takes many optional and conflicting parameters. That’s easy to do in VB, but PowerShell sort of likes you to use all the parameters to a COM method. A bit of careful web searching lead me to a great solution by Jason Archer where he uses some seriously ninja PowerShell tricks to solve the problem. If you want to learn some advanced PowerShell, look at Invoke-NamedParameter function.

By using the Package Manager Console, I thought packaging up my cmdlets as a NuGet package would be the way to go. The only problem is that a NuGet package is designed to be used with a solution, which is the correct approach, but I wanted my cmdlets to be available at all times. To that end I chose to go with a PowerShell module, which works just fine with the Package Manager Console.

You can put the files in the download anywhere you want, but if you would like to include them in the module path, use Install-Module.PS1 to do the installation.

It looks like there’s a bug in the NuGet Package Manager Console because the $ENV:PSModulePath does not include the normal user’s documents directory in the default path. Consequently, to run Install-Module.PS1 you will need to run Dev 11 elevated to do the installation as the NuGet modules directory is in Program Files.

If you’re still using Visual Studio 2010 and you want to try out my cmdlets, please do as they all work provided you installed NuGet. If you have any questions or ideas for other macros, please don’t hesitate to let me know.

Download WintellectVSCmdlets.

  1. TOPIC
  2.     about_WintellectVSCmdlets
  4.     Provides missing functionality, especially around debugging, to Visual Studio 2010 and Dev 11.
  6.     This describes the basic commands included in the WintellectVSCmdlets module. With Dev 11 not offering
  7.     macros, simple extensions require installing an SDK and debugging the extensions with a second instance
  8.     of the IDE. In all, it makes for a very poor experience when you want to do simple customization of the
  9.     the development environment.
  10.     These macros, which are very useful for debugging, demostrate that the NuGet Package Console is
  11.     sufficient for many of your customization needs. Most of these cmdlets are ports of VB.NET macros that
  12.     John Robbins has shown on his blog and books.
  13.     All cmdlets work with both Visual Studio 2010 and Dev 11.
  14.     Note that these cmdlets support C#, VB, and native C++. They probably support more but those were
  15.     all the languages tested.
  16.     If you have any questions, suggestions, or bug reports, please contact John at [email protected].
  17.     The following Wintellect VS cmdlets are included.
  18.         Cmdlet                                            Description
  19.         ——————                                ———————————————-
  20.         Add-BreakpointsOnAllDocMethods                  Sets breakpoints on methods in the current code document. This
  21.                                                         is very useful in .NET languages as the debugger expression
  22.                                                         evaluator does not support that.
  23.         Remove-BreakpointsOnAllDocMethods               Removes all the breakpoints set with Add-BreakpointsOnAllDocMethods.
  24.                                                         This cmdlet will not remove any of your breakpoints.
  25.         Add-InterestingThreadFilterToBreakpoints        Adds the filter “ThreadName==InterestingThread” to all breakpoints to
  26.                                                         make it easier to debug through a single transaction.
  27.         Remove-InterestingThreadFilterFromBreakpoints   Removes the “ThreadName==InterestingThread” filter applied with
  28.                                                         Add-InterestingThreadFilterToBreakpoints.
  29.         Disable-NonActiveThreads                        Freezes all but the active thread so you can single step to the end
  30.                                                         of a method without dramatically bouncing to another thread when you
  31.                                                         least expect it.
  32.         Resume-NonActiveThreads                         Thaws all threads previously frozen with Disable-NonActiveThreads.
  33.         Get-Breakpoints                                 Returns the latest version of the IBreakpoints derived list.
  34.         Get-Threads                                     Returns all the threads.
  35.         Invoke-NamedParameter                           A wonderful cmdlet that lets you easily call methods with many
  36.                                                         optional parameters. Full credit to Jason Archer for this cmdlet.
  37.         Invoke-WinDBG                                   VS/Dev 11 have ease of use, where WinDBG (with SOS + SOSEX) have
  38.                                                         tons of power to tell you what’s going on in your application. This
  39.                                                         cmdlet starts WinDBG on the process you’re currently debugging in the
  40.                                                         IDE so you can have the best of both worlds.
  41.         Open-LastIntelliTraceRecording                  When you stop debugging, your current IntelliTrace log disappears. This
  42.                                                         cmdlet fixes that by opening the last log you produced so you can post-mortem
  43.                                                         look at your debugging session.
  44. SEE ALSO
  45.     Online help and updates: https://training.atmosera.com/CS/blogs/jrobbins/default.aspx
  46.     Add-BreakpointsOnAllDocMethods
  47.     Remove-BreakpointsOnAllDocMethods
  48.     Add-InterestingThreadFilterToBreakpoints
  49.     Remove-InterestingThreadFilterFromBreakpoints
  50.     Disable-NonActiveThreads
  51.     Resume-NonActiveThreads
  52.     Get-Breakpoints
  53.     Get-Threads
  54.     Invoke-NamedParameter
  55.     Invoke-WinDBG
  56.     Open-LastIntelliTraceRecording