harbar.net component based software & platform hygiene

Rational Guide to Multi Tenancy with SharePoint 2010, Part Four: Configuring the base infrastructure

Print | posted on Saturday, September 11, 2010 6:13 AM



This, the fourth part of the Rational Guide article on multi tenancy will start to walk through the configuration of the sample scenario detailed in the previous part. This is where we get into the meat of things.

If you haven’t checked out the previous parts, I strongly encourage you to review them. I won’t repeat information and I assume you have read the previous parts, which are:

  1. Feature and Capability Overview
  2. Planning your Deployment
  3. Example Scenario and what Multi Tenancy brings to the party
  4. Configuring the base Infrastructure (this article)
  5. Configuring Partitioned Service Applications
  6. Provisioning Tenants
  7. Testing the Functionality


Before we get started, a warning. From here on out there’s going to be lots of Windows PowerShell. I am deliberately splitting things up into different posts based on feedback, and in order to explain the steps adequately. However, the idea is that these scripts can be combined to enable the delivery of all the core services with basic configuration, plus a couple of tenants from scratch in about 10 minutes.

I will highlight the elements of the scripts which are pertinent only. Thus I expect you, the reader to be familiar with core PowerShell concepts and so forth. I will also call out any wackiness that may enter into play. Furthermore, the example scenario is deliberately simple. I’ve cut out as much extraneous details as I can to focus in on the specifics for multi tenant environments. Which brings us nicely to…

The base infrastructure – for this example scenario, I am running a single SharePoint server. I have separate machines for my Domain Controller and my SQL Server. That’s just a personal choice I’ve made on my rig. You can use these instructions on a single box with all those roles combined if you wish. In the real world, of course, you would have more than one SharePoint server, and these scripts would need tweaked to accommodate the specific topology. But remember, this article is not about topology it’s about tenancy!

My single SharePoint server is a Windows 2008 R2 base image with the SharePoint bits installed. That’s it. I have not run the SharePoint Configuration Wizard or anything else. It’s a clean start point. Make sure you have a similar base image to work with before attempting to use these scripts.

DNS, Active Directory and SQL Requirements

For the sample scenario, there are some simple pre-requisites as far as DNS and Active Directory are concerned.


Because I have chosen to use host named site collections, I need three DNS A Records, one for each of my tenants. Don’t use C Names (Aliases)! To keep things simple I am naming these microsoft.sharepoint.com, oracle.sharepoint.com and apple.sharepoint.com. Of course I have these configured to point to my SharePoint server, which is named SPH1:



Active Directory

The AD configuration is also very simple. I’ve configured some service accounts, which will be used later. This is all standard stuff you should be doing anyway. Here you can see those accounts:

Service Accounts

Next up is an Organizational Unit Hierarchy. Now this is very important. We need this to support both the configuration of the People Picker on a per tenant basis, but also for the User Profile Sync capability.

There is a limitation with the way the OU is specified for profile sync. When we configure this later, we can only specify a name, we cannot specify a DN. Therefore we need one level at which all customers users are stored. And of course we cannot have two OUs with the same name at the same level. This “limitation” is a design constraint and will not be changed in the future. This is how you must do it. If you think you can be clever here and trick it, you can’t! So don’t try!

As you can see below, I have an OU called Customers, and within that I have an OU for each of my tenants (Microsoft, Oracle and Apple). Each individual customer OU contains a tenant admin user and then some regular users.

Tenants in AD


SQL Server

For SQL Server I’ve simply gone ahead and added my setup account, with the appropriate permissions needed to create the farm. Nothing specific here to tenancy at all.

There you go, nothing complicated. Some very simple pre-reqs before moving onto the SharePoint box.

Creating the SharePoint Farm and setup the core infra

Now we can get to the PowerShell. All we are doing at this stage is creating ourselves a new Farm and provisioning Central Administration. This part is very simple. We start with some variables, which you will need to update for your environment. We then go ahead and perform the tasks that would be run if we had run PSConfig (the SharePoint Configuration Wizard). we will be prompted to enter the password for the Farm account.

Add-PSSnapin Microsoft.SharePoint.Powershell -EA 0 

# Settings
$databaseServer = "SQL"
$configDatabase = "HostingFarm_Config"
$adminContentDB = "HostingFarm_Content_Admin"
$passphrase = "Password1"
$farmAccountName = "SHAREPOINT\spfarm"
$farmAccount = Get-Credential $farmAccountName
$passphrase = (ConvertTo-SecureString $passphrase -AsPlainText -force)

