One of the projects that I'm working on at the moment involves deploying the same code base (Features, DLL etc) to a number of different site collections on my development vm. However, one of the aspects of Visual Studio 2010 it that it will only deploy to a single site - which you specify in the project settings. In this case it's a pain because certain elements of the Features require activation which only happens on that one site. If I deploy my latest code to http://site1 then everything is good, but then http://site2 and http://site3 have a mix of old and new (e.g. they'll have the latest DLL which are in the GAC but not necessarily page layouts, css etc). At the moment it means I have to go through each site and manually deactivate and then activate each Feature by hand. SharePoint deployments aren't always the quickest and this just adds extra delays which isn't very helpful.
Fortunately the deployment process through Visual Studio, especially for SharePoint projects, is extremely extensible which means you can control what happens when a deployment it done. There a couple of different out of the deployment configurations, for example Default and No Activation. Both will deploy Features to the site in the same way, except Default will also activate it. You can extend these and even write your own actions and if you install something like the CKSDev toolkit you can get some extra deployment configurations like Quick Deploy, Upgrade Solution etc which can be helpful. Another option is tying custom commands, like PowerShell which is what I'm using here.
In my case I want Visual Studio to deactivate/activate my Feature on a number of different sites, which can all be achieved through PowerShell and the standard commands that come with SharePoint. Broadly speaking I want Visual Studio to do the following:
- Compile, package and Deploy my Feature as normal
- Then loop through my sites and deactivate (if required) and activate
Everything in step 1 is done automatically by Visual Studio the only thing I'm changing is to switch the 'Active Deployment Configuration' to 'No Activation'. You don't have to, but I'd prefer having all my sites handled by the same script. So in this case, Visual Studio is only going to deploy my Feature, without activating it. For step 2 there are two parts which need changing. Firstly we have to create a PowerShell file which contains our scripts and secondly we have to amend the 'Post-deployment Command Line' which calls our custom script.
The PowerShell
For this, I just create a ps1 file at the root of my project (you can put it anywhere within the project structure). Since I only want this file to be used in Visual Studio I'm keeping the 'Copy to Output Directory' set to 'Do not copy'so it shouldn't be included in builds. This is the content of my file:
write-output "Running post-deployment scripts" $snapin = get-pssnapin | where { $_.Name -eq "Microsoft.SharePoint.PowerShell" }
if($snapin -eq $null)
{
Add-PsSnapin Microsoft.SharePoint.PowerShell
}
$featureId = new-object System.Guid("00000000-0000-0000-0000-000000000000")
$deployableSites = "http://site1","http://site2","http://site3"
foreach($webUrl in $deployableSites)
{
$site = get-spsite $webUrl
$solution = $site.Features | where {$_.DefinitionId -eq $featureId}
if ($solution)
{
write-output "Disabling Feature for $webUrl"
disable-spfeature $featureId -url $webUrl -Confirm:$false
}
#Enable Feature
write-output "Enabling Feature for $webUrl"
enable-spfeature $featureId -url $webUrl }
The script it fairly straight-forward -
- Firstly we need to pull in the SharePoint PowerShell snapin
- Define the Feature Id and sites to deploy to
- Then loop through each site, checking if it is currently available deactivate it and then activate it
You can write your script to do pretty much whatever you need it to – as long as you can write the script!
The Post-Deployment Command Line
With SharePoint we can right-click on a project, which brings up the Properties and we can head to the SharePoint tab which gives us the option to run commands both pre and post deployment. Typically this takes command line so we need to call out to PowerShell. The thing is, it's not just a case of calling out to PowerShell because of the whole 32 vs 64bit software. SharePoint as you know is 64bit, which is required for its PowerShell commands, however Visual Studio is still 32bit and so by default will call the 32bit version of PowerShell. If you try loading the SharePoint snapin in 32bit PowerShell you'll get this error:
Add-PSSnapin : The Windows PowerShell snap-in 'Microsoft.SharePoint.PowerShell' is not installed on this machine.
So instead, we need to tell Visual Studio to load the 64bit PowerShell instead which we can by referencing:
%windir%\sysnative\windowspowershell\v1.0\powershell
Now it's simply a case of passing in our deployment script we created before and deploying!
So the final command line is:
%windir%\sysnative\windowspowershell\v1.0\powershell -file "$(ProjectDir)PSDeploy.ps1"
Further options
This is just a simple example of how how we can incorporate PowerShell into a deployment process in Visual Studio to roll out our Features to multiple sites. Of couse the same approach can be used in Pre-deployment and also pre and post builds. So depending on when you need scripts to run you can place them where their needed.