woensdag, oktober 09, 2013

Troubleshooting restoring a site collection

The following applies to SharePoint 2013 RTM and potentially to SharePoint 2010, but was not tested.

Ever tried to backup and restore a site collection with PowerShell using a least privilege SPRestore account approach and bumped into some fatal errors? As a starter you should have followed the instructions that are documented on TechNet:

Restore site collections in SharePoint 2013
http://technet.microsoft.com/en-us/library/ee748655.aspx

Apparently this documention is not completely sufficient, as you bumped in some fatal errors and are seeking for help. In this blog I would like to discuss two error messages and show you how to address them.

Error 1: access denied

In PowerShell:

02/26/2013 15:38:27.95 PowerShell.exe (0x2B28) 0x2B78 SharePoint Foundation General ai1wu Medium System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)), StackTrace: at Microsoft.SharePoint.SPSite.Restore(String filename, Boolean isADMode, Boolean& readOnlyMode, Boolean& hadWriteLock) at Microsoft.SharePoint.Administration.​SPSiteCollection.Restore(String strSiteUrl, String strFilename, Boolean bOverwrite, Boolean bGradualDelete, Boolean hostHeaderAsSiteName, Boolean preserveSiteId) at Microsoft.SharePoint.PowerShell.SPCmdletRestoreSite.​InternalProcessRecord() at Microsoft.SharePoint.PowerShell.SPCmdlet.ProcessRecord() at System.Management.Automation.CommandProcessor.ProcessRecord() at System.Management.Automation.CommandProcessorBase.DoExecute() at System.Management.Automation.Internal.PipelineProcessor.Syn... 615fe450-5cc1-4608-a50d-edae5cd0d862

In ULS:

System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)), StackTrace: at Microsoft.SharePoint.SPSite.Restore(String filename, Boolean isADMode, Boolean& readOnlyMode, Boolean& hadWriteLock) at Microsoft.SharePoint.Administration.SPSiteCollection.Restore(String strSiteUrl, String strFilename, Boolean bOverwrite, Boolean bGradualDelete, Boolean hostHeaderAsSiteName, Boolean preserveSiteId) 

Solution to error 1

After some debugging we found out that the account additionally needs rights on the webapp. So ultimately one should provision an account using the following procedure:

  • Create the user SPRestore in Active Directory
  • Add the user to the local administrators group
  • Execute the Add-SPShellAdmin PowerShell command using your SPFarm account
  • Additionally execute the following PowerShell command (this is not documented within the TechNet article):
    $w = Get-SPWebApplication -identity $webapp
    $w.GrantAccessToProcessIdentity("SHAREPOINT2013\SPRestore")
    This action is equal to grant full control on the webapp via central administration. By the way, strangely, tests show that only read access is sufficient.
  • Using SQL Server Management Studio:
    Grant the SPRestore user the DB_Owner DB role of the relevant content database
    Grant SPRestore the fixed server role: securityadmin. Also strangely, although documented in the TechNet article, tests show that this latter grant is not required.

Error 2: no content database available

As you most probably already have experienced, a correctly provisioned account can still lead to the following fatal error:

In PowerShell:

Restore-SPSite : The operation that you are attempting to perform cannot be completed successfully. No content databases in the web application were available to store your site collection. The existing content databases may have reached the maximum number of site collections, or be set to read-only, or be offline, or may already contain a copy of this site collection. Create another content database for the Web application and then try the operation again.

In ULS:

System.InvalidOperationException: The operation that you are attempting to perform cannot be completed successfully. No content databases in the web application were available to store your site collection. The existing content databases may have reached the maximum number of site collections, or be set to read-only, or be offline, or may already contain a copy of this site collection. Create another content database for the Web application and then try the operation again. at Microsoft.SharePoint.Administration.SPContentDatabaseCollection​.FindBestContentDatabaseForSiteCreation(IEnumerable`1 contentDatabases, Guid siteIdToAvoid, Guid webIdToAvoid, SPContentDatabase database, SPContentDatabase databaseTheSiteWillBeDeletedFrom) at Microsoft.SharePoint.Administration.SPContentDatabaseCollection​.FindBestContentDatabaseForSiteCreation(SPSiteCreationParameters siteCreationParameters, Guid siteIdToAvoid, Guid webIdToAvoid, SPContentDatabase database, SPContentDatabase databaseTheSiteWillBeDeletedFrom) at Microsoft.SharePoint.Administration.SPSiteCollection.Restore(String strSiteUrl, String strFilename, Boolean bOverwrite, Boolean bGradualDelete, Boolean hostHeaderAsSiteName, Boolean preserveSiteId) at Microsoft.SharePoint.PowerShell.SPCmdletRestoreSite​.InternalProcessRecord() at Microsoft.SharePoint.PowerShell.SPCmdlet.ProcessRecord()

Solution to error 2

After some research (decompilation of the relevant methods within the SharePoint assemblies) it looks like SPSiteCollection.GetContentDatabase contains a bug. I created two c# snippets to simulate the innerworkings of the PowerShell command:

string SiteURL= "http://spdev/";
string BackupFile = @"c:\backup\backup.bak";
SPWebApplication webapp = SPWebApplication.Lookup(new Uri(SiteURL));
SPSiteCollection mySiteCols = webapp.Sites;
mySiteCols.Restore(SiteURL, BackupFile, true);

results in the exception.

string DatabaseServerName = "spdatabaseserver";
string ContentDatabaseName = "contentdb";
SPContentDatabase db= Support.GetContentDatabase(webapp, DatabaseServerName, ContentDatabaseName);
db.Sites.Restore(SiteURL, BackupFile, true);

does not result in the exception. This brings us to the conclusion that one should always specify database server name, and content database name. Instead of:

Restore-SPSite -Identity $SiteURL -Path $BackupFile –Force

Always use:

Restore-SPSite $SiteURL -path $BackupFile -force -databaseserver $DatabaseServerName -databasename $ContentDatabaseName

I hope this blog is of any help to all of you out there doing great SharePoint work. Please let me know if you need any further assistance.

2 opmerkingen:

Juha Alhojoki zei

Hi, thank you for sharing this information. Until I found your blog, I was lost with our problem. Our problem was related to moving site collections from one web application to another with Backup-SPSite and Restore-SPSite. Out of 256 site collections on refused to be restored until I found your blog post and added the databasename and databaseserver -parameters to Restore-SPSite. After that there were no more problems, so thanks.

Jedik zei

This is very nice article, clean and easy to read. That's the way to post articles.
And is of course very helpful. Thanks!