Automating SharePoint Deployments (aka Continuous Integration) by PowerShell

SharePoint has an infrastructure for packaging, deploying, and upgrading with its own meta language (XAML), but often our requirements during deployment and maintenance goes beyond what’s possible in SharePoint’s out-of-the-box IMHO it’s the case with every software that provides such facilities. Fortunately SharePoint relies on PowerShell, a scripting language meant for automating administrative tasks. Since I’m a fan of good tools that let us get rid of non-creative tasks, long ago I decided to build an extendable script that can take care of main scenarios and also takes care of common pitfalls along the way.

The script uses a clean and understandable XML file to let you control the process without modifying the code. The XML file consists of 3 main segments BeforeDeploy, Deploy and AfterDeploy. You just need to put tasks inside these main nodes in whatever order you like and if the script does not understand a task it simply ignores it. This gives you the possibility to use the same XML file for your other configurations without any need to create a separate one. Let’s look at an example.

<Deployment>
  <BeforeDeploy>
    <Provision>
      <Website Description="Home" Template="CMSPUBLISHING#0" Title="Home" Url="http://dev/myapp/en/home"/>
      <Website Description="Products" Template="CMSPUBLISHING#0" Title="Products" Url="http://dev/epro/en/products"/>
      <Website Description="Support" Template="CMSPUBLISHING#0" Title="Support" Url="http://dev/epro/en/support"/>
    </Provision>
    <Features>
      <deactivate Description="MyApp.Support.Pages" Id="2aa7ea41-6b01-45d4-87e0-a8194ea246fb" Url="http://dev/myapp/en/support"/>
      <activate Description="MyApp.Products.Pages" Id="2aa7ea41-6b01-45d4-87e0-a8194ea246fb" Url="http://dev/myapp/en/products"/>
      <deactivate Description="MyApp.Home.Pages" Id="2aa7ea41-6b01-45d4-87e0-a8194ea246fb" Url="http://dev/myapp/en/home"/>
      <deactivate Description="MyApp.PageLayouts" Id="f21423d1-0052-456f-b727-aa7268fa4e52" Url="http://dev/myapp"/>
      <deactivate Description="MyApp.ContentTypes" Id="807d55b5-77fc-423c-bae3-aedd861a96c4" Url="http://dev/myapp"/>
      <deactivate Description="MyApp.SessionSharing" Id="93a36eb1-5948-44ed-82a4-642bc1a4132b" Url="http://dev/"/>
      <deactivate Description="MyApp.UrlRewrite" Id="1f8cdfca-c7a6-4f11-8520-b02459b79479" Url="http://dev/"/>
      <deactivate Description="MyApp.BCS" Id="4d3288a9-ce52-4a0e-af83-b0ff78e1d40e"/>
    </Features>
  </BeforeDeploy>
  <Deploy>
    <Solutions>
      <Solution Force="true" Path="C:\CODE\MyApp\Package\MyApp.wsp" UpgradeExisting="false">
        <WebApplications>
          <WebApplication>http://dev/</WebApplication>
        </WebApplications>
      </Solution>
    </Solutions>
  </Deploy>
  <AfterDeploy>
    <Features>
      <activate Description="MyApp.BCS" Id="4d3288a9-ce52-4a0e-af83-b0ff78e1d40e"/>
      <activate Description="MyApp.UrlRewrite" Id="1f8cdfca-c7a6-4f11-8520-b02459b79479" Url="http://dev/"/>
      <activate Description="MyApp.SessionSharing" Id="93a36eb1-5948-44ed-82a4-642bc1a4132b" Url="http://dev/"/>
      <activate Description="MyApp.ContentTypes" Id="807d55b5-77fc-423c-bae3-aedd861a96c4" Url="http://dev/myapp"/>
      <activate Description="MyApp.PageLayouts" Id="f21423d1-0052-456f-b727-aa7268fa4e52" Url="http://dev/myapp"/>
      <activate Description="MyApp.Home.Pages" Id="2aa7ea41-6b01-45d4-87e0-a8194ea246fb" Url="http://dev/myapp/en/home"/>
      <activate Description="MyApp.Products.Pages" Id="2aa7ea41-6b01-45d4-87e0-a8194ea246fb" Url="http://dev/myapp/en/products"/>
      <activate Description="MyApp.Support.Pages" Id="2aa7ea41-6b01-45d4-87e0-a8194ea246fb" Url="http://dev/myapp/en/support"/>
    </Features>
  <AfterDeploy>
    <IIS>
      <Recycle AppPool="MyApp - Service"/>
      <Recycle AppPool="SharePoint - DEV"/>
    </IIS>
    <WarmUp Url="http://dev/myapp/en/home/pages/welcome.aspx" />
    <WarmUp Url="http://dev/myapp/en/support/pages/welcome.aspx" />
    <WarmUp Url="http://dev/myapp/en/products/pages/welcome.aspx" />
    <TimerJobs>
      <Start JobName="Variations Propagate Page Job Definition" WebApp="http://dev" WaitForCompletion="false"/>
    </TimerJobs>
  </AfterDeploy>
</Deployment>

The above XML tells the script to provision a hierarchy of websites, then deactivate some features and then deploy the solution (which will also retract and remove the solution if it is previously deployed) after the deployment is done, it activates features, recycle two application pools and warms up the SharePoint web application by requesting a few pages and at the end starts a timer job. Please note that the order of different elements in the XML file defines the order of the tasks to be run. You can save the XML in a file with arbitrary name and call it like so:

Deploy-SPSolutions c:\solutions.xml -Log "c:\install.log"

You can download the latest version of Deploy-SPSolutions (SharePoint CI) script from GitHub You will also find some samples there.

I’m currently cleaning up the script and putting it in GitHub, but the I always make sure the version on GitHub is reliable enough for everyone to use.

Advertisements
Automating SharePoint Deployments (aka Continuous Integration) by PowerShell