Upgrade multiple SharePoint content databases using PowerShell and XML

As a SharePoint Consultant, a lot of the work I do is around upgrades and migrations. I’ve done quite a few of these, and I’ve done them from 2003 to 2007, 2007 to 2010, and now 2010 to 2013. I’ve done several migrations where a 3rd party tool was used to migrate the content, but a lot of the time I end up using the standard database attach approach to move the content databases from the old farm to the new farm. In doing so, obviously PowerShell is required – but more times than not there are multiple content databases. Manually testing and mounting each one can be extremely time consuming, especially if you’re going to end up deploying the content to multiple farms (Dev, QA, DR, Production). What I’ve decided to do is actually build some PowerShell and XML that can be used both to run Test-SPContentDatabase as well as Mount-SPContentDatabase to allow you to do these in bulk.

When writing this script, I had a few things in mind that I wanted to accomplish:

  1. Provide 100% of the input to the script in the form of XML, allowing the script to be 100% separate from the parameters and input.
  2. Provide options to use Test OR Mount, depending on where I’m at in the migration. (It’s always recommended to run Test-SPContentDatabase BEFORE Mount-SPContentDatabase!)
  3. Provide readable output and progress indication to know where the script is in it’s execution.

To accomplish these 3 goals, I made sure to:

  • Include ALL of the available options when running Test-SPContentDatabase AND Mount-SPContentDatabase in the XML and Script (empty values are simply ignored).
  • Include SWITCH parameters for Test and Mount – to allow the user to specify their intention at runtime.
  • Include Write-Progress and Write-Output to provide clear output to the executing user.

Now that I’ve explained my intentions with writing this code, I’ll share it!

Here is an example of how you could use the XML:

<?xml version="1.0" encoding="utf-8" ?>
	<WebApp Url="http://portal.adventureworks.com">
			<Database Name="SP2010_Pub_Content_1" WarningSiteCount="0" MaxSiteCount="1" AssignNewDatabaseId="false" ChangeSyncKnowledge="false" ClearChangeLog="false" DatabaseCredentials="" DatabaseServer="SPSQL\Publishing" NoB2BSiteUpgrade="false" SkipIntegrityChecks="false"/>
			<Database Name="SP2010_Pub_Content_2" WarningSiteCount="5" MaxSiteCount="10" AssignNewDatabaseId="false" ChangeSyncKnowledge="false" ClearChangeLog="false" DatabaseCredentials="" DatabaseServer="SPSQL\Publishing" NoB2BSiteUpgrade="false" SkipIntegrityChecks="false"/>
	<WebApp Url="http://collab.adventureworks.com">
			<Database Name="SP2010_Collab_Content_1" WarningSiteCount="25" MaxSiteCount="30" AssignNewDatabaseId="false" ChangeSyncKnowledge="false" ClearChangeLog="false" DatabaseCredentials="" DatabaseServer="SPSQL\Collab" NoB2BSiteUpgrade="false" SkipIntegrityChecks="false"/>
			<Database Name="SP2010_Collab_Content_2" WarningSiteCount="50" MaxSiteCount="100" AssignNewDatabaseId="false" ChangeSyncKnowledge="false" ClearChangeLog="false" DatabaseCredentials="" DatabaseServer="SPSQL\Collab" NoB2BSiteUpgrade="false" SkipIntegrityChecks="false"/>

Here is the PowerShell code:

    This script leverages an XML file as the input - and based on the XML contents will attach one or more 
	content databases to one or more SharePoint 2010/2013 Web Applications.
    This PowerShell Script uses Get-Content, ForEach-Object and Mount-SPContentDatabase cmdlets along with 
	some other various code snippets to iterate through one or more web applications.
    While attaching content databases to a SharePoint 2010/2013 farm, it will use Write-Progress to provide an update in the PowerShell window.
    Mount-SPContentDatabasesFromXml.ps1 -XmlInput C:\ContentDatabases.xml
    This example will mount all content databases to all web applications specified in an XML file at C:\ContentDatabases.xml.
    Example XML syntax:
    <?xml version="1.0" encoding="utf-8" ?>
        <WebApp Url="http://igs">
                <Database Name="SP2010_Content_1" WarningLevel="5" MaxSites="10"/>
                <Database Name="SP2010_Content_2" WarningLevel="50" MaxSites="100"/>
    Name: Mount-SPContentDatabasesFromXml.ps1
    Author: Ryan Dennis
    Last Edit: 9/16/2013
    Keywords: Mount-SPContentDatabase, ForEach-Object, Get-Content, SharePoint Upgrade/Migration
#Requires -Version 2.0
# Look for the SharePoint Snapin and add it if not already added #
if ((Get-PSSnapin Microsoft.SharePoint.PowerShell) -eq $null)
    Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$FarmVersion = (Get-SPFarm).BuildVersion
if ($FarmVersion.Major -eq '15') {$FarmVersion = "2013"} 
elseif ($FarmVersion.Major -eq '14') {$FarmVersion = "2010"} 
else {$FarmVersion = ""}

# Load XML document #
[System.Xml.XmlDocument]$xml = Get-Content $($XmlInput)
if ($xml -eq $null)
    throw "XML input not found"

