John Robbins' Blog

Using NuGet PowerShell to Replace Missing Macros in Dev 11

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

Comments (13)

  1. Have you seen studioshell from codeowls ? it's opensource automation for VS. The 5 minute demos are very impressive.

  2. Dan,

    Sadly, there is not a way that I know of to bind these to keystrokes.

    Don't get me started on the missing simple extensiblity in VS 2012. Grrr.

    - John Robbins

  3. WTF? No more macros? Because "telemetry" says no one uses them? But how many programmers turn off telemetry the first time they start using Visual Studio? (Me, for example, and many of my colleagues) And how many programmers must work in virtual machines disconnected from the Internet, where no telemetry is possible?

  4. For creating shortcut keys you can try this: http://www.codewrecks.com/blog/index.php/2012/08/24/converting-visual-studio-macro-to-visual-studio-plugin/

  5. Nice article.
    I am writing some Cmdlet too.
    How do you debug the Cmdlet w/ NuGet as the host?
    is the Write-Host the only way to debug it?

    Thanks

  6. In your excellent book "Debugging Microsoft .NET 2.0 Applications", pages 216-219, you describe cool advanced debugging techniques with Tracepoints that can call macros. Now, in VS2012, Tracepoints can only write messages, they cannot call macros because, of course, macros do not exist any longer. And here you cannot use the Powershell trick. :(

  7. In your post I see you mention adding break points, is there any sample you have for adding a break point and when that break point is hit to run some code and then return to executing?
    I.E. Something like you use to be able to do with a macro executing when a breakpoint was hit. thanks

  8. Hi John, I hope you're well!
    Here's a quick trick I just used for basic macros that add keys into the editor. I have a whole bunch of keyboard shortcuts that insert code into the editor. (At least I used to with earlier versions of VS.) When I press Ctrl+Shift+Enter, it inserts two curly braces with a blank line between them, and positions the cursor in the middle. With no more macros, I found a standalone Windows app called autohotkey (google it). I added this macro. (Hopefully the comment mechanism will get all these characters right. If not, the docs explain it pretty well.)
    ^+Enter::Send {{}{enter}{}}{Up}{End}{enter}
    And one benefit is now I can use this across all my editors. But important note to save pulling your hair out: Run autohotkeys with administrator privs, otherwise it won't be able to communicate with apps running as admin.

  9. A tip for debugging PowerShell scripts in the NuGet console. This NuGet package:

    https://www.nuget.org/packages/NuGetDebugTools/

    provides a simple an yet effective script debugger. With this tool I can debug NuGet specific scripts and scripts used for Visual Studio automation. It is minimalistic, somewhat similar to Microsoft console host debugger, but it provides all necessary debugging features.

    --
    Roman

  10. A tip for debugging PowerShell scripts in the NuGet console. This NuGet package:

    https://www.nuget.org/packages/NuGetDebugTools/

    provides a simple an yet effective script debugger. With this tool I can debug NuGet specific scripts and scripts used for Visual Studio automation. It is minimalistic, somewhat similar to Microsoft console host debugger, but it provides all necessary debugging features.

    --
    Roman

Leave a Comment

Archives

Tags