StudioShell.DependencyExample Nuget Package

§ February 13, 2014 17:49 by beefarino |

As promised, I’ve pushed a simple example of using StudioShell.Provider as a Nuget package dependency.  You can pull the StudioShell.DependencyExample for the code.  At the moment this package does one thing – it adds a Solution Module to your current solution if one is not already present.

Let’s take a closer look at what this package actually does and how it does it…

The Nuspec File

Inside of the StudioShell.DependencyExample nuspec file, I’ve listed StudioShell.Provider as a dependency package:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <id>StudioShell.DependencyExample</id>
    <version>1.0</version>
    <authors>beefarino</authors>
    <owners>beefarino</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>A simple demonstration of using StudioShell.Provider automation features from your Nuget packages</description>
    <tags>VisualStudio StudioShell DTE automation nuget</tags>
    <dependencies>
      <dependency id="StudioShell.Provider" version="1.6.2" />
    </dependencies>
  </metadata>
</package>

This ensures that the StudioShell PSDTE provider is loaded into the package manager console session before installing my example package.  This will allows me to leverage the DTE drive from my package scripts.

The Init.ps1 File

The init.ps1 files makes use of the DTE drive to spelunker the solution, project items, and folders.

The first few lines of the init.ps1 file get the currently open Visual Studio solution.  The $slnName variable is set to the “name” of the solution, which is determined as the filename without the .sln extension.  The $modulePath variable is set to the location of the solution module for this solution. 

#
#   Copyright (c) 2014 Code Owls LLC, All Rights Reserved.
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
param($installPath, $toolsPath, $package, $project)

# add a new StudioShell solution module to the solution if one does not already exist

$sln = get-item dte:/solution;
$slnName = ( $sln.FullName | split-path -leaf ) -replace '\..+$','';
$modulePath = $sln.FullName -replace '\.sln$','.psm1';
#...

Next we check if a solution module does not already exist at this path; if we find one, we simply return out of the script:

#...
if( test-path $modulePath )    
{
  return;
}
#...

And if no solution file exists, we go ahead and create one using a little powershell here-string magic:

#...
@"
# Example StudioShell solution module for ${slnName}
# 

`$menuItems = @(
    # list any menu items your module adds here
    #
    # e.g.:
    new-item 'dte:/commandbars/menu bar/help' `
	 -name 'about my module' `
	-value { 'Module ${slnName}' | `
    out-outputpane; invoke-item dte:/windows/output; }
);

# this function is called automatically when your solution is unloaded
function unregister-${slnName}
{
    # remove any added menu items;
    `$menuItems | remove-item;
}
"@ | out-file -filepath $modulePath;
#...

Once the solution module file is created, we add it to the current solution items.  First we create a Solution Items folder if one does not yet exist:

#...
#create a solution items project folder if necessary
if( -not ( test-path 'dte:/solution/projects/solution items' ) )
{
    new-item -path 'dte:/solution/projects/solution items' -type folder;
}
#...

After we ensure we have a Solution Items folder, we simply add the existing file to it:

#...
#add the solution module to the solution items project folder
new-item -path 'dte:/solution/projects/solution items' -filepath $modulePath;

Looking Ahead

I’ll keep updating the StudioShell.DependencyExample package as I find new and interesting things to do with StudioShell and Nuget.  If you come up with your own, please let me know about them!



StudioShell 1.6.2 is all About Better Nuget Support

§ February 13, 2014 16:40 by beefarino |

ssnugetI just pushed a point release of StudioShell.  It contains a few fixes related to autocomplete, but the majority of the code changes are related to being able to easily leverage the DTE drive from Nuget packages and the Package Manager console in Visual Studio.

Up until this point, you had to install the entire StudioShell environment to be able to use its features from the Package Manager console.  This was problematic because the full install for StudioShell is not straightforward or simple, and most of the install-related issues reported for the project stemmed from people trying to leverage it from the Package Manager console.

This latest release remedies this by breaking the StudioShell project into two unique distributions:

  1. StudioShell: the complete StudioShell environment;
  2. StudioShell.Provider: the StudioShell DTE PowerShell provider.

Here’s a breakdown of how the features between the two distributions differ:

Feature StudioShell StudioShell.Provider
DTE Drive

*

*

Solution Modules

*

*

Custom Scripted Menu Items

*

*

Data Panes & Visualizations

*

 
Custom Host Settings

*

 
Custom Profile Scripts

*

 
Custom Console

*

 

In a nutshell, StudioShell.Provider isolates the main gem of StudioShell automation – the PSDTE PowerShell provider.  The host-level features, such as visualizations and the custom StudioShell profile script, are only available in the full StudioShell install.

The reason I’m doing this is simple: I want people to be able to use StudioShell in their Nuget packages to manipulate Visual Studio.  I’m working on a simple demonstration package that will show off a bit of what you’ll be able to do from your Nuget packages if you add a dependcy on StudioShell.Provider and will publish it as soon as it’s ready.



StudioShell 1.6 Supports VS 2013

§ January 28, 2014 23:18 by beefarino |

ohaiGreat news for StudioShell lovers…

This evening I pushed a new build of StudioShell that includes support for Visual Studio 2013.  The new build is available through the usual channels:

  • Download the installer from CodePlex
  • Install using NuGet or Chocolately
  • Clone the code and invoke the install psake task:
hg clone  https://hg.codeplex.com/studioshell
cd studioshell
import-module psake
invoke-psake install

As always, report any issues or requests using the Issue Tracker.

Happy coding!



Manipulating the AppDomain of your PowerShell Session

§ January 17, 2014 15:21 by beefarino |

imageEarlier this week I pushed a new project to my public github repositories.  This project contains a PowerShell module that enables you to change the active configuration of the appdomain that is hosting your PowerShell session.  I’ve been asked a lot of questions about what this does exactly, and why someone would want to use it.  This goal of this post is to clarify the scenario where this is useful.

TL;DR: if you have to ask, you don’t need it.

Let’s say you want to use a .NET library that relies on one or more settings in the application configuration file.  Like what?  Well, let’s say you need to add a connection string to the appdomain configuration to get a library that uses Entity Framework to work correctly.   In fact, that’s where this project came from – I needed a way to manipulate connection strings in the app domain configuration to get Entity Shell to work properly.

In order to leverage such a library from PowerShell, you’ll need to modify the application configuration file for the PowerShell application, which is really bad form.  Seriously.  Don’t do that.  That file isn’t for you.  Stop touching it.  Sit on your hands if you have to.

Another alternative is to make a copy of the entire PowerShell application, with its own configuration file, and then edit the copy.  That’s silly.  Seriously.  Don’t do that.  No one wants multiple copies of the same application laying about.  No one I say!  So just remove-item –recurse –force all those duplicate powershell.exe applications, okay? 

And yet another alternative – and this was my preferred path until recently – was to use a tool called poshrunner from friend and coastal neighbor Justin Dearing.  This little gem would help you spool up a new app domain using a specific configuration file, so a script could take advantage of the new configuration.  I still like this approach, and it works really well as long as you’re willing to plan ahead a little bit.  Which I’m not.  I tend to find myself in a PowerShell session filled with state and variables that I want to keep using.  Poshrunner was hard to fit into this gambitesque workflow.

So I found an alternative way.  A way you can manipulate app settings and connection strings for the active PowerShell session.  Here’s an example using this new module to configure a connection string in the active PowerShell session:

> import-module appDomainConfig
> add-connectionString -name 'UserGroupContext' `
  -provider 'System.Data.SqlClient' `
  -connectionstring 'Data Source=.\SQLExpress;Initial Catalog=SuperAwesomeWebsite.Models.UserGroupContext;Integrated Security=True'

Name                    : UserGroupContext
ConnectionString        : Data Source=.\SQLExpress;Initial ...
ProviderName            : System.Data.SqlClient
LockAttributes          : {}
LockAllAttributesExcept : {}
LockElements            : {}
LockAllElementsExcept   : {}
LockItem                : False
ElementInformation      : System.Configuration.ElementInformation
CurrentConfiguration    :

Pretty simple, eh?  No fuss, it just works.  Your PowerShell session isn’t disrupted, and the configuration change sticks for the remainder of your session without being persisted to any file. 

So far the module supports adding, getting, and removing app settings and configuration strings.  More features may be added if I find I need them (or you can send a pull request with your own changes).

How it Works

It cheats. 

Well sort of.  It uses .NET reflection to manipulate the configuration type private members and gain write access to the configuration bits for the current app domain.

Isn’t that dangerous?  I guess.  Well, I mean, in the grand scheme of things, this is a pretty safe thing to do.  We’re not naked soaring on a flaming hang-glider over sharks-with-lasers-infested waters during an air-to-air battle with zombie-piloted Messerschmitts.  You might be able to muss up your app domain configuration, but I haven’t crashed the process yet.

Isn’t that fragile?  I guess.  Well, I mean, that API has been around for a long time.  And this is a technique I’ve been using for about 8 years now.  And it still works.  And if it stops working then I suppose I’ll take another look at it.  I mean, how fragile could it be?  “The code’s only been working for EIGHT years!”

Isn’t that bad practice?  I guess.  Well, I mean, I personally think the configuration API should have a programmatic interface as well as the XML one.  That’s the bad practice in my mind.  I’m just taking corrective measures so I can use it the way I need to use it to get my work done.

Isn’t that …. Look, if this sort of thing leaves a bad taste in your mouth, then please offer an acceptable alternative.

In the meantime, I would suggest you give the module a whirl if you think it would help you.