SharePoint Advanced Large Scale Deployment Scripting – “Features” (part 2 of 3)
29 Jul 2011 2 Comments
I have been battling deployments for a while and finally decided to do something about it.
The challenge is to handle a dozen WSP packages on farms that host 20-50 web applications (or host header named site collections) to complete the deployments in a timely manner, ensure that the required features are uniformly activated every time while minimizing the human error element of the poor guy deploying through the night.
The deployment scripts require PowerShell v2 and are equally applicable to both SharePoint 2007 and 2010 – the need is roughly the same and the APIs are also largely unchanged. Some minor differences in service names are covered by the code.
To keep this post reasonable in length I’ve split the subject into three parts:
Part 2 is the scripts and configuration for automatic large scale feature activations
Note: This took a long time to write and it will likely take you, dear reader, at least a few hours to implement in your environment.
If you have not done so already read “Part 1” first and excuse me for a bit of duplicated text.
It’s all about the Features
This part is about features and managing their (de-)activations.
What you can do with this is:
- Maintain a set of templates (“FeatureSets”) that defines what features should be activated on a given type of site – the scripts then ensures that they are properly activated
Set actions for features to be either activate, deactivate or reactivate through the configuration file
- It safely handles web.config updates so that the scripts do not enter a race condition with the SharePoint timer service
- Selectively override the default behavior and reactivate certain features when you need to
In other words you can ensure that your features are properly activated across sites and farms.
A note on reactivation is in order here. Reactivation is (force) deactivation and followed by activation which is particular useful for features that updates files in document library, e.g. masterpages. Some features require it when they have been updated but it is very rare that a feature always require reactivation.
Therefore I usually do not specify any features to always be reactivated in the configuration file, however if I know that we updated the masterpages I’ll update the batch file, or supply an additional one, where that feature is forced reactivated. The safe option of always reactivating is simply too slow if many files are deployed (or lengthy feature receivers) are involved.
The scripts work based on a configuration file that is shared between your dev, test, QA and production environments.
The procedure is:
- Identify all valid Sites/URLs in the local farm (i.e. always executed on one of the servers in the farm)
For each site/URL go through all Feature sets and ensure activations, deactivations and reactivations required
- Keep track of reactivations so same feature is only reactivated once at each scope, i.e. overlap between FeatureSets are allowed as long as they specify the same action
- Report inconsistencies as errors, but do continue with the next features so that you can have the complete overview of all errors at the end of the run
A sample configuration file is (note: I just picked some more or less random WSPs from codeplex):
<?xml version="1.0" ?> <Config> <Sites> <!-- note: urls for all environments can be added, the ones found in local farm will be utilized --> <!-- DEV --> <Site url="http://localhost/"> <FeatureSet name="BrandingAndCommon" /> <FeatureSet name="Intranet" /> </Site> <Site url="http://localhost:8080/"> <FeatureSet name="BrandingAndCommon" /> <FeatureSet name="MySite" /> </Site> <Site url="http://localhost:2010"> <FeatureSet name="CA" /> </Site> <!-- TEST --> <Site url="http://test.intranet/"> <FeatureSet name="BrandingAndCommon" /> <FeatureSet name="Intranet" /> </Site> ... <!-- PROD --> <Site url="http://intranet/"> <FeatureSet name="BrandingAndCommon" /> <FeatureSet name="Intranet" /> </Site> ... </Sites> <FeatureSets> <FeatureSet name="BrandingAndCommon"> <Solution name="AccessCheckerWebPart.wsp" /> <Feature nameOrId="AccessCheckerSiteSettings" action="activate" ignoreerror="false" /> <Feature nameOrId="AccessCheckerWebPart" action="activate" ignoreerror="false" /> <Solution name="Dicks.Reminders.wsp" /> <Feature nameOrId="DicksRemindersSettings" action="activate" ignoreerror="false" /> <Feature nameOrId="DicksRemindersTimerJob" action="activate" ignoreerror="false" /> <!-- Todo - all sorts of masterpages, css, js, etc. --> </FeatureSet> <FeatureSet name="Intranet"> <Solution name="ContentTypeHierarchy.wsp" /> <Feature nameOrId="ContentTypeHierarchy" action="activate" ignoreerror="false" /> </FeatureSet> <FeatureSet name="MySite"> </FeatureSet> <FeatureSet name="CA"> </FeatureSet> </FeatureSets> <Solutions> <!-- list of all solutions and whatever params are required for their deployment --> <Solution name="AccessCheckerWebPart.wsp" allcontenturls="false" centraladmin="false" upgrade="false" resettimerservice="false" /> <Solution name="ContentTypeHierarchy.wsp" allcontenturls="false" centraladmin="false" upgrade="false" resettimerservice="false" /> <Solution name="Dicks.Reminders.wsp" allcontenturls="true" centraladmin="false" upgrade="false" resettimerservice="true" /> </Solutions> </Config>
Where the interesting bits are that Sites contain a number of named FeatureSets. The FeatureSets are gathered in their own section (for reusability) and defines a number of solutions to be deployed and the features to be handled. It is good practice to list the solutions for the features that you are working on so you can be sure that the solution deployment matches your features. Do not spend time on noting all the SharePoint system features to be activated as they are normally handled just fine by the Site Definitions.
Each feature activation line looks like:
<Feature nameOrId=”AccessCheckerWebPart” action=”activate” ignoreerror=”false” />
Where nameOrId is either the guid (with or without braces, dashes etc.) or the name of the feature, i.e. the internal name in the WSP packages, not the display name. When possible I always opt for flexibility 😉
The action attribute is either “activate”, “deactivate” or “reactivate”.
The ignoreerror is simply a boolean true/false switch that determines how the error should be logged if the feature fails to be activated. It is quite usable for the occasional inconsistencies between environments, e.g. if you are removing a feature then it might be present in production but no longer in the test environment. The script continues with next feature in case of errors regardless of this switch.
It is important to note that web scoped features are not supported here, “only” farm, web app or site scope is allowed.
The features are activated in the order that they are present in the config file.
There are two sections here:
- A number of SharePoint PowerShell scripts that include each other as needed
A few batch files that start it all. I generally prefer to have some (parameter less) batch files that executes the PowerShell scripts with appropriate parameters
I have gold-plated the scripts quite a bit and created a small script library for my SharePoint related PowerShell.
The PowerShell scripts are too long to write in the post, they can be downloaded here. The list is (\SharePointLib):
*(Part 1) DeploySharePointSoluitions.ps1: Start the WSP deployments. Parse command line arguments of config file name and directory of WSP solutions
*EnsureFeatureActivation.ps1: Start the feature activation scripts (need command line arguments)
*(Part 3) QADeploymentProcess.ps1: Deployment process for dev, test and QA environments (need command line arguments)
SharePointDeploymentScripts.ps1: Main script that defines a large number of methods for deployment and activations.
SharePointHelper.ps1: Fairly simple SharePoint helper methods to get farm information
*RestartSharePointServices.ps1: Restart all SharePoint services on all servers in the local farm
Services.ps1: Non-SharePoint specific methods for handling services, e.g. restarts
Logging.ps1: Generic logging method. Note that there are options for setting different log levels, output files, etc.
The ones with an asterisk are the ones that you are supposed to execute – the others just defined methods for the “asterisk scripts”.
The batch files (same download) (root of zip download):
(Part 1) 01 Deploy Solutions.bat: Start the solution deployment. It will deploy all the WSP files dropped in “\SolutionsDropDir\” that are also specified in the “\DeploymentConfig.xml”:
02 Activate Features.bat: Works with the “\DeploymentConfig.xml” file and ensures that all features are activated.
In other words you’ll execute “02 Activate Features.bat” to ensure that all features are activated in your farm.
The important line in 02 Activate Features.bat file is
powershell.exe -File “SharePointLib\EnsureFeatureActivation.ps1” “%config%” “” >>ActivateFeatures.log
And if you need to reactivate your branding features (masterpages) you can just copy the batch file and change the line to something like:
powershell.exe -File “SharePointLib\EnsureFeatureActivation.ps1” “%config%” “BrandingMasterPages,BrandingCSS,BrandingPageLayouts” >>ReactivateFeatures.log
to force the three (made up) features “BrandingMasterPages”, “BrandingCSS” and “BrandingPageLayouts” to be reactivated.
By default you will get one log file from each batch file named after the operation, one log file with a timestamp and in case of any errors an additional error log with the same timestamp. In other words if the error log file is not created then no errors occurred.
The scripts are quite fast and the time to execute is determined by the time it takes to activate the features within SharePoint. Therefore if the script has nothing to do, i.e. all features are activated as they should, then it’s normally less than 1 minute to check everything and return.
What usually takes time is features with many files to be added to document libraries (branding) and features that modify the web.config as we wait for the timer job to complete (assuming that the API is used to do this).
The scripts write quite a bit of logging that can be daunting (especially if you set it to verbose) but don’t worry – I rarely look at them anymore. Instead I look for the EnsureFeatureActivation_date_error_log. If it’s not there then no error occurred and no reason to look into the log files.
These scripts have been a huge benefit for our deployment in order to reduce the post-deployment errors and fixes. It is however also the first to be blamed for errors whenever some feature does not behave as intended (“the unghosted file is not change that must be the fault of the deployment scripts”) and it rarely is the source of the error.
They can be blamed for being a bit complicated though and that is a fair point. If you don’t understand what they do and how you shouldn’t use them.
If you make some brilliant changes then let me know so I can include it in my “official” version.
Please also leave credits in there so it’ll be possible for your successors to find the source and documentation.
Note: Updated Aug 29 2011.