Impasse

Calendar WebPart and List Issue

Calendar Web Part doesnt get updated upon Moving to a new Web Application (Migration). So we gotta run powershell script for each Web Part (or Calendar Lists) to get them working. Update means updating CalendarSettings properties and replacing older URL to newer URL.

Also the Error will be that calendar cannot access the “Older URL” or “Older Content Database”.

********************************************

#Add SharePoint PowerShell SnapIn if not already added

if ((Get-PSSnapin “Microsoft.SharePoint.PowerShell” -ErrorAction SilentlyContinue) -eq $null) {
Add-PSSnapin “Microsoft.SharePoint.PowerShell”
}

$web = Get-SPWeb “http://myteam.au.mywestfield.com/erooms/be/GITC”

$mainCalendar = $web.Lists[“Calendar”]
$view = $mainCalendar.Views[“Calendar”]

$calSettings = $view.CalendarSettings
$view.CalendarSettings = $calSettings.Replace(“http://www.au.mywestfield.com/”, “http://myteam.au.mywestfield.com/”)
$calSettings = $view.CalendarSettings

$view.CalendarSettings = $calSettings.Replace(“http://my.scentregroup.com/”, “http://myteam.au.mywestfield.com/”)
Write-Host $view.CalendarSettings

$view.Update()

***************************************************

Impasse

Migration of Site Collections From one Web Application to Other

Summary

Moving 200 Sites From one Place to the other requires strategy to ensure that users are disturbed minimally. Following are the steps we are going to follow

  1. [Create Content Database]Create Specific Content Databases to push the applications in Web application.
  2. [Script to Move Sites]Script to Move Site Collections from one Web application to the other
  3. [Redirection] Putting redirection on Existing Sites so to redirect any calls going to older Site collections
  4. [Errors and Resolutions] Any possible Problems which will arise during movement and their resolutions

We are going to go about each module of this migration in details.

Create Content Databases

Create Content Databases using Central Administration into appropriate Web application. Decide first how many Site collections you want to dump in each database. In current case we have 4 Databases

  • SP10PROD_Content_ERooms_Archive
  •  SP10PROD_Content_ERooms1
  • SP10PROD_Content_ERooms2
  • SP10PROD_Content_ERooms3

Make sure you define limit (and alert on Reaching level) of Site Collections in each database bigger than the intended because if you reach the threshold it is going to throw execption while moving site.

Ensure to ask DBA team to add your newly created databases to Fail over cluster.

Also if you are using Office Web apps ask DBA team to given Owner rights to users : “AU\svc_sp10wordappp” & “AU\svc_sp10excelappp”

Access Rights for Web App Service Accounts
CREATE USER [AU\svc_sp10wordappp] FOR LOGIN [AU\svc_sp10wordappp] WITH DEFAULT_SCHEMA=[AU\svc_sp10wordappp]
GO
EXEC sp_addrolemember N'db_owner', N'AU\svc_sp10wordappp'
GO
 
CREATE USER
[AU\svc_sp10excelappp] FOR LOGIN [AU\svc_sp10excelappp] WITH DEFAULT_SCHEMA=[AU\svc_sp10excelappp]
GO
EXEC sp_addrolemember N'db_owner', N'AU\svc_sp10excelappp'
GO

Script to Move Sites

We have an existing Web Application containing many sites in it. So while writing script we need to ensure if some site has same web address as existing one, we rename the address for it.

Many sites are archived ones and they need to go to newly created archive database (we can identify that by confirming which DB currently a web application resides)

Internal links upon migration will only update the base address and not Managed Paths so we have to ensure that we use the same managed path. ( http://my.scentregroup.com/erooms/TMS) Make sure you create the managed path before migration.

It was decided to move 30 sites in each Content Database.

Ensure that you have following folder D:\Test-Backup\Results for backups and result sheet. Ensure availability of space on drive for the biggest web application you are going to move. (Update the quotes in script if copying)

if((Get-PSSnapin | Where {$_.Name -eq "Microsoft.SharePoint.PowerShell"}) -eq $null)
{
    Add-PSSnapin Microsoft.SharePoint.PowerShell;
}
 
$ErrorActionPreference = "Stop"
 
$outputPath = "D:\Test-Backup\Results.csv"
 
try
{
 
    Add-Content -Path $outputPath -Value "Site Name, Type,Message,Source Site Path,Source Site,DateTime,New Content DB,New Site Address"
 
    $siteUrl = "http://www.au.mywestfield.com/" #Read-Host "Enter Source Web Application URL" #"http://test.au.mywestfield.com"
    $rootSite = New-Object Microsoft.SharePoint.SPSite($siteUrl)
    $spWebApp = $rootSite.WebApplication
 
 
    $destinationSiteUrl "http://myteam.au.mywestfield.com" #Read-Host "Provide Destination Web Application URL" #"http://myteamst.au.mywestfield.com" 
    $destinationRootSite = New-Object Microsoft.SharePoint.SPSite($destinationSiteUrl)
    $destinationWebApp = $destinationRootSite.WebApplication
 
    $count = 0
    $sitesToSkip = @("/erooms/BAS","/erooms/CorporateFinance","/erooms/RASdebtorsportal")
    
    $siteCount = 0
    $ContentDB = "SP10PROD_Content_ERooms1"
    
    foreach($site in $spWebApp.Sites)
    {
 
       #Write-Host $site.URL
       $path = ($site.URL -split '.com/erooms/')[1]
      
       
       #Write-Host $path
       
       if($path -NotLike "")
       {
           #To Check if Site Collection Already exists. We will Log it in Log-File and skip the Site Collection
           $DestSites = $destinationWebApp.Sites |  where {$_.URL -Like $("*/s/" + $path)}  | measure-object #where {$_.URL.ToLower().Contains($path)}
           
            try
                {
                   if($DestSites.Count -eq 0)
                   {
                   
                        if($site.ContentDatabase.Name -eq "MOSSp_Content_eRoomsarchive")
                        {
                             # Moving All Archived Site Collections into on Dedicated database for that
                             Write-Host $("D:\\Test-Backup\" + $path + ".bak")   
                             
                             Backup-SPSite -Identity $site.URL -Path $("D:\Test-Backup\" + $path + ".bak") -force
                             Add-Content -Path $outputPath -Value $($site.Title + ",Success - Archive,Backup from Source Site Collection Successful," + $site.URL + "," + $path + "," + $(Get-Date))
                        
                             Restore-SPSite -Identity $("http://myteam.au.mywestfield.com/s/" + $path) -Path $("D:\\Test-Backup\" + $path + ".bak")  -DatabaseName "SP10PROD_Content_ERooms_Archive" -Confirm:$false -Force
                             Add-Content -Path $outputPath -Value $($site.Title + ",Success - Archive,Backup restored on New Web Application! Successful," + $site.URL + "," + $path + "," + $(Get-Date) + ",SP10PROD_Content_ERooms_Archive" + ",http://myteam.au.mywestfield.com/s/" + $path)
                            
                             Remove-Item ("D:\\Test-Backup\\" + $path + ".bak")
                             Add-Content -Path $outputPath -Value $($site.Title + ",Success - Archive,Backup File Removal Successful," + $site.URL + "," + $path + "," + $(Get-Date))
                             
                             #Remove-SPSite -Identity $site.URL -Confirm:$false 
                        }
                        else
                        {
                        
                            if($sitesToSkip -contains $( "/erooms/" + $path))
                            {
                                #SKipping Sites which were asked not to move rightnow
                                Write-Host $( "Site Skipped!!   " + $path)
                                Add-Content -Path $outputPath -Value $($site.Title + ",Skipped,Site is Skipped As per Instrcutions of Owner," + $site.URL + "," + $path + "," + $(Get-Date))
                            }
                            else
                            {
 
                                Write-Host $("D:\\Test-Backup\" + $path + ".bak")
                                
                                Backup-SPSite -Identity $site.URL -Path $("D:\Test-Backup\" + $path + ".bak") -force
                                Add-Content -Path $outputPath -Value $($site.Title + ",Success,Backup from Source Site Collection Successful," + $site.URL + "," + $path + "," + $(Get-Date))
                            
                                if($siteCount -lt 31)
                                {
                                    $ContentDB = "SP10PROD_Content_ERooms1"
                                    $siteCount = $sitecount + 1
                                }
                                elseif ($siteCount -gt 30 -and $siteCount -lt 61)
                                {
                                    $ContentDB = "SP10PROD_Content_ERooms2"
                                    $siteCount = $sitecount + 1
                                }
                                elseif($siteCount -gt 60)
                                {
                                    $ContentDB = "SP10PROD_Content_ERooms3"
                                    $siteCount = $sitecount + 1
                                }
                                Restore-SPSite -Identity $("http://myteam.au.mywestfield.com/s/" + $path) -Path $("D:\\Test-Backup\" + $path + ".bak") -DatabaseName $ContentDB -Confirm:$false -Force
                                Add-Content -Path $outputPath -Value $($site.Title + ",Success,Backup restored on New Web Application! Successful," + $site.URL + "," + $path + "," + $(Get-Date) + "," + $ContentDB + ",http://myteam.au.mywestfield.com/s/" + $path)
                                
                                
                                Remove-Item ("D:\\Test-Backup\\" + $path + ".bak")
                                Add-Content -Path $outputPath -Value $($site.Title + ",Success,Backup File Removal Successful," + $site.URL + "," + $path + "," + $(Get-Date))
                           
                            
                                #Remove-SPSite -Identity $site.URL -Confirm:$false  
                                #Remove-Item ("D:\\Test-Backup\\" + $path + ".bak")
                            }
                        }
                    }
                    else
                    {
                        Write-Host $( "Exists!!   " + $Dest.URL)
                        Add-Content -Path $outputPath -Value $($site.Name + ",Already Exists,Site with same Path already exists on Destination Server," + $site.URL + "," + $path + "," + $(Get-Date) +",,http://myteam.au.mywestfield.com/s/" + $path)
                    }
                       
                  # $count = $count+1
                  # if($count -eq 4)
                  # {
                  #     break
                  # }
                        
                }
                catch
                {
                    Write-Host $("Cannot Access Site Collection: " + $path + " ----- " + $error[0])
                    Add-Content -Path $outputPath -Value $($site.Title + ",Error,Site Collection Movement Unsuccessful -----" + $error[0] + "," + $site.URL + "," + $path + "," + $(Get-Date))                      
                }
        
            $site.Dispose()
    }
 
}
catch
{
     Write-Host $("Cannot Access Site Collection: " + $path + " ---- " + $error[0])
     Add-Content -Path $outputPath -Value $($site.Title + ",Error,Error in Script startup ----" + $error[0] + "," + $site.URL + "," + $path + "," + $(Get-Date))
}

Redirection

We are going to write the redirection logic in a DLL and deploy it at GAC. To enable redirection on a specific site we need to add entries into Web.Config files of corresponding legacy web applications from where we are migrating sites.

To keep the changes minimal and gradual movements of sites you can define 3 files which this code is using

  • C:\RedirectionModuleSites\Redirect.txt   (Data example: /erooms/AB_Project)
  • C:\RedirectionModuleSites\Newlocation.txt  (Data example: http://myTeam.au.mywestfield.com/erooms/)
  • C:\RedirectionModuleSites\SiteCollectionsWithChangedNames.txt    (Example Data: /erooms/marketing)

NewLocation.txt should contain only 1 like pointing to the new Web Application and Managed Path followed by /

Redirect.txt and  SiteCollectionsWithChangedNames.txt can have multiple lines representing the sites which are going to be move as they are and which on requires to make changes in their site address). Ensure in no file there are extra spaces or carriage returns.

These files and DLLS have to be copied on each server where Front web servers are running.

Create a Library project in visual studio. Add system.Web name space and this code

Redirection Module
public class DynamicModule: IHttpModule
     {
        
public void Init(HttpApplication context)
        {
            context.BeginRequest +=
new EventHandler(context_BeginRequest);
        }
        
void context_BeginRequest(object sender, EventArgs e)
        {
            
try
             {
                
HttpApplication application = (HttpApplication)sender;
                
HttpContext context = application.Context;
                
string httpUrl = context.Request.Url.ToString();
                
bool AlreadyUpdated = false;
                
if (httpUrl.ToLower().Contains("/erooms/"))
                {
                    
string[] AllSitesToRedirect = System.IO.File.ReadAllLines(@"C:\RedirectionModuleSites\Redirect.txt");
                    
string NewSiteURL = System.IO.File.ReadAllText(@"C:\RedirectionModuleSites\Newlocation.txt");
                    
string[] ChangedURLS = System.IO.File.ReadAllLines(@"C:\RedirectionModuleSites\SiteCollectionsWithChangedNames.txt");
                    
foreach (string ChangeURL in ChangedURLS)
                    {
                        
if (httpUrl.ToLower().Contains(ChangeURL.ToLower()))
                        {
                            AlreadyUpdated =
true;
                            
string[] _AddressBits = httpUrl.ToLower().Split(new string[1] { "/erooms/" }, StringSplitOptions.None);
                            
string _Address = "";
                            
if (_AddressBits.Length > 1)
                            {
                                _Address = NewSiteURL.Trim() + _AddressBits[1] +
"00";
                                
HttpContext.Current.Server.ClearError();
                                
HttpContext.Current.Response.Clear();
                                
HttpContext.Current.Response.Redirect(_Address, false);
                                
break;
                            }
                            
                        }
                    }
                    
if (AlreadyUpdated == false)
                    {
                        
foreach (string siteRedirect in AllSitesToRedirect)
                        {
                            
if (httpUrl.ToLower().Contains(siteRedirect.ToLower()))
                            {
                                
string[] _AddressBits = httpUrl.ToLower().Split(new string[1] { "/erooms/" }, StringSplitOptions.None);
                                
string _Address = "";
                                
if (_AddressBits.Length > 1)
                                {
                                    _Address = NewSiteURL.Trim() + _AddressBits[1];
                                    
HttpContext.Current.Server.ClearError();
                                    
HttpContext.Current.Response.Clear();
                                    
HttpContext.Current.Response.Redirect(_Address, false);
                                }
                                
break;
                            }
                        }
                    }
                }
            }
            
catch (Exception oEx)
            {
            }
        }
        
public void Dispose() { }
    }

Once DLL is copied in GAC and site path files set to their location. We need to update Web.Config files of Each legacy Web Application from where we want to redirect. In our case those arewww.au.mywestfield.com and my.scentregroup.com on each server
This entry ideally should go between <httpModules>  </httpModules> Tags, but in our case we need to also make this entry into <modules runAllManagedModulesForAllRequests=”true”> </modules> tags too in each web.config.

Web.Config Entries
<add name="DynamicModule" type="RedirectModule, RedirectModule.DynamicModule, Version=1.0.0.0, Culture=neutral, PublicKey=f4b26db776765b26" />

Errors and Resolutions

Managed Path:

Ensure that you keep the managed path same (“/erooms/” in our case). Or else the internal links within sharepoint Sites created by users will not work.

Calendar Web Part and Lists:

After Migration Calendar web part will still be pointing older sites and database. That is a known issue with Microsoft Calendar Web Part. And only resolution to it is update individually the Calendar Settings Property on Each List and Delete the older webpart and create them again every where. Script to update the Calendar List is Follows (Update the quotes in script if copying)

Calendar Web Part Fixing
if ((Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) {  Add-PSSnapin "Microsoft.SharePoint.PowerShell"  }
$mainCalendar = $web.Lists["Calendar"$view = $mainCalendar.Views["Calendar"]
$calSettings = $view.CalendarSettings
$view.CalendarSettings = $calSettings.Replace("http://www.au.mywestfield.com/", "http://myteam.au.mywestfield.com/")
$calSettings = $view.CalendarSettings
$view.CalendarSettings = $calSettings.Replace("http://my.scentregroup.com/", "http://myteam.au.mywestfield.com/")
Write-Host $view.CalendarSettings
$view.Update()

Office Web Apps not working:

If upon migration the Office web apps stop working (i.e. you cannot open Word/Excel/PowerPoint documents in browser check with the access rights to service accounts on newly created content databases. It has been mentioned above with SQL script to grant access to specific users.

Impasse

PowerShell – Delete all “deleted” site collections in a web application

When you delete a site collection, it actually stays kicking around for a while, as explained at

http://blogs.msdn.com/b/chaks/archive/2011/06/30/sharepoint-2010-sp1-site-recycle-bin-ui-experience.aspx.

As I happened to have a lot of deleted site collections I wanted to permanently remove, I was not satisfied with having to manually grab the site collection ID’s and plunk them into the Remove-SPDeletedSite PowerShell command one-by-one.

Also If you are in Migration and you are deleting and re-migrating sites you might come across problem which says

The site collection could not be restored. If this problem persists, please make sure the content databases are available and have sufficient free space.

Which is the misleading error, nevertheless Google search gave me the answer. However that is not always the case this error could be generated because of several other reasons too.

So, below is the method to delete ALL the “deleted” site collections under a specified web application. In this case, the web application URL is http://sharepoint – replace with your own desired web app URL:

1
Get-SPDeletedSite -webapplication "http://sharepoint" | Remove-SPDeletedSite

You will be prompted to delete them one by one, if you want it to run through them all without further prompts just Yes To All