# Iterate through each WebApps.WebApp in the XML document and mount databases #
$dbCount = $xml.GetElementsByTagName("Database").Count
$xml.WebApps.WebApp | ForEach-Object {
$waUrl = $_.Url

    $_.Databases.Database | ForEach-Object {
        $dbName = $_.Name
		if (!([string]::IsNullOrEmpty($_.WarningSiteCount)))
		{$paramWarningSites = @{WarningSiteCount = $_.WarningSiteCount}}
		else{$paramWarningSites = ""}
		if (!([string]::IsNullOrEmpty($_.MaxSiteCount)))
		{$paramMaxSites = @{MaxSiteCount = $_.MaxSiteCount}}
		else{$paramMaxSites = ""}
		if (!([string]::IsNullOrEmpty($_.AssignNewDatabaseId)))
		{$paramNewDbId = @{AssignNewDatabaseId = $true}}
		else{$paramNewDbId = ""}
		if (!([string]::IsNullOrEmpty($_.ChangeSyncKnowledge)))
		{$paramChangeSync = @{ChangeSyncKnowledge = $true}}
		else{$paramChangeSync = ""}
		if (!([string]::IsNullOrEmpty($_.ClearChangeLog)))
		{$paramClearLog = @{ClearChangeLog = $true}}
		else{$paramClearLog = ""}
		if (!([string]::IsNullOrEmpty($_.DatabaseCredentials)))
		{$paramDbCreds = (Get-Credential -Message "Enter Database Credentials")}
		else{$paramDbCreds = ""}
		if (!([string]::IsNullOrEmpty($_.DatabaseServer)))
				$paramDbServer = @{ServerInstance = $_.DatabaseServer}
				$paramDbServer = @{DatabaseServer = $_.DatabaseServer}
		else{$paramDbServer = ""}
		if (!([string]::IsNullOrEmpty($_.NoB2BSiteUpgrade)))
		{$paramNoB2B = @{NoB2BSiteUpgrade = $true}}
		else{$paramNoB2B = ""}
		if (!([string]::IsNullOrEmpty($_.SkipIntegrityChecks)))
		{$paramSkipChecks = @{SkipIntegrityChecks = $true}}
		else{$paramSkipChecks = ""}
            # If Mount switch param is included, mount the databases #
				Write-Progress -Activity "Mounting $dbName to web application $($waUrl)" -PercentComplete ($i/$dbCount*100) -Status "Mounting content databases to SharePoint $FarmVersion"
				Mount-SPContentDatabase -Name $dbName -WebApplication $waUrl @paramNewDbId @paramChangeSync @paramClearLog @paramDbCreds @paramDbServer @paramMaxSites @paramNoB2B @paramSkipChecks @paramWarningSites
			# If Test switch param is included, test the databases #
				Write-Progress -Activity "Testing $dbName" -PercentComplete ($i/$dbCount*100) -Status "Testing content databases with SharePoint $FarmVersion"
				Write-Output "::Performing operation Test-SPContentDatabase on database: $dbName`n"
				Test-SPContentDatabase -Name $dbName -WebApplication $waUrl @paramDbCreds @paramDbServer
            Write-Error $_
    } #endDbForEach
} #endForEach

Generic Error on Listedit.aspx page after SP1 and Aug 2011 CU

Wow did this issue get under my skin.

At my current client, where their SharePoint 2010 Enterprise Intranet is about as business critical as a SP environment can be – I performed the SP1 and Aug 2011 CU updates. The updates themselves went about as smooth as could be expected, until we noticed that lists and libraries would give the generic error w/ correlation ID when navigating to the List Settings page (/_layouts/listedit.aspx).

This seemed like not too big of a deal on the first site collection we noticed it on – then we realized it was farm-wide.

After doing a lot of log-reading, re-running PSCONFIG.exe to ensure that everything completed from an upgrade perspective; we were in the dark…

This morning I noticed something while browsing through the layouts folder – listedit.aspx (and some other files) was modified on 6/8/2011 at 11:46 AM. Most of the other aspx files were showing a modified date much further in the past.

On a whim I copied listedit.aspx from a known-good farm into my broken farm and VOILA – lists and libraries work again.

This might not help anybody, because I couldn’t find anyone else having this exact issue – but I didn’t want to lose track of the “fix.”

Where did the View menu go in SharePoint 2010?

This is going to be a 2-part post…

1. The view menu is now in 2 different places.
2. Customized views will only display it in 1 place.

In SharePoint 2007, the View menu was right on the list toolbar as seen below.

In SharePoint 2010 it’s now in the ribbon:

But it’s also in the breadcrumb:

That is, unless you have a modified view page, in which case you only have it in the ribbon:

Modifying the view page (adding a web part to it, for example) takes away this functionality. The only way I’ve been able to get it back is to revert the view back to the “default” state.

First 2010 Implementation Complete! (Well, sort of)

As of 11/3/2010, my first “real” 2010 implementation is complete for my current client. This implementation was a small farm consisting of a SQL database server and a single SharePoint server (both VMs).

The SharePoint 2010 VM is Windows Server 2008 R2 with 8GB of RAM and it is an Enterprise license.

The migration was from MOSS 2007 Enterprise and I utilized the database attach method for the migration piece. In total, there were 3 content databases, 2 web applications and 76 site collections with a few hundred subwebs.

So far so good and the migration itself was very smooth.

Now the real fun begins, utilizing the new 2010 functionality!

PDFs no longer open in browser in SharePoint 2010

In MOSS, if you navigated to a library or performed a search for a PDF; you could click on it to open it right up in the browser. That is of course if you have Adobe Reader. 🙂

In 2010, if you do the same thing your used to, you will be prompted with the option to Save or Cancel.

To get the auto-open behavior back, go to Central Administration>Application Management>Manage Web Applications.

Click on the Web Application to select it, and click General Settings.

In the Web Application Settings dialog window, scroll down to Browser File Handling and change the setting from Strict to Permissive, and click OK.

Your PDF files should now open automatically as they did in previous versions of SharePoint.