Spring Cleaning Your Dev Box


After some time your dev box ends up looking like a well-used tool shed complete with unused tools and cobwebs in the corners.

While it’s quick and easy to get rid of half the icons on your desktop and delete droves of temporary working files – I always end up returning to a few well used scripts to get my much needed disk space back as well as a cleaner and faster box.

Often the trigger is exhausted disk space.

These are the scripts I always end up using.

Delete old site collections

If you are making site definitions (or web templates) you’ll likely end up with tons of small test site collections over time. I often use scripts to create them named after the current time.

To clean that all up I use the PS script (run in the SharePoint Administrative Console):

    get-spsite http://* -limit all |? { $_.Url -Match "http://.*/" -and $_.LastContentModifiedDate -gt [DateTime]::Today.AddMonths(-2)} | remove-spsite

In human terms: “Delete every site collection that is not a root site collection and that have not been modified within the last two months”. Phew.

Do NOT run this in production.

Set Simple SQL Recovery Mode

Next I ensure that all my local databases run in simple recovery mode, i.e. avoid huge transactions logs that need to truncated once in a while.

I nicked this script somewhere in google (likely here):

USE MASTER
declare
	@isql varchar(2000),
	@dbname varchar(64)
	
	declare c1 cursor for select name from master..sysdatabases where name not in ('master','model','msdb','tempdb')
	open c1
	fetch next from c1 into @dbname
	While @@fetch_status  -1
		begin
		select @isql = 'ALTER DATABASE [@dbname] SET AUTO_CLOSE OFF'
		select @isql = replace(@isql,'@dbname',@dbname)
		print @isql
		exec(@isql)
		select @isql = 'ALTER DATABASE [@dbname] SET RECOVERY SIMPLE'
		select @isql = replace(@isql,'@dbname',@dbname)
		print @isql
		exec(@isql)
		select @isql='USE [@dbname] checkpoint'
		select @isql = replace(@isql,'@dbname',@dbname)
		print @isql
		exec(@isql)
		
		fetch next from c1 into @dbname
		end
	close c1
	deallocate c1

Run it within the SQL Server Management Studio.

Note that it is likely that the script will report a few minor errors if some DBs are detached/offline. Never mind.

Shrink DBs

Finally save some much needed space by shrinking the DB files. After site collection deletions and recovery mode changes there are likely a lot of space to be freed within the DB files.

This script will try to shrink all the DB files (I think I got it from here):

DROP TABLE #CommandQueue

CREATE TABLE #CommandQueue
(
    ID INT IDENTITY ( 1, 1 )
    , SqlStatement VARCHAR(1000)
)

