SharePoint 2010 Deployment script using Powershell

For a project I was working on last month, I needed a way to deploy SharePoint 2010 solutions in a controlled manner.
Thanks to Gary Lapointe I was quickly up to speed to create my first Powershell Script. The script he provided in his post makes it possible to deploy solutions using a xml configuration file. But I needed a script that activates the features as well, so I extended Gary’s script.

solutions.xml

<Solutions>
<Solution Path=”[[Solution1.wsp]]” CASPolicies=”false” GACDeployment=”true”>
<WebApplications>
<WebApplication Url=”[[URL]]:8080″>
<Feature Name=”1116af9b-e3b5-498e-9706-1b67b7b60c43″ Url=”[[URL]]” />
<Feature Name=”2220d8aa-2d25-47bb-8d44-29a45caaa4ce” Url=”[[URL]]” />
<Feature Name=”3330364b-e879-4fee-b103-3c3dd10c0a1c” Url=”[[URL]]” />
<Feature Name=”444a36e0-d249-469a-ba46-4ca7baa10ea6″ Url=”[[URL]]” />
</WebApplication>
</WebApplications>
</Solution>
<Solution Path=”[[Solution2.wsp]]” CASPolicies=”false” GACDeployment=”true”>
<WebApplications>
<WebApplication Url=”[[URL]]”>
<Feature Name=”Feature1″ Url=”[[URL]]” />
</WebApplication>
</WebApplications>
</Solution>
</Solutions>

Deplopy.ps1

$solutionfile = “solutions.xml”

if ( (Get-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null )
{
Add-PSSnapin Microsoft.SharePoint.PowerShell
}

function Install-Solutions([string]$configFile)
{
if ([string]::IsNullOrEmpty($configFile)) { return }

$solutionsConfig = Get-Content $configFile
if ($solutionsConfig -eq $null) { return }

$solutionsConfig.Solutions.Solution | ForEach-Object {

$_.WebApplications.WebApplication | ForEach-Object {
Write-Host $_.Url
$_.Feature | ForEach-Object {
Write-Host $_.Name
[string]$name = $_.Name
[string]$url = $_.Url
Write-Host Deactivate-Feature $name $url
Deactivate-Feature $name $url
}
}

[string]$path = $_.Path
[bool]$gac = [bool]::Parse($_.GACDeployment)
[bool]$cas = [bool]::Parse($_.CASPolicies)
$webApps = $_.WebApplications.WebApplication
Write-Host Install-Solution $path $gac $cas $webApps.Url
Install-Solution $path $gac $cas $webApps.Url

$_.WebApplications.WebApplication | ForEach-Object {
$_.Feature | ForEach-Object {
[string]$name = $_.Name
[string]$url = $_.Url
Activate-Feature $name $url
}
}
}
}

function Deactivate-Feature([string]$featurename, [string]$url)
{
#Check for Sitecollection-scoped feature
$feature = Get-SPFeature $featurename -Site $url -ErrorAction SilentlyContinue
if ($feature -eq $null) {
#Check for Web-scoped feature
$feature = Get-SPFeature $featurename -Web $url -ErrorAction SilentlyContinue
}

if ($feature -ne $null) {
Write-Host Disable-SPFeature -Identity $featurename -Url $url
Disable-SPFeature -Identity $featurename -Url $url -Confirm:$false
}

}

function Activate-Feature([string]$featurename, [string]$url)
{
$feature = Get-SPFeature $featurename -ErrorAction SilentlyContinue
if ($feature -ne $null) {
Write-Host Enable-SPFeature -Identity $featurename -Url $url
Enable-SPFeature -Identity $featurename -Url $url
}
}

function Install-Solution([string]$path, [bool]$gac, [bool]$cas, [string[]]$webApps = @())
{
$spAdminServiceName = “SPAdminV4″

[string]$name = Split-Path -Path $path -Leaf
$solution = Get-SPSolution $name -ErrorAction SilentlyContinue

if ($solution -ne $null) {
#Retract the solution
if ($solution.Deployed) {
Write-Host “Retracting solution $name…”
if ($solution.ContainsWebApplicationResource) {
$solution | Uninstall-SPSolution -AllWebApplications -Confirm:$false
} else {
$solution | Uninstall-SPSolution -Confirm:$false
}
Stop-Service -Name $spAdminServiceName
Start-SPAdminJob -Verbose
Start-Service -Name $spAdminServiceName

#Block until we’re sure the solution is no longer deployed.
do { Start-Sleep 2 } while ((Get-SPSolution $name).Deployed)
}

#Delete the solution
Write-Host “Removing solution $name…”
Get-SPSolution $name | Remove-SPSolution -Confirm:$false
}

#Add the solution
Write-Host “Adding solution $name…”
$solution = Add-SPSolution $path

#Deploy the solution
if (!$solution.ContainsWebApplicationResource) {
Write-Host “Deploying solution $name to the Farm…”
$solution | Install-SPSolution -GACDeployment:$gac -CASPolicies:$cas -Confirm:$false
} else {
if ($webApps -eq $null -or $webApps.Length -eq 0) {
Write-Warning “The solution $name contains web application resources but no web applications were specified to deploy to.”
return
}
$webApps | ForEach-Object {
Write-Host “Deploying solution $name to $_…”
$solution | Install-SPSolution -GACDeployment:$gac -CASPolicies:$cas -WebApplication $_ -Confirm:$false
}
}
Stop-Service -Name $spAdminServiceName
Start-SPAdminJob -Verbose
Start-Service -Name $spAdminServiceName

#Block until we’re sure the solution is deployed.
do { Start-Sleep 2 } while (!((Get-SPSolution $name).Deployed))
}

function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}

Install-Solutions($solutionfile);