StudioShell at Charleston Alt.Net

§ March 7, 2011 05:34 by beefarino |

imageI’ll be giving a 75 minute talk on StudioShell at the March 2011 meeting of Charleston ALT.NET in Charleston, SC. 

The plan is to give about 10 minutes of overview material and an hour of demos and code walkthroughs.

Planned demos include:

  • custom code factories;
  • deeply integrating external tools into the IDE;
  • event-driven scripting;
  • leveraging existing PowerShell features and modules;
  • profile scripts and solution modules;

If you’re in the Charleston or surrounding areas, please come out, support your local user group, and learn how StudioShell brings the awesome when you need it most!

For event details, please see the Charleston ALT.NET event page.

Access Window Configurations with StudioShell

§ March 4, 2011 04:11 by beefarino |

funkywindowsOne feature of the Visual Studio SDK that isn’t available in the standard IDE interface is Window Configurations.  Visual Studio can remember where all of your windows are located and recall their visibility and positioning at your whim.

StudioShell exposes this as a first-class feature on the DTE: drive.  You can view the list of defined window configurations using the get-childitems cmdlet:

> get-childitems dte:/windowConfigurations Location: PSDTE::dte:\windowconfigurations Available Operations: d+ < Name ---------- ---- ~<> i Design ~<> i Debug ~<> i NoToolWin

Adding a new named window configuration to this list is easy.  First, arrange your windows exactly as you want them to appear.  Second, type this command at the StudioShell prompt:

> new-item dte:/windowConfigurations -name MyConfig Location: PSDTE::dte:\windowConfigurations Available Operations: d+ < Name ---------- ---- MyConfig

There, now you have a named window configuration.  If you ever want your IDE windows to bounce back to their MyConfig locations, just type this:

>invoke-item dte:/windowConfigurations/MyConfig

The windows will arrange themselves back to the configuration you specified.

Here Comes the Awesome

I use a laptop all the time (except when gaming).  At my home office I like to dock the laptop and make use of two large monitors.  In this mode, I like to have Visual Studio tool windows, like the output window, errors, etc, shoved off to a second monitor.  Unfortunately undocking the laptop when I’m in this configuration wreaks havoc with Visual Studio and sends my windows into a swarm of window soup.

No more.

I defined two window configurations: one named “DockedLaptop” where all of my tool windows are on my second monitor, and one named “UndockedLaptop”, where most of my tool windows are hidden.  Works great on-demand.

On-demand is nice.  Automatic is better.

Since StudioShell is just PowerShell, and since PowerShell gives us access to tons of great administrative widgets, we can arrange our windows in response to system events.  I found a little WMI snippet that watches the registry for dock/undock state changes using WMI, and since I can hook into Visual Studio’s IDE now, putting the two together was simple (the original dock/undock code can be found here):

1 function invoke-DockStateWindowChange() 2 { 3 $state = get-itemproperty 'hklm:/system/currentControlSet/control/idConfigDB/currentDockInfo' -name DockingState; 4 $configName = "UndockedLaptop"; 5 if( 1 -eq $state.DockingState ) 6 { 7 $config = "DockedLaptop"; 8 } 9 10 invoke-item "dte:/windowConfigurations/$config"; 11 } 12 13 register-wmievent -action {invoke-DockStateWindowChange} -query @" 14 Select * from RegistryValueChangeEvent WITHIN 1 WHERE 15 Hive='HKEY_LOCAL_MACHINE' AND 16 KeyPath='SYSTEM\\CurrentControlSet\\Control\\IDConfigDB\\CurrentDockInfo' AND 17 ValueName='DockingState' 18 "@ ;

The code looks a bit messy because of the WMI query, but the logic is quite simple.  The invoke-DockStateWindowChange function checks the registry for a value indicating the docking state of my laptop.  Depending on this value, one of two window configurations is invoked. 

The rest is hooking into WMI to monitor the registry for changes.  When the docking state changes, the registry is updated, the WMI event is raised, my function is called, and my windows arrange themselves the way I want them to be.

Dropped the code into my StudioShell profile script (you can find yours at ~/documents/codeowlsllc.studioshell/profile.ps1), and it just works.  Now whenever I dock or undock, my windows end up where I want them instead of where they happen to land.


I know the WMI registry event trick doesn’t work for some laptop docks – late-model Dells in particular.  As an alternative the code below taps into the power source change events, which isn’t as nice – you can’t tell what power source is being used, but at least you can always fallback your IDE windows to a safe configuration when your docking state changes.

1 function invoke-DockStateWindowChange() 2 { 3 invoke-item "dte:/windowConfigurations/undockedLaptop"; 4 } 5 6 register-wmievent -action {invoke-DockStateWindowChange} -class win32_powermanagementevent

So, how will StudioShell add awesome to your daily development life?

Overview of StudioShell Solution Modules

§ March 2, 2011 08:38 by beefarino |

solutionmoduleOne of the most hidden features of StudioShell is also one of the most useful: Solution Modules.

If you don’t already know, modules are PowerShell’s way of packaging functionality into reusable units.  For instance, the PSake build automation tool is a module.  From your PowerShell session, you yank in the PSake module as a single unit using the import-module cmdlet.  When you’re done, you can remove the PSake module from your PowerShell session using the remove-module cmdlet.

Solution Modules are the same idea.  The only difference is that a solution module lives inside of your Visual Studio solution, with your code.  StudioShell automatically recognizes these modules and imports them when the solution is loaded.  When the solution is closed, the module is removed.  This makes Solution Modules a perfect way to pack your Visual Studio modifications with your solution.

Quick Example

If you haven’t already, install StudioShell

Start Visual Studio and create a new empty solution.  Name it “ModuleSolutionExample”.

Add a new test file as a solution item, name it ModuleSolutionExample.psm1.  Your solution explorer window should look like this:


Double-click the ModuleSolutionExample.psm1 file to open it in the Visual Studio editor.  Type in the following PowerShell code (without the line numbers):

1 "Loading Solution Module" | out-outputpane; 2 3 $m = $MyInvocation.MyCommand.ScriptBlock.Module; 4 $m.OnRemove = { 5 "Unloading Solution Module" | out-outputpane; 6 }

Save the file.  Close the solution.

Now open the StudioShell console and output window from the View menu.

With the output pane displayed, re-open the ModuleSolutionExample from your File > Recent Projects and Solutions menu.  You will see “Loading Solution Module” appear in the output window as the solution is being loaded:


Now close the solution.  The string “Unloading Solution Module” will appear as the solution is unloaded [1].


StudioShell has a few requirements for a solution module:

  1. the file must have a .psm1 (script module) or .psd1 (module definition file) extension;
  2. the file name must match the name of the solution;
  3. the file must reside in the same file system location as the .sln solution file.

Outside of that, the sky’s the limit.

A Detailed Example

The script module below should give you some idea of what’s possible.  This is part of a solution module I use for a project that builds using PSake.  The solution module modifies my build menu and adds a Build With PSake menu item to the build menu, and assigns it a key binding of CTRL+SHIFT+P:

1 import-module psake; 2 3 # mount the file system location of the solution 4 function mount-solutionFolder() 5 { 6 $path = ( get-item dte:/solution ).fullName; 7 $path | split-path | pushd; 8 } 9 10 # run psake, dump output to console 11 function start-psakeBuild() 12 { 13 mount-solutionFolder; 14 invoke-psake | out-host; 15 write-prompt; 16 popd; 17 } 18 19 # add a psake build item to the build menu 20 new-item commandbars:/menubar/build -name "PSake Build" -value { 21 start-psakeBuild 22 } -binding "CTRL+SHIFT+P"; 23 24 $MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { 25 if( test-path "commandbars:/menubar/build/PSake Build" ) 26 { 27 remove-item "commandbars:/menubar/build/PSake Build" 28 } 29 }

So, solution modules provide a great way to package StudioShell scripts you use for a solution with the solution itself.  Altering the build process, customizing the PowerShell session with custom functions, modifying the IDE, folding in outside tools, whatever you can think of… 

And the best part is that the scripts travel with the solution itself, keeping your tools close to your code.


[1] The scripts in the installer at the time this post was written contain a bug that prevent solution modules from unloading.  The TIP of the repository contains the fix.