# will error, but fix the regkey...
# we do this to prevent an error if the machine state registry key is not correctly set,
# which will prevent the next command from completing.
psconfig.exe -cmd upgrade
Write-Host "Creating Configuration Database and Central Admin Content Database..."
New-SPConfigurationDatabase -DatabaseServer $databaseServer -DatabaseName $configDatabase `
    -AdministrationContentDatabaseName $adminContentDB `
    -Passphrase $passphrase -FarmCredentials $farmAccount
$spfarm = Get-SPFarm -ErrorAction SilentlyContinue -ErrorVariable err        
if ($spfarm -eq $null -or $err) {
   throw "Unable to verify farm creation."

Write-Host "ACLing SharePoint Resources..."
Write-Host "Installing Services ..."
Write-Host "Installing Features..."
Install-SPFeature -AllExistingFeatures

Write-Host "Creating Central Administration..."              
New-SPCentralAdministration -Port 8080 -WindowsAuthProvider NTLM

Write-Host "Installing Help..."
Install-SPHelpCollection -All        
Write-Host "Installing Application Content..."

Write-Host "Farm Creation Done!"

That’s it – very simple so far! In the next part, we are going to create and configure some other base requirements. These are the non tenant Service Applications, things like the State Service. Then we will will setup our Web Application and Managed Paths.

Again, before we do any work we need to set some variables for naming and so on. We are going to run all our Service Applications in an Application Pool named SharePoint Web Services Default and we will host a single Content Web Application named http://sph1 in an application pool named SharePoint Content:

# App Pools
$saAppPoolName = "SharePoint Web Services Default"
$saAppPoolUserName = "SHAREPOINT\spservices"
$waAppPoolName = "SharePoint Content"
$waAppPoolUserName = "SHAREPOINT\spcontent"

# Service Application and DB names
$stateName = "Hosting Farm State Service"
$stateDBName = "HostingFarm_StateService"
$usageName = "Hosting Farm Usage and Health Data Collection Service"
$usageDBName = "HostingFarm_Usage"
$subsInstanceName = "SPSubscriptionSettingsServiceInstance"
$subsName = "Hosting Farm Subscription Settings"
$subsDBName = "HostingFarm_SubscriptionSettings"

# Web App details
$hostingMainURL = "http://sph1"
$webAppName = "SharePoint Hosting"
$contentDBName = "HostingFarm_Content_Hosting"

# Root Site Collection details
$ownerEmail = "administrator@sharepoint.com"
$ownerAlias = "SHAREPOINT\administrator"


Next we move on and create a couple Managed Accounts and the Application Pool for the Service Applications:

# Create Managed Accounts and Application Pools
# Service Apps
Write-Host "Please supply the password for the $saAppPoolUserName Account..."
$appPoolCred = Get-Credential $saAppPoolUserName
$saAppPoolAccount = New-SPManagedAccount -Credential $appPoolCred
$saAppPool = New-SPServiceApplicationPool -Name $saAppPoolName -Account $saAppPoolAccount
# Web app
Write-Host "Please supply the password for the $waAppPoolUserName Account..."
$appPoolCred = Get-Credential $waAppPoolUserName
$waAppPoolAccount = New-SPManagedAccount -Credential $appPoolCred

Note that there is no way to create a “normal” application pool using SharePoint PowerShell. This doesn’t matter in this case, as it’s handled for us when we create our Web Application later.

Now we move on and create the “core” Service Applications and start any associated Service Instances. None of these have tenant specific properties, these are just the ones we should be running in every farm.

<# Create State Service Application and Proxy, and add to default proxy group
        we need the state service for many things, like workflow and the like
        State isn't a "real" service application, note the lack of app pool etc
Write-Host "Creating $stateName Application and Proxy..."
$stateDB = New-SPStateServiceDatabase -Name $stateDBName
$state = New-SPStateServiceApplication -Name $stateName -Database $stateDB
New-SPStateServiceApplicationProxy -Name "$stateName Proxy" -ServiceApplication $state -DefaultProxyGroup

<# Setup the Usage Service App
        configuring Search later will do this automatically but uses default names
        we cannot change the Proxy name
        Usage isn't a "real" service application, note the lack of app pool etc
Write-Host "Creating $usageName Application and Proxy..."
$serviceInstance = Get-SPUsageService
New-SPUsageApplication -Name $usageName -DatabaseName $usageDBName -UsageService $serviceInstance

Next up is the Subscription Settings service - this is the guy that’s going to keep track of all our Subscription IDs etc:

<# Setup the Subscription Settings Service Application & Proxy and start the service instance
        we cannot change the Proxy name or Proxy Group
Write-Host "Creating $subsName Application and Proxy..."
$subs = New-SPSubscriptionSettingsServiceApplication –ApplicationPool $saAppPool –Name $subsName –DatabaseName $subsDBName
$proxy = New-SPSubscriptionSettingsServiceApplicationProxy –ServiceApplication $subs 
Write-Host "Starting subsInstanceName..."
Get-SPServiceInstance | where{$_.GetType().Name -eq $subsInstanceName} | Start-SPServiceInstance


The next stage is to create our Content Web Application – this is where our tenants will be hosted:

<# Create a new Web App using Claims (Windows (NTLM))
      Note the Path is set automatically if omitted
      DefaultProxyGroup is used if omitted
      -Port 80 will only work if there are no apps on this port unless we specify a host header
      we do not want a host header, as we will be using host named site collections
      we do this now so that the app pool identity is added to the perms of SAs for us later 

$authProvider = New-SPAuthenticationProvider
$webApp = New-SPWebApplication -ApplicationPool $waAppPoolName -ApplicationPoolAccount $waAppPoolAccount -Name $webAppName -Port 80 -AuthenticationProvider $authProvider -DatabaseName $contentDBName

# Set sensible content db limits
Set-SPContentDatabase $contentDBName  -MaxSiteCount 50 -WarningSiteCount 30
# we could create more cdbs for the webapp here

It is important to do this here, as it means the application pool hosting it will be added to our Service Application permissions automatically when we create them later. Make sure you don’t use a host name on the Web App – that will stop users accessing our host named site collations later.

I strongly recommend you use Claims mode for multi-tenant environments.

Now we have a Web App its time to create a Site Collection at the root. Although no one will ever use this guy, you should be doing this as a matter of course. In our scenario, it is required to allow us to turn on self service site creation.

<# Create Site Collection at root
        This wont ever be accessed by users
        It is required in order to enable self service site creation, and good practice to have a SC at the root.
        We do NOT need to create a site from a template, we are creating an Empty site
New-SPSite -Url $hostingMainURL -owneralias $ownerAlias -ownerEmail $ownerEmail
We must use stsadm to enable self service site creation. There is no PowerShell cmdlet for this yet. We do this to allow tenant administrators to create site collections from tenant administration.
# Enable Self Service Site Creation -there is no powershell cmdlet for this yet
stsadm -o enablessc -url $hostingMainURL

We can alternatively configure Self Service Site Creation with Windows PowerShell by setting properties of the Web Application:

# Enable Self Service Site Creation 
$webApp.SelfServiceSiteCreationEnabled = $true
$webApp.RequireContactForSelfServiceSiteCreation = $false

Now we have our Web App and Site Collection, we need to configure the managed paths needed for our scenario. Note that this is the only way to create managed paths which are shared across host named site collections.

<# Create the required Managed Paths
        to support our intended deployment/features
        we remove the default 'sites' path on the app so we can prevent sites being created from CA.
        -hostheader shares the managed path across all host header based site collections and doesn't appear in CA.
        'sites' is there by default also for HostHeader, we will use that for member sites
Remove-SPManagedPath "sites" -WebApplication $webApp -Confirm:$false
New-SPManagedPath "admin" -HostHeader -Explicit #tenant admin
New-SPManagedPath "cthub" -HostHeader -Explicit #content type gallery
New-SPManagedPath "mysites" -HostHeader -Explicit #mysite host
New-SPManagedPath "mysites/personal" -HostHeader #mysites

Write-Host "Initial SAs and Hosting WebApp Done!"



And that’s that – pretty simple stuff! In the next part we will move on to creating the partitioned service applications. Stay Tuned!

If you want the entire script for this part, it’s available on the TechNet Script Center. Note that the TechNet script center doesn’t allow updating old posts due to a flaw in it’s new implementation. Thus the script there does not include the Windows PowerShell for Self Service Site Creation.