INSERT INTO    #CommandQueue
(
    SqlStatement
)
SELECT
    'USE [' + A.name + '] DBCC SHRINKFILE (N''' + B.name + ''' , 1)'
FROM
    sys.databases A
    INNER JOIN sys.master_files B
    ON A.database_id = B.database_id
WHERE
    A.name NOT IN ( 'master', 'model', 'msdb', 'tempdb' )

DECLARE @id INT

select * from #CommandQueue

SELECT @id = MIN(ID)
FROM #CommandQueue

WHILE @id IS NOT NULL
BEGIN
    DECLARE @sqlStatement VARCHAR(1000)
    
    SELECT
        @sqlStatement = SqlStatement
    FROM
        #CommandQueue
    WHERE
        ID = @id

    PRINT 'Executing ''' + @sqlStatement + '''...'

    EXEC (@sqlStatement)

    DELETE FROM #CommandQueue
    WHERE ID = @id

    SELECT @id = MIN(ID)
    FROM #CommandQueue
END

Again expect some errors, inspect and accept them ;-)

Expand the Disk?

If the three steps above didn’t free enough space for you, the solution often is to just expand the VHDs on your virtual machines.

It’s a fairly easy process in both VMWare and HyperV it only requires you to turn off the VM, remove any snapshots, and expand the disk using the wizard for it. This will only expand the VHD; your partitions will not grow, so you need to do that next.

You can use the disk management tool for it – however I find it cumbersome. Especially if it is the system disk you’re expanding it is awkward. I prefer to use GPartED, which is a very nice linux partition editor. It is a downloadable iso that is a breeze to boot into and expand the partition whether it is the system or not.

One note: In a typical Linux way you are asked all sorts of questions at boot; just hit return at every one of them. Who cares about the keyboard layout for a GUI program with big buttons anyway?

It looks something like this:

(Note: Before using this program make sure that you close down the VM nicely from the guest)

Easy.

Quick tip: Handy Scripts for Local Hyper-V Management


Here is a quick post with a small script that I find incredibly handy for managing my local Hyper-V machines (on windows 8).

It simply ensures what set of VMs are running at a given time – attach that to a shortcut on the desktop and it saves me 3 minutes every day; I find it useful.

Why? Quite often, I need to switch from one set of VMs to another for different tasks (VMWare term is “teams”) e.g. switching between SP2010 and SP2013 development. Sometimes just turn them off if I need the resources for something else.

Normally you just go into Hyper-V manager and start/stop the relevant VMs. Automating that was quite simple and painless – the download is here.

  1. I have one PowerShell script (SetRunningVMs.ps1) that handles the VM management and then a couple of batch files for executing that script with proper parameters. The script is:
    <#
    .SYNOPSIS
    This is a simple Powershell script that adjust what VMs are running on the local Hyper-V host.
    
    .DESCRIPTION
    This script will start/resume the requested VMs and suspend all other VMs to give you maximum power and make it easy to switch from one
    development task to another, i.e. switch teams.
    
    .EXAMPLE
    Make sure that only the dev1 and ad01 machines are running:
    ./SetRunningVMs.ps1 'dev1' 'ad01'
    
    Stop all VMs (no arguments)
    ./SetRunningVMs.ps1 
    
    .NOTES
    Requires admin rights to run. Start using admin shell or use one of the provided batch files.
    Pauses on error.
    
    .LINK
    
    http://soerennielsen.wordpress.com
    
    #>
    
    param( [Parameter(ValueFromRemainingArguments=$true)][string[]] $allowedVMs = @() )
    
    try{
        get-vm |? { $_.State -eq "Running" -and $allowedVMs -notcontains $_.Name } |% { Write "Saving $($_.Name)"; Save-VM $_.Name }
    
        get-vm |? { $_.State -ne "Running" -and $allowedVMs -contains $_.Name } |% { Write "Starting $($_.Name)"; Start-VM $_.Name }
    
        write "SetRunningVMs succesfully done"
    }
    catch{
        Write-Error "Oops, error:" $_
        pause
    }

    I assume that the PowerShell Hyper-V module is loaded; it has always been the case in my tests.

  2. I have a number of batch files for easily executing the script, one for turning off (suspend) all VMs, one for a SP2010 team and one for the SP2013 team. It’s a one-liner bat file that will work with both PowerShell 2 and 3, with or without UAC.

    To Start my SP2010 team (StartSP2010Team.bat):

    powershell -noprofile -command “&{ start-process powershell -ArgumentList ‘-noprofile -file %~dp0SetRunningVMs.ps1 \”AD01\” \”Dev1\”‘ -verb RunAs}”

    (where you replace the bold VM names above with your own)

    To start my SP2013 team (StartSP2013Team.bat)

    powershell -noprofile -command “&{ start-process powershell -ArgumentList ‘-noprofile -file %~dp0SetRunningVMs.ps1 \”AD02\” \”SP2013\”‘ -verb RunAs}”

    To stop all VMs

    powershell -noprofile -command “&{ start-process powershell -ArgumentList ‘-noprofile -file %~dp0\SetRunningVMs.ps1′ -verb RunAs}”

If you have UAC enabled (as I do) you will be prompted, otherwise it will just suspend/resume the relevant VMs.

It took about two hours to write the scripts, where the hardest part was getting the batch files properly in shape with escape characters and UAC.

You gotta love PowerShell ;-)

Find/Remove Obsolete Resource Labels


This is part 3 of 4 in a series on how to improve the way we usually work with resource (resx) files. At least the way my team and I work with them.

I generally like to – and do – use resource files for all string constants that are shown to end-users, however I do feel that it is needlessly cumbersome, therefore these posts:

  1. A Good Way to Handle Multi Language Resource Files
  2. Verify that your Resource Labels Exists
  3. Find Obsolete Resource Labels (this one)
  4. Supercharge your (Resource) Efficiency with Macros

Generally these issues are generic to .NET and not specific to SharePoint, though that is where I’m spending my time writing this.

So – Near the End of the Project – are those Resource Entries Still in Use?

The issue at hand is that you have hundreds of source files of various flavors and they are sprinkled with references to a number of resource files. When code is refactored or just deleted what happens to old resource labels? Likely nothing at all.

Are you happy with a ton of useless resource entries no longer in active use? What if you had to translate it to a couple of languages?

Quite obviously this is no biggie code/quality wise, but still…

The answer is that you run the PowerShell script below, that’ll check – and optionally fix – it ;-)

The Script

I made a small script to check and remove the excess resource entries to slim down those resource files a bit.

The script will, given a starting location (i.e. the root folder for your solution)

  1. Go through every code file (to be safe every file, except a list of binary extensions) and look for resource labels of the form “$Resources:filename,label_key
  2. Search recursively for resx files
  3. For every one of those resx files it will look through the resource labels in use and flag those that it cannot find
  4. (Optionally) Do a “safemode” check where every file is searched for the resource label, i.e. necessary if you are using multiple/other resource lookup methods then the $Resource moniker
  5. (Optionally) If you choose you may remove them automatically but do make a dry run first to sanity check that you got the paths right and that you have all the source files to be searched

Usage:

    PS> & VerifyResxLabels.ps1 “path to solution dir” [-remove] [-safemode]

(Tip: Download the script to somewhere, write an ampersand (&) and then drag the ps1 file into the PowerShell window and then drag the solution folder to the window.)

You’ll definitely want to pipe the output to a file.

Limitations

There are obviously some limitations

  • It will not: Check out the resx files from source control (but it will show the file error in the output)
  • It will not: Respect commented out code – it’s simple pattern matching so commented out code will be treated as actual code (hardly an issue)
  • Safemode is very slow of necessity and will likely find false positives, i.e. it will play it safe and keep entries that exists in some files, even though the same label may be used in a completely different context
    • It’s an (O(n*m) algorithm, with number of files and number of labels) – My test with 1000 unique labels, 28 resx files and 2400 files it takes a night

Download the script here

Verify that your Resource Labels Exists


This is part 2 of 4 in a series on how to improve the way we usually work with resource (resx) files. At least the way my team and I work with them.

I generally like to – and do – use resource files for all string constants that are shown to end-users, however I do feel that it is needlessly cumbersome, therefore these posts:

  1. A Good Way to Handle Multi Language Resource Files
  2. Verify that your Resource Labels Exists (this one)
  3. Find Obsolete Resource Labels
  4. Supercharge your Resource Efficiency with Macros

Generally these issues are generic to .NET and not specific to SharePoint, though that is where I’m spending my time writing this.

So, are you sure that your Resource Labels Exists?

The issue at hand is that you have hundreds of source files of various flavors and they are springled with references to a number of resource files. Usually only one for each project/wsp though.

So how can you be sure that you don’t use one in your code that isn’t defined in your resource file?

As missing resource labels are just output verbose to the end user/application this can be a major issue.

The answer is that you run the PowerShell script below, that’ll check it ;-)

The Script

I made a small script to check for resource labels after a major code rewrite that had me change literally hundreds of labels.

The script will, given a starting location (i.e. the root folder for your solution)

  1. Search recursively for resx files and store their locations
  2. Go through every code file (.xml, .cs, .vb, .as*x, .webpart, .dwp, .feature) and look for resource labels of the form “$Resources:filename,label_key
  3. For every one of those resource keys it’ll open the corresponding resx file and check that the key is present and write a warning to the console if not

Obviously this takes a minute or two – in my current project with 8500 files (including everything) it takes about 1 minute to complete (a VM on a power laptop) which is completely acceptable as you don’t really need to run it that often.

Enterprising people may want to add it to the buildserver’s list of tests. I haven’t found the need or the time yet ;-)

Usage:

    PS> & VerifyResourceLabelsExists.ps1 “path to solution dir

(Tip: Download the script to somewhere, write an ampersand (&) and then drag the ps1 file into the PowerShell window and then drag the solution folder to the window.)

Sample output:

Searching for resx files
Searching for labels
Parsing resx files
Checking labels
Warning: Could not find $Resources:Delegate.XXX.XXX,ContentType_XXX_Description in file C:\Dev\TFS\xxxx\Elements.xml
Warning: Could not find $Resources:Delegate.XXX.XXX,ListDefinition_XXX_Heading in file C:\Dev\TFS\xxxx\Schema.xml
...
 

You’ll likely want to pipe the results to a file and then run through your source files to add the missing labels (see part 4, when I finish it).

What it does not do

There are obviously some limitations. It will not

  • Add the missing labels for you
  • It simply looks at files. If you have some files that are excluded from your project files they will be counted in regardless
  • It simply does pattern matching – code commented out is still included by the script
  • It always works of the default non-language specific resx file – the task of ensuring that all labels are defined in all languages is a fairly simple xml comparison for which tools exists
  • Handle default resource files, i.e. the case where you define a default resource file in your feature.xml files and then use the “$Resources:label_key” shorthand with no file name

Download the script here

Script to Import/Export Metadata Termstore


Recently I’ve been using the Managed Metadata Store in SharePoint 2010 and been amazed by the lack of proper import/export functionality.

It feels like a blast from the past to be able to only import a CSV file… CSV?!? What happened to proper XML? What happened to Export? What happened to being able to transfer (meta)data between farms (like test and production) since the builtin Import insists on creating new TermSets and not update existing ones (and yes your managed metadata linked site columns do in fact store a strong reference, not just a name, so you’ll loose the link).

I couldn’t find any existing Powershell commandlets to the rescue either.

I couldn’t readily bing ;-) any usable scripts for this.

What I did

So I built a powershell script to take a CSV file and import it into the Term Store and merge it with any existing term store already there.

CSV?!?? Yeah…

Point is then you can still use the CSV file you likely already hold. You can use the TermSetImporter to export CSV files from your existing environment.

If you are starting Greenfield, then I recommend to use excel with some macros to create the Term Sets (then your users can create them instead of you) or you might just let your users loose in the term store manager.

How to use

First download my small script and the sample excel and CSV files.

Second, fire up powershell (on a SharePoint server), write:

. ./MergeTermSets.ps1 csvfile groupname urlForASharePointSite

Do remember the “dot space” at the start of the line. The second “./” is just the path for the ps1 file in this case.

The urlForASharePointSite is optional and will default to http://localhost:2010 which likely corresponds to a valid SharePoint Central Admin site on 50% of all SharePoint installations. Watch the output log. If something goes wrong it’s likely that you should have a look in your CSV file for errors and/or whether or not the managed metadata store is connected properly.

Notes:

  • I’ve tried to do some tricks to handle encoding properly and I also trim spaces which really causes the term store to stumble (it will trim spaces and every subsequent comparison the script might do will fail).
  • Note that LCID and the parent Terms need to be set on every line in the excel sheet. Don’t blame me I didn’t make that part ;-)
  • Terms are only added not updated, i.e. I don’t try to keep stuff like descriptions in sync
  • No fancy stuff, no merging, no deletions, deprecation etc.

Hope it’s useful for you too.

SharePoint Advanced Large Scale Deployment Scripting – “Dev and QA gold-plating” (part 3 of 3)


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 1 is the main (powershell) deployment scripts primarily targeted at your test/QA/production deployments

Part 2 is the scripts and configuration for automatic large scale feature activations

Part 3 (this part) is about gold-plating the dev/test/QA deployment scenario where convenience to developers is prioritized while maintaining strict change control and records

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 the two other parts first.

The Challenge

When you have a number of developers working on the same service line you need to be able to keep strict control of your QA and test environment.
So either you have one guy as the gatekeeper or you automate as much as possible. I’m the last type of guy so I’ve developed a “one-click” deployment methodology where the focus is
1. Simple and consistent deployment
2. Easy collection of solutions for next production deployment – you should deploy the exact code that you tested not a “fresh” build(!)

The Solution

Our build server is set up to produce date labelled zip files with the wsp and manual installer (exe) within folder of the same name.
I’m sure yours are different therefore the scripts work with a solution drop directory that accepts both zip files (that includes a wsp file) and also plain wsp files.
The folder structure is up to you I’ll just search recursively for zip and wsp.

The script files are:

03 DeployAndStoreDropDir.bat: The starting batch file that will execute the deployment process as a specific install user. That way the developers can login with their personalized service accounts and use a specialized one for deployment purposes. You need to change the user name in this batch file. The first time you run this you need to enter the password for your install account subsequent runs will remember it  (“runas /savecred”).

03b DeployAndStoreDropDirAux.bat: The batch file doing half the work. It’ll archive old log files in “.\ArchivedDeploymentLogFiles” (created if not present) and it execute “QADeploymentProcess.ps1″ that is doing the hard work. At the end it’ll look for error log and write an alert that you should look for it. Saves a lot of time – I don’t go looking in log files if I don’t get that message.

SharePointLib\QADeploymentProcess.ps1: The script that is handling the unzipping and storage of the zip/wsp files and executing both the deployment and feature activation scripts. The goal is to have a simple drop dir where for WSP/zips and a single storage location, “SolutionsDeployed”, for the currently deployed code. The “SolutionsDeployed” folder will be updated at every deployment, so that there is only the latest version of each wsp deployed. You do not need to drop all wsps in the drop dir every time; it does not just delete the SolutionsDeployed folder at every deployment.

This is how the files are moved around for a couple of WSPs and a zip file:

In short:

  1. If you want to start it with a specific install user, just execute “03 DeployAndStoreDropDir.bat”
  2. If you want to start it in your own name, execute “03b DeployAndStoreDropDirAux.bat” and perhaps delete the other bat file.
  3. If you want to modify how it works go to the “QADeploymentProcess.ps1″ file.
  4. If you want to work with zip files they can have the name and internal folder structure that you like. The one important thing is that they should only contain one WSP file. It is pretty smart; at the next deployment your zip file may be named differently (e.g. with a date/time in the name) and it will still remove the old version from “SolutionsDeployed” and store your new version with the new folder/zip name.
  5. At the end of your build iteration SolutionsDeployed will contain the latest version of your deployed code (provided that you emptied it at the last production deployment)

Closing Notes

It is not a big challenge to connect the remaining dots and have your build server do the deployment at certain build types and have a “zero-click” deployment, however I opted to not do it. It should be a conscious decision to deploy to your test and QA environments, not something equivalent to a daily checkin. Your milage may wary.

I would generally provide these scripts to everyone in the team and encourage them to use them on their own dev box once in a while – it always pays to have your dev environment resemble the actual production environment this makes it feasible to keep the code (almost) in sync on all dev environments.

The challenge may be the complexity of the scripts and the effort to understand them – you shouldn’t rely too much on stuff you don’t understand ;-)

Feel free to adjust the script a bit (likely QADeploymentProcess.ps1) to suit your environment.

If you make something brilliant 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.

Download

Grab the files here – part 1, 2 and 3 are all in there. I’ll update them a bit if I find any errors or make improvements.

Note: Updated Aug 29 2011, minor stuff.

Don’t forget to change the user name in “03 DeployAndStoreDropDir.bat” to your “install” account.

SharePoint Advanced Large Scale Deployment Scripting – “Features” (part 2 of 3)


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 1 is the main (powershell) deployment scripts primarily targeted at your test/QA/production deployments

Part 2 is the scripts and configuration for automatic large scale feature activations

Part 3 is about gold-plating the dev/test/QA deployment scenario where convenience to developers is prioritized while maintaining strict change control and records

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 Configuration

The scripts work based on a configuration file that is shared between your dev, test, QA and production environments.

The procedure is:

  1. Identify all valid Sites/URLs in the local farm (i.e. always executed on one of the servers in the farm)
  2. For each site/URL go through all Feature sets and ensure activations, deactivations and reactivations required
    1. 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
    2. 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.

The Scripts

There are two sections here:

  1. A number of SharePoint PowerShell scripts that include each other as needed
  2. 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.

Runtimes

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).

Closing Notes

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.

Download

Grab the scripts here.

Note: Updated Aug 29 2011.

SharePoint Advanced Large Scale Deployment Scripting – “Deploy” (part 1 of 3)


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 are equally applicable to both SharePoint 2007 and 2010 – the need is roughly the same and the APIs are 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 1 is the main (powershell) deployment scripts primarily targeted at your test/QA/production deployments

Part 2 is the scripts and t for automatic large scale feature activations

Part 3 is about gold-plating the dev/test deployment scenario where convenience to developers is prioritized while maintaining strict change control and records

Note: This took a long time and countless iterations to develop and it will likely take you, dear reader, at least a few hours to implement in your environment.

The Requirements

My design goals were to solve

  • Automatic solution deployments (including timer jobs resets)
  • Consistent activation of features across the farm while allowing for different types of sites
  • Easy, fast and reliable execution
  • Not too awkward configuration of solutions and features for farms with many sites – it will never be a no-brainer
  • Exact same configuration (file) to be re-used across Dev, Test, QA and Prod tiers

The cost is some fairly complex scripts that took quite a while to write and test.

The same script works equally well for both 2007 and 2010.

There is almost no difference between SharePoint 2007 and 2010 in this area – 2010 comes with some new CmdLets for PowerShell but they are often just convenient access to the API. I’m taking the extra effort to hit the API directly which is essentially unchanged for deployment purposes. One of the really cool new features in 2010 is the ability to control solution upgrade in detail which is of course supported by these scripts simply by choosing the upgrade option for a given solution.

The Solution

The idea is that you have the same configuration file for all your app tiers, and

  1. When you need to deploy a new version of some of your WSPs you just provide them and execute the scripts
  2. Script will scan the local farm and map the URLs with the provided WSPs and deploy them
  3. Run through every identified Site and match feature activations with the configuration file and fix any discrepancies

The features are

  • Deploy WSP files regardless of whether or not they were deployed beforehand (uninstall followed by install is the default installation mode for me)
    • If solution deployment goes wrong the behavior is to restart all SharePoint related services on all servers in farm and retry (a few times). It surprisingly often solves problems like locked files etc.
    • If a solution contains timer jobs the timer service is restarted on all servers in farm. Finally
  • Upgrade existing WSP files
  • (Part 2) Scan the farm and ensure that required features are activated (or perhaps deactivated) on specified sites
    • Farm and WebApp scoped features are by default deactivated after an uninstall/install – this script reactivates them
    • Features are always (de)activated with the “force” parameter just for good measure
    • Yes, it’ll wait for web config modifications jobs when required
  • (Part 2) Re-activate selected features i.e. deactivate first then activate
  • (Part 3) Automatic deployment and activations for dev, test and QA environments

The Configuration File

The hearth of the scripts is the configuration file.

The one configuration file can be re-used for both handling solution deployment and feature activations across all tiers of your farms. You can also conceivable use the same config file for different types of farms, e.g. the intranet and extranet, however I feel that in those scenarios it is better to keep those things separate.

The configuration file contains:

  • A number of “Sites” which is the URLs of either (host header named) site collections or web applications
    • The local farm will be scanned and the sites found in the config file that are present in the local farm is the ones that we work on – the rest are ignored (e.g. running in test it’ll skip all the production URLs)
    • Each site node contains a number of FeatureSets but no list of features or solutions
  • A number of “FeatureSets” that groups WSPs and features. Features are either “activated”, “deactivated” or “reactivated”
    • (The feature thingie is in part 2)
    • For a given site the union of all the solutions specified in all the FeatureSets associated with the sites defines what solutions should be deployed to that site.
  • A number of “Solutions” that list the WSP names and their individual options, i.e. deploy to central admin, all content URLs, upgrade or (re)install, does it contain timer jobs (which requires timer service to be restarted on all farms)
    • Note: The scripts deploy all the solutions in a given “drop” directory and ignore all the configuration nodes without a matching WSP file

To demo it I’ve downloaded a couple of WSPs from CodePlex and created the following configuration file for my dev box:

<?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>

Note: I more or less picked some random WSPs from CodePlex for demo purposes.

Note 2: The scripts will respect the order given in the config file. The Sites are processed in order, the FeatureSets listed first within a “Site” node is handled in top-down order. The solutions deployed to the farm are deployed in the order they are listed in the “Solutions” node.

Note 3: XML is case sensitive; therefore, all the named sections are case sensitive. The one exception is that I accept different casing between the WSP file names and the name they are given within the config file.

The Scripts

There are two sections here:

  1. A number of SharePoint PowerShell scripts that include each other as needed
  2. 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):

*DeploySharePointSoluitions.ps1: Start the WSP deployments. Parse command line arguments of config file name and directory of WSP solutions

*(Part 2) 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 (see runtime notes below)

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):

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 (Part 2): Works with the “\DeploymentConfig.xml” file and ensures that all features are activated.

In other words you’ll execute “01 Deploy Solutions.bat” to deploy all your solutions.


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.

Note: Scripts must be executed on one of your SharePoint servers which sufficient rights. That is more or less local admin and owner on the individual databases (or local admin on the SQL box as well).

Note 2: I write quite a bit of logging it is invaluable in times of trouble. You can change the amount in the logging.ps1 file by adjusting the loglevel variable.

Note 3: In case of deployment errors the default behavior is to restart every SharePoint service on every server and then retry. These service restarts are performed async, so it should take no more than a minute or two, no matter how many servers you have (almost).

Note 4: Any WSP found in the drop dir that has not been specified in the config is considered an error – therefore you know that all the wsps provided are deployed if no errors are reported.

Runtimes

The time it takes to search the local farm for relevant site collections / web applications is negligible so you shouldn’t worry unduly about impact on runtime to add 300 URLs to cover all your possible environments including every developer’s individual preferred setup.

But there is no magic and it simply runs in the time it takes to deploy solutions to your environment. If it takes about 3 minutes for a full retract, remove, add, deploy then it takes 30 minutes for 10 WSPs.

The default way of handling deployment errors is to restart all SharePoint services in the farm. The clever way of doing that is to send the stop/start commands to all services first and then wait for the operations afterwards. That way the time taken to do restarts is about the time of restarting the slowest service in the farm once – it usually takes 1-2 minutes regardless of the number of servers. In my opinion this is quite cool :-)

Closing notes

If you are wondering about my exception handling note that the scripts were originally made for PowerShell 1.0 and later I decided to only target 2.0. Some statements may be written prettier without me taking the time to do so.

These scripts save us a ton of time and prevents a lot conversations of the sort “oh I forgot to activate that feature, 2 secs, there you go” – but of course quite some time has been spent creating the deployment scripts and fixing errors within them.

Some of the scripts are quite usable for other purposes. For instance, the remote service restart script I have not seen anywhere else – this is simpler than installing PowerShell remoting (WinRM?) on every server.

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.

Download

Grab the scripts here (updated with part 2 and 3).

Note: Updated Aug 29 2011.

Automatic Fix of Pre Upgrade Issues (SharePoint 2007 to 2010)


Ever tried to run the PreUpgradeCheck command at your MOSS farm and received a frightening long list of issues that takes forever to solve manually?

If you are like me you refuse to do any manual work that takes more than 2 hours (and you’ll have to re-do it for every farm) – so I’ve tried to script all the required fixes. This is one of those posts that I’ve been working on for months so I hope you appreciate it – I’m a bit proud of the script at the end of the post.

The goal is to have a PowerShell (v1.0) script fix every one of those blocking issues you see in the PreUpgradeCheck report. On my own very messy (intentionally so!) farm with 40+ databases and site collections and a large number of solutions I’ve managed to fix all but the one about my operating system needing an upgrade to Server 2008. That one I’ll not work on ;-)

Going from:

To this:

Note: It will only work of you have installed SP2 and cumulative update from October 2009. At least. I recommend that you work of as new a version as possible.

WARNING

The script will remove invalid “stuff” from your sites so be absolutely sure that every solution that you care about is deployed to the farm – otherwise all features, files and webparts from missing solutions will be removed from the sites.

The script will also publish unpublished pages if they contain some of these invalid webparts.

I give you no warrenty – backup your farm first. I’m pretty sure I won’t mess it up though…

What it does

The script will check a number of things in your farm by working on the output of the “stsadm –o enumallwebs” command.

I use some direct SQL to get information out that is not possible through the API, but all modifications are done through the SharePoint 2007 API in a supported way only.

The script currently does 5 things:

Remove Invalid Webparts

(AKA: “The following web part(s) are referenced by the content, but they are not installed on the web server“)

This is the method I started with and by far the biggest timesaver.

It uses the “stsadm –o enumallwebs” to get a list of webparts that’s currently missing in your farm. They have been uninstalled at some point and are now those webpart with “Fatal Errors” on some of your pages. Some of the missing webparts are not even listed as failing with fatal errors (they have socalled “bad markup”) they are just listed on the page with and ID and no description (i.e. if you go to a given page and add “?contents=1″ to go to the webpart maintenance page).

Trouble is that there can be lots of these and there is no easy way to find all the pages.

This function will query the SQL for the pages where these webparts are (both the one with fatal errors and the ones with “bad markup”) and then remove them through the API. The offending pages will be published (if not already), whatever checkouts they may have been there is overridden, the webparts are removed and the page re-published.

It will take all pages not just the one in document libraries (i.e. those that came through features)

Note: I’m only handling the case of shared webparts I did not have any user specific webparts in my test farm so I’m uncertain how that will be handled.

Note2: I’ve copied the PublishListItem from some of Gary Lapointes excellent extentions and converted them to powershell. It seems that no one has been as thorough handling special cases as he.

Remove Orphaned Site Collections

(AKA: “Issue : Orphaned site collections“)

Site collections can get orphaned in a number of ways; the fix is simply to delete those.

You will not lose anything (new) as those sites were not accessible before anyway.

Remove Uninstalled/missing Features Activated at Web scope

Features that have been uninstalled at some point often linger in the content databases because they are still activated in some web or site. That activation is not deleted when the feature is removed though the feature will have no actual function anymore.

I wrote quite a bit on this a while ago.

The script will run through all those SPWeb’s and deactivate the offending features.

Note that I’m not crawling all webs in the site I only access those with missing features.

Remove Uninstalled/missing Features Activated at Site Collection Scope

(AKA: “The following feature(s) are referenced by the content, but they are not installed on the web server“)

Similarly features may be activated at site collection level and forgotten. In this case these features are not reported by the “stsadm –o enumallwebs” command and I have to run through every Site Collection in the farm to locate the features.

Remove Missing Setup Files

(AKA: “The following setup file(s) are referenced by the content, but they are not installed on the web server“)

After features have been uninstalled it is quite common that they forget to remove the files they installed on the farm. I suppose it’s just the way SharePoint works. If a feature installs a file in a document library somewhere changes are it will remain.

What are those files? Some examples are stuff in the style library, webpart gallery, master pages, page layouts, etc…

This method uses SQL to find where the missing files are still references and deletes them from the lists. It even deletes files that have been unghosted which could actually still be accessed because SharePoint has made a customized copy of it.

I’m still considering if it would be better to only remove the ones that are still ghosted.

Note: In my tests some page layouts could not be removed because they were still being referenced in the farm. That is clearly an error in my farm, however the script will not fix that. It really does require special handling by a human to decide what to do. I suppose it’s a good thing that they are not removed in this case as some things might otherwise break.

What it does not no

Out of scope of script:

  1. Fixing the OS version
  2. Fixing the database version

Sorry ;-)

How to Execute

First of all the script requires you to be site collection owner on every site collection, farm admin and have owner rights in every content and configuration database. Pretty much all you can get.

In the beginning of the script there is a few switches that you should know:

  • The logging level, set it to 3 to get lots of info: $verboseLevel = 3. Lower is less.
  • The “$whatif” ´switch. Set it to “$true” to have the script simulate a run but not change anything in your farm
  • The “$targetdb” that can limit the script to a single content database only. Blank equals all databases a name indicates one (note: Not the site name)

I’ve built in a lot of error handling and logging to let you know what’s going on.

Note that STSADM must be included in the path setting.

Recommended sequence of execution

Everything need to run on the SharePoint 2007 server and it must have (at least) PowerShell 1.0 installed.

  1. Backup all content databases. This is not optional. Easiest to use stsadm –o backup
  2. Use stsadm -o preupgradecheck
  3. Run script on one or all databases with the “whatif” statement set to true
  4. Check and recheck the output and verify that it looks correct to you.
    1. You may want to reduce the logging level a bit
  5. Run with $whatif set to $false, i.e. let it work!
    1. Depending on your confidence in me you can ask to work on only one database at a time
  6. Check the output!
    1. Errors and warnings will be written both to the output stream (what is piped down in your logfile) and on the screen
  7. Run preupgradecheck again and see the result J

Note to run the script use something like “powershell -file FixUpgradeIssues.ps1 >>fixupdateoutput.txt”, i.e. always pipe the output to a file that you can investigate later.

Runtime is about 5 minutes on my 40+ database test system so reasonably ok given the task.

I’ve been working on this script for a couple of months and have fixed a huge number of issues and funny edge cases; however I’ve likely missed a few. Let me know in the comments.

Good luck J

Download the Actual Script

All 850 lines of powershelling are not pretty in a blog post, so you can download it here.

[Updaet 25-12-2010: Now with correct file]

How to Setup Kerberos SPNs for SharePoint


This is a fairly short post about how to setup kerberos for SharePoint 2007 and 2010 written because it is a subject that frequently continues to baffle SharePoint consultants.

Why

Kerberos authentication has been available since SharePoint 2003 yet most people are still using NTLM authentication. Why? NTLM is ancient and we all know that it works out of the box where Kerberos comes with a huge number of knowledge base articles and instruction to create Service Principal Names (SPNs) in your AD.

The reason for making the effort is that it enables you to solve the old double hop issue.

Ehh? When you are authenticated on a SharePoint server the server side code runs in “your name” with the privileges of your account. If however that server side code calls a second system, e.g. a web service, that second (the double hop) call is not authenticated and run with anonymous privileges. This is a limitation (or a security feature in your AD).

Now there are a number of ways around this problem, hardcoding some credentials in the server side, escalating privileges in the code, messing with the host file, etc. but the only good way is to use Kerberos.

Now when does this apply to SharePoint, where does it benefit from Kerberos? Then non-complete list is (additional suggestions welcome in the comments)

  • RSS viewer webpart
  • Page viewer webpart
  • Mail, calendar and task webparts (often used in MySites)
  • Excel services
  • Forms services
  • (and your custom code)

How to setup Kerberos

Now this is very far from a complete guide on Kerberos as it’s by far too long and too complicated for most people to read it. I’ll describe the simple bits needed to make SharePoint spin with Kerberos.

SharePoint setup

When you create a new web application you get the choice of using NTLM or Kerberos authentication. After creation you can always go into the authentication provider settings within the Central Administration and change it. Note: That a faulty Kerberos setup is virtually the same as bare NTLM ;-)

SPN setup

The hardest part is to setup Service Principal Names in your AD to enable SharePoint to use Kerberos properly. Basically a SPN is an entry into the AD allowing a specific service account for a service (e.g. HTTP) to re-authenticate a user.

The trick is of course what exactly should go into these SPNs and how many you need. The answer is:

  • One for each URL you are serving
  • One for each combination of server and app pool service account (if you are like me you’ll have multiple)

You use the “SetSPN.exe” program to do this and you need very high privileges to do so. Domain Admin or equivalent is sufficient ;-) though it could have been delegated to lower ranks. Note that this can be executed on any server in your domain not only the SharePoint servers.

The major point of this post is that I’ve created a small PowerShell script to generate a bat file that will create the SPNs required.

Given a config file (CreateSPNBatFile_config.xml) like this:

 <?xml version="1.0" ?> <Config> <Servers> <Server name="moss1" domain="internal.contoso.com" /> <Server name="moss2" domain="internal.contoso.com" /> <Server name="moss3" domain="internal.contoso.com" /> </Servers> <Urls> <Url hostheader="intranet" serviceaccount="contoso\sa_intranet" /> <Url hostheader="extranet.contoso.com" serviceaccount="contoso\sa_extranet" /> </Urls> </Config> 

The script (CreateSPNBatFile.ps1) (download here if quotes and stuff are messed up):

# Create a bat file for SPN creation based on config file # # 2010 Søren L. Nielsen function CreateSPNBatFile( $configFile, $outputFile ){ $config = [xml] (Get-Content $configFile) $output = "" #Gather all the service accounts $serviceAccounts = @{} foreach( $url in $config.Config.Urls.Url ){ $output += "Setspn.exe -A HTTP/" + $url.hostheader + " " + $url.serviceaccount + "`r`n" $serviceAccounts[ $url.serviceaccount.ToLower() ] = 1 } foreach( $server in $config.Config.Servers.Server ){ foreach( $serviceAccount in $serviceAccounts.Keys ){ #every combination of server and service account $output += "Setspn.exe -A HTTP/" + $server.name + "." + $server.domain + " " + $serviceAccount + "`r`n" } } $output += "pause`r`n" Set-Content -LiteralPath $outputFile -Value $output Write "Batch file $outputFile created" } CreateSPNBatFile "./CreateSPNBatFile_config.xml" "./CreateSPN.bat" 

Will generate the following bat file (CreateSPN.bat):

Setspn.exe -A HTTP/intranet contoso\sa_intranet Setspn.exe -A HTTP/extranet.contoso.com contoso\sa_extranet Setspn.exe -A HTTP/moss1.internal.contoso.com contoso\sa_extranet Setspn.exe -A HTTP/moss1.internal.contoso.com contoso\sa_intranet Setspn.exe -A HTTP/moss2.internal.contoso.com contoso\sa_extranet Setspn.exe -A HTTP/moss2.internal.contoso.com contoso\sa_intranet Setspn.exe -A HTTP/moss3.internal.contoso.com contoso\sa_extranet Setspn.exe -A HTTP/moss3.internal.contoso.com contoso\sa_intranet pause 

Ready to ship off to your domain administrator.

Trust for Delegation (Updated)

You need to configure the servers to be trusted for delegation in the AD (sorry I don’t know the command line). The procedure is:

  1. On any computer in the domain start Active Directory Users and Computers (“dsa.msc”)
  2. In the left pane, click Computers.
  3. In the right pane, right-click the name of your SharePoint server, and then click Properties.
  4. Click the Delegation tab (or General for WinSrv2000), click to select the Trust computer for delegation check box.
  5. Repeat step 3 and 4 for every SharePoint server in your farm including the SQL server

And you also need to configure the service accounts the same way (provided that they are domain accounts):

  1. On any computer in the domain start Active Directory Users and Computers (“dsa.msc”)
  2. Locate your service account in your AD (I generally prefer to search for the samAccountName)
  3. click Properties on the service account
  4. Click the Delegation tab (or General for WinSrv2000), click to select the Trust this user/computer for delegation to any service (Kerberos)  check box.
  5. Repeat step 3 and 4 for every service account in your farm including SQL account

Firewall

Kerberos uses port 88 to communicate with the AD server therefore that port need to be open between the AD and your servers. There likely are a bunch of additional ports – ask google not me.

Test

There are of course a number of ways to test this – look at the list above.

I generally start by enabling fiddler and check that the authentication part looks like a Kerberos ticket – fiddler will tell you this on the “Auth” tab.

The easiest test is to go to a list and get the RSS feed url. Then add a RSS viewer webpart to a page with that URL. If Kerberos works (for that site! You need to test all) you should see the list feed with the same elements as you would browsing directly to the RSS url.

If it does not work you’ll see the RSS feed as an anonymous user (note: Pick a list without anonymous access).

There are a large number of potential problems that would make this fail. Kerberos is very hard to debug – I can’t help you all but do try some of Microsofts tools.

I hope this help some of you with Kerberos. I had to hunt down a surprising number of post, documents and trial runs to compile this. Sorry for not sharing them all I simply don’t recall all of them as I did the installation over a year ago.

Note: If some users cannot authenticate but others get a “400 bad request” have a look here.

Follow

Get every new post delivered to your Inbox.