Installing SharePoint 2010 via Powershell

May 9, 2011 7 comments

Installing & configuring a SharePoint 2010 farm environment can be a difficult task. It involves a lot of research, manual configuration, troubleshooting issues etc. To make things worse, administrators rarely document the installation/upgrade process. PowerShell scripts can be used to perform any install/configure/upgrade scenario and can be documented to act as a installation/environment guide. These scripts can then be used to re-create SharePoint farm environments in a consistent manner e.g. QA/DR environments. As a SharePoint consultant I am often tasked with installing SharePoint farms. PowerShell scripts saves me a lot of time and has become an irreplaceable tool in my toolbox.

This blog documents my approach to installing & configuring a SharePoint 2010 farm environment via PowerShell scripts. The process below serves as an example for installing, configuring & upgrading a SharePoint 2010 farm. For the sake of brevity, I have omitted detailed explanations for the steps taken. There are still some manual steps involved, but I’m in the process of creating PowerShell scripts for them. I also cannot take credit for the scripts used as they have been gathered from my research on the web.

Please note, the scripts need to be tailored for your environment. This mostly involves changing the parameters at the beginning of the scripts. Don’t just blindly run the scripts in PowerShell (some people do), rather use an PowerShell ISE to step through the script line for line. I use PowerShell ISE (enable the feature in Windows 2008) or PowerGUI Script Editor. That way you can debug the scripts and correct problems before the rest of the script runs.

Accounts:
I generally use these accounts for an enterprise farm environment. For smaller environments, you can probably get away with only the SP_Farm, SP_Service accounts.

  • SP_Admin (Install account):
    • Must be Local Administrator on all SharePoint servers.
    • Needs database permissions (securityadmin, dbcreator, db_owner if running powershell scripts that affect the database)
  • SP_Farm (The Database access account):
    • Is automatically granted dbcreator, securityadmin & db_owner roles in database.
    • The DOMAIN\SPFARM account requires the log on locally right on the machine running the User Profile Synchronization (FIMSync) service (CentralAdmin application server).
      1. Security Settings – > Local Policies -> User Rights Assignment -> Allow Logon Locally
      2. If on a DC ( you shouldn’t be :)) GPMC.MSC and edit the default domain controller policy
      3. Run gpupdate to refresh the policy change
    • Must be Local Administrator on the Central Admin application server. The local administrator rights are only required during User Profile SSA provisioning. After that, remove SP_Farm from Administrators.
  • SP_Service (Application Pools & Service account)
  • SP_SuperUser (SharePoint cache user account)
  • SP_SuperReader (SharePoint cache user account)
  • SP_SearchCrawl (Search content access account)
    • Must only have “Full Read” permissions in the user policy for the applicable web applications. Else, you will see a lot of garbage in your search results.
  • SP_UserProfileSync
    • Needs “Replicating Directory Changes” on the Domain you are syncing with.

Before installing:

  • Plan your server topology e.g. what services on which server etc.
  • Host headers? This is important for when creating web applications.
  • NLB? Affinity doesn’t matter, Unicast/Multicast?
  • According to health analyser no services should run as SP_Farm
  • Using built-in accounts like Network Service or Local System as application pool or as service identities is not supported in a farm configuration.
  • When you go to add a new server to the farm (unless you do some SQL permission setting), you will have to be logged in as SP_Farm, not SP_admin.
  • When upgrading from the Standard edition to the Enterprise edition, log in as SP_Farm onto the box.

Installation steps:

  • Create the above accounts.
  • Reboot all servers for changes to take effect.
  • Install SharePoint via installer (Complete) on all servers. This is just to install the binaries onto the server. You can use scripts to do this, but I generally just use the installer for this.
  • Apply latest CU updates on all servers.
  • Configure the farm: Run ConfigureFarm.ps1 on the Central Administration Application Server.
    • 		Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
      		
      		## Settings you may want to change ##
      		$databaseServerName = "dbservername"
      
      		# create a new configuration database and central admin content database.  
      		New-SPConfigurationDatabase –DatabaseName "SharePoint_Config" –DatabaseServer $databaseServerName –AdministrationContentDatabaseName "SharePoint_Admin" –Passphrase (ConvertTo-SecureString "P@ssphr@se" –AsPlaintext –Force) –FarmCredentials (Get-Credential)
      
      		# install the help files
      		Install-SPHelpCollection -All 
      
      		# secure the files and registry entries on the server 
      		Initialize-SPResourceSecurity
      
      		# Provision the services onto the farm
      		Install-SPService        #(for server farm installations) 
      		#Install-SPService  -Provision  #(for standalone servers only) 
      
      		# install the features on the server.  
      		Install-SPFeature –AllExistingFeatures
      
      		# provision the central admin web application on our desired port
      		New-SPCentralAdministration -Port 10000  -WindowsAuthProvider "NTLM"
      
      		# install all of the application content
      		Install-SPApplicationContent 
      
      		# disable the loopback check
      		New-ItemProperty HKLM:\System\CurrentControlSet\Control\Lsa -Name "DisableLoopbackCheck"  -value "1" -PropertyType dword
      		
    • When prompted, enter credentials for SP_Farm account.
    • If it can’t access the database, login as SP_Farm or give SP_Admin access in DB.
  • Add the other servers to farm via the Configuration wizard.
  • Add SP_Admin to farm administrators in Central Administration.
  • Create the standard shared-service applications: Run ConfigureSSAStandard.ps1 (use SP_Service account)
    • 		################################################################################
      		## This script replicates most of the functionality found in the Config Wizard##
      		################################################################################
      		 
      		Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
      		 
      		## Settings you may want to change ##
      		$databaseServerName = "dbservername"
      		$saAppPoolName = "SharePoint Web Services"
      		$appPoolUserName = "domain\SP_Service"
      		  
      		## Service Application Service Names ##
      		$bcsSAName = "Business Data Connectivity Service"
      		$metadataSAName = "Managed Metadata Web Service"
      		$stateSAName = "State Service"
      		$secureStoreSAName = "Secure Store Service"
      		$usageSAName = "Usage and Health Data Collection Service"
      		$userProfileSAName = "User Profile Synchronization Service"
      		$WebAnalyticsSAName = "Web Analytics Service"
      		$WordAutomationSAName = "Word Automation Services"
      		
      		 
      		$saAppPool = Get-SPServiceApplicationPool -Identity $saAppPoolName -EA 0
      		if($saAppPool -eq $null)
      		{
      		  Write-Host "Creating Service Application Pool..."
      		 
      		  $appPoolAccount = Get-SPManagedAccount -Identity $appPoolUserName -EA 0
      		  if($appPoolAccount -eq $null)
      		  {
      			  Write-Host "Please supply the password for the Service Account..."
      			  $appPoolCred = Get-Credential $appPoolUserName
      			  $appPoolAccount = New-SPManagedAccount -Credential $appPoolCred -EA 0
      		  }
      		 
      		  $appPoolAccount = Get-SPManagedAccount -Identity $appPoolUserName -EA 0
      		 
      		  if($appPoolAccount -eq $null)
      		  {
      			Write-Host "Cannot create or find the managed account $appPoolUserName, please ensure the account exists."
      			Exit -1
      		  }
      		 
      		  New-SPServiceApplicationPool -Name $saAppPoolName -Account $appPoolAccount -EA 0 > $null	
      		}
      
      		Write-Host "Creating Usage Service and Proxy..."
      		$serviceInstance = Get-SPUsageService
      		New-SPUsageApplication -Name $usageSAName -DatabaseServer $databaseServerName -DatabaseName "SharePoint_UsageDB" -UsageService $serviceInstance > $null
      		 
      		Write-Host "Creating BCS Service and Proxy..."
      		New-SPBusinessDataCatalogServiceApplication -Name $bcsSAName -ApplicationPool $saAppPoolName -DatabaseServer $databaseServerName -DatabaseName "SharePoint_BusinessDataCatalogDB" > $null
      		Get-SPServiceInstance | where-object {$_.TypeName -eq "Business Data Connectivity Service"} | Start-SPServiceInstance > $null
      		 
      		Write-Host "Creating Metadata Service and Proxy..."
      		New-SPMetadataServiceApplication -Name $metadataSAName -ApplicationPool $saAppPoolName -DatabaseServer $databaseServerName -DatabaseName "SharePoint_MetadataDB" > $null
      		New-SPMetadataServiceApplicationProxy -Name "$metadataSAName Proxy" -DefaultProxyGroup -ServiceApplication $metadataSAName > $null
      		Get-SPServiceInstance | where-object {$_.TypeName -eq "Managed Metadata Web Service"} | Start-SPServiceInstance > $null
      		  
      		Write-Host "Creating State Service and Proxy..."
      		New-SPStateServiceDatabase -Name "SharePoint_StateServiceDB" -DatabaseServer $databaseServerName | New-SPStateServiceApplication -Name $stateSAName | New-SPStateServiceApplicationProxy -Name "$stateSAName Proxy" -DefaultProxyGroup > $null
      		  
      		Write-Host "Creating Secure Store Service and Proxy..."
      		New-SPSecureStoreServiceapplication -Name $secureStoreSAName -Sharing:$false -DatabaseServer $databaseServerName -DatabaseName "SharePoint_SecureStoreServiceAppDB" -ApplicationPool $saAppPoolName -auditingEnabled:$true -auditlogmaxsize 30 | New-SPSecureStoreServiceApplicationProxy -name "$secureStoreSAName Proxy" -DefaultProxygroup > $null
      		Get-SPServiceInstance | where-object {$_.TypeName -eq "Secure Store Service"} | Start-SPServiceInstance > $null
      		  
      		Write-Host "Creating User Profile Service and Proxy..."
      		$userProfileService = New-SPProfileServiceApplication -Name $userProfileSAName -ApplicationPool $saAppPoolName -ProfileDBServer $databaseServerName -ProfileDBName "SharePoint_ProfileDB" -SocialDBServer $databaseServerName -SocialDBName "SharePoint_SocialDB" -ProfileSyncDBServer $databaseServerName -ProfileSyncDBName "SharePoint_SyncDB"
      		New-SPProfileServiceApplicationProxy -Name "$userProfileSAName Proxy" -ServiceApplication $userProfileService -DefaultProxyGroup > $null
      		Get-SPServiceInstance | where-object {$_.TypeName -eq "User Profile Service"} | Start-SPServiceInstance > $null
      		  
      		Write-Host "Creating Web Analytics Service and Proxy..."
      		$stagerSubscription = "<StagingDatabases><StagingDatabase ServerName='$databaseServerName' DatabaseName='SharePoint_StagerDB'/></StagingDatabases>"
      		$reportingSubscription = "<ReportingDatabases><ReportingDatabase ServerName='$databaseServerName' DatabaseName='SharePoint_WarehouseDB'/></ReportingDatabases>" 
      		New-SPWebAnalyticsServiceApplication -Name $WebAnalyticsSAName -ApplicationPool $saAppPoolName -ReportingDataRetention 20 -SamplingRate 100 -ListOfReportingDatabases $reportingSubscription -ListOfStagingDatabases $stagerSubscription > $null  
      		New-SPWebAnalyticsServiceApplicationProxy -Name "$WebAnalyticsSAName Proxy" -ServiceApplication $WebAnalyticsSAName > $null
      		Get-SPServiceInstance | where-object {$_.TypeName -eq "Web Analytics Web Service"} | Start-SPServiceInstance > $null
      		Get-SPServiceInstance | where-object {$_.TypeName -eq "Web Analytics Data Processing Service"} | Start-SPServiceInstance > $null
      		  
      		Write-Host "Creating Word Conversion Service and Proxy..."
      		New-SPWordConversionServiceApplication -Name $WordAutomationSAName -ApplicationPool $saAppPoolName -DatabaseServer $databaseServerName -DatabaseName "SharePoint_WordAutomationDB" -Default > $null
      		Get-SPServiceInstance | where-object {$_.TypeName -eq "Word Automation Services"} | Start-SPServiceInstance > $null
      		
      		
    • When prompted, enter credentials for SP_Service account
    • Put breakpoint on second SSA creation, cause sometimes it fails.
  • Create the enterprise shared-service applications: Run ConfigureSSAEnterprise.ps1 (use SP_Service account).
    • 		################################################################################
      		## This script replicates most of the functionality found in the Config Wizard##
      		################################################################################
      		 
      		Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
      		 
      		## Settings you may want to change ##
      		$databaseServerName = "dbservername"
      		$saAppPoolName = "SharePoint Web Services"
      		$appPoolUserName = "domain\SP_Service"
      		  
      		## Service Application Service Names ##
      		$accesssSAName = "Access Services"
      		$excelSAName = "Excel Services"
      		$performancePointSAName = "PerformancePoint Service"
      		$visioSAName = "Visio Graphics Service"
      
      		 
      		$saAppPool = Get-SPServiceApplicationPool -Identity $saAppPoolName -EA 0
      		if($saAppPool -eq $null)
      		{
      		  Write-Host "Creating Service Application Pool..."
      		 
      		  $appPoolAccount = Get-SPManagedAccount -Identity $appPoolUserName -EA 0
      		  if($appPoolAccount -eq $null)
      		  {
      			  Write-Host "Please supply the password for the Service Account..."
      			  $appPoolCred = Get-Credential $appPoolUserName
      			  $appPoolAccount = New-SPManagedAccount -Credential $appPoolCred -EA 0
      		  }
      		 
      		  $appPoolAccount = Get-SPManagedAccount -Identity $appPoolUserName -EA 0
      		 
      		  if($appPoolAccount -eq $null)
      		  {
      			Write-Host "Cannot create or find the managed account $appPoolUserName, please ensure the account exists."
      			Exit -1
      		  }
      		 
      		  New-SPServiceApplicationPool -Name $saAppPoolName -Account $appPoolAccount -EA 0 > $null	
      		}
      
      		Write-Host "Creating Access Services and Proxy..."
      		New-SPAccessServiceApplication -Name $accesssSAName -ApplicationPool $saAppPoolName > $null
      		Get-SPServiceInstance | where-object {$_.TypeName -eq "Access Database Service"} | Start-SPServiceInstance > $null
      
      		Write-Host "Creating Excel Service..."
      		New-SPExcelServiceApplication -name $excelSAName -ApplicationPool $saAppPoolName > $null
      		Set-SPExcelFileLocation -Identity "http://" -ExcelServiceApplication $excelSAName -ExternalDataAllowed 2 -WorkbookSizeMax 10 -WarnOnDataRefresh:$true 
      		Get-SPServiceInstance | where-object {$_.TypeName -eq "Excel Calculation Services"} | Start-SPServiceInstance > $null
      		 
      		Write-Host "Creating Performance Point Service and Proxy..."
      		New-SPPerformancePointServiceApplication -Name $performancePointSAName -ApplicationPool $saAppPoolName > $null
      		New-SPPerformancePointServiceApplicationProxy -Default -Name "$performancePointSAName Proxy" -ServiceApplication $performancePointSAName > $null
      		Get-SPServiceInstance | where-object {$_.TypeName -eq "PerformancePoint Service"} | Start-SPServiceInstance > $null
      		   
      		Write-Host "Creating Visio Graphics Service and Proxy..."
      		New-SPVisioServiceApplication -Name $visioSAName -ApplicationPool $saAppPoolName > $null
      		New-SPVisioServiceApplicationProxy -Name "$visioSAName Proxy" -ServiceApplication $visioSAName > $null
      		Get-SPServiceInstance | where-object {$_.TypeName -eq "Visio Graphics Service"} | Start-SPServiceInstance > $null
      		
      		
    • When prompted, enter credentials for SP_Service account.
  • Give the install user (SP_Admin) & User Profile Service user (SP_Farm) full control for User Profile Synchronization Service Application in Central Administration.
  • Start the User Profile Synchronization system service in Central Administration
    • If Central Administration is on the same machine as the User Profile Synchronization service, then do IISRESET after provisioning the service.
    • Common User Profile Sync service issues: http://www.harbar.net/articles/sp2010ups2.aspx
  • Search:
    On DC environment:
    Run ConfigureSearchSSAWithDC.ps1

    ####################################################################################
    ## This script configures a Search SSA in an environment with a domain controller ##
    ####################################################################################
     
    Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
     
    ## Settings you may want to change ##
    $databaseServerName = "dbservername"
    $searchServerName = "ZAVMT-SPAPP2"
    $saAppPoolName = "SharePoint Web Services"
    $appPoolUserName = "domain\SP_Service"
      
    ## Service Application Service Names ##
    $searchSAName = "Enterprise Search Service"
    
    $saAppPool = Get-SPServiceApplicationPool -Identity $saAppPoolName -EA 0
    if($saAppPool -eq $null)
    {
      Write-Host "Creating Service Application Pool..."
     
      $appPoolAccount = Get-SPManagedAccount -Identity $appPoolUserName -EA 0
      if($appPoolAccount -eq $null)
      {
          Write-Host "Please supply the password for the Service Account..."
          $appPoolCred = Get-Credential $appPoolUserName
          $appPoolAccount = New-SPManagedAccount -Credential $appPoolCred -EA 0
      }
     
      $appPoolAccount = Get-SPManagedAccount -Identity $appPoolUserName -EA 0
     
      if($appPoolAccount -eq $null)
      {
        Write-Host "Cannot create or find the managed account $appPoolUserName, please ensure the account exists."
        Exit -1
      }
     
      New-SPServiceApplicationPool -Name $saAppPoolName -Account $appPoolAccount -EA 0 > $null	
    }
     
    ##START SEARCH 
    Write-Host "Creating Search Service and Proxy..."
    Write-Host "  Starting Services..."
    Start-SPEnterpriseSearchServiceInstance $searchServerName
    Start-SPEnterpriseSearchQueryAndSiteSettingsServiceInstance $searchServerName
     
    Write-Host "  Creating Search Application..."
    $searchApp = New-SPEnterpriseSearchServiceApplication -Name $searchSAName -ApplicationPool $saAppPoolName -DatabaseServer $databaseServerName -DatabaseName "SharePoint_SearchDB"
    $searchInstance = Get-SPEnterpriseSearchServiceInstance $searchServerName
     
    Write-Host "  Creating Administration Component..."
    $searchApp | Get-SPEnterpriseSearchAdministrationComponent | Set-SPEnterpriseSearchAdministrationComponent -SearchServiceInstance $searchInstance
      
    ##Crawl
    Write-Host "  Creating Crawl Component..."
    $InitialCrawlTopology = $searchApp | Get-SPEnterpriseSearchCrawlTopology -Active
    $CrawlTopology = $searchApp | New-SPEnterpriseSearchCrawlTopology
    $CrawlDatabase = ([array]($searchApp | Get-SPEnterpriseSearchCrawlDatabase))[0]
    $CrawlComponent = New-SPEnterpriseSearchCrawlComponent -CrawlTopology $CrawlTopology -CrawlDatabase $CrawlDatabase -SearchServiceInstance $searchInstance
    $CrawlTopology | Set-SPEnterpriseSearchCrawlTopology -Active
     
    Write-Host -ForegroundColor white "  Waiting for the old crawl topology to become inactive" -NoNewline
    do {write-host -NoNewline .;Start-Sleep 6;} while ($InitialCrawlTopology.State -ne "Inactive")
    $InitialCrawlTopology | Remove-SPEnterpriseSearchCrawlTopology -Confirm:$false
    Write-Host
       
    ##Query
    Write-Host "  Creating Query Component..."
    $InitialQueryTopology = $searchApp | Get-SPEnterpriseSearchQueryTopology -Active
    $QueryTopology = $searchApp | New-SPEnterpriseSearchQueryTopology -Partitions 1 
    $IndexPartition= (Get-SPEnterpriseSearchIndexPartition -QueryTopology $QueryTopology)
    $QueryComponent = New-SPEnterpriseSearchQuerycomponent -QueryTopology $QueryTopology -IndexPartition $IndexPartition -SearchServiceInstance $searchInstance
    $PropertyDatabase = ([array]($searchApp | Get-SPEnterpriseSearchPropertyDatabase))[0] 
    $IndexPartition | Set-SPEnterpriseSearchIndexPartition -PropertyDatabase $PropertyDatabase
    $QueryTopology | Set-SPEnterpriseSearchQueryTopology -Active
      
    Write-Host "  Creating Proxy..."
    $searchAppProxy = New-SPEnterpriseSearchServiceApplicationProxy -Name "$searchSAName Proxy" -SearchApplication $searchSAName > $null
      
    #####END SEARCH
    
    Write-Host "Operation Complete."
    

    On sandbox environment (without DC), there is a problem with the search: see http://soerennielsen.wordpress.com/2010/07/15/how-to-install-a-sharepoint-2010-complete-server-without-ad/

    1. Change configurating in searchconfig.xml
    2. Load the ConfigureSearchSSAWithoutDC.ps1 script (just drag the file into the shell and execute) which will define the required functions
      	
      	# SetupEnterpriseSearch.ps1
      	#
      	# Original script for SharePoint 2010 beta2 by Gary Lapointe ()
      	#
      	# Modified by Søren Laurits Nielsen (soerennielsen.wordpress.com):
      	#
      	# Purpose: In addition to setup an enterprise search across multiple servers, it can now be used to setup a working 
      	# search setup on a single server install in non-domain mode with a complete install role (as opposed to the stand-alone option)
      	#
      	# Modified to fix some errors since some cmdlets have changed a bit since beta 2 and added support for "ShareName" for 
      	# the query component. It is required for non DC computers. 
      	# 
      	# Modified to support "localhost" moniker in config file. 
      	#
      	# Note: Accounts, Shares and directories specified in the config file must be setup before hand.
      	#
      	# Usage: 
      	#     Start-EnterpriseSearch <config file>
      	#
      	# e.g.:
      	#     Start-EnterpriseSearch "<path>\searchconfig.xml"
      	#
      	# Notes on usage: 
      	#   In order to setup a single server non-domain SharePoint dev machine follow the guidance here: ...
      	#
      
      	#In order to be able to single step the script in PowerShell IDE load SharePoint snapin if not present.
      	if( (Get-PSSnapIn Microsoft.SharePoint.Powershell -ErrorAction:SilentlyContinue) -eq $null ){
      		#Load SharePoint snapin, apparently not started throught the SharePoint powershell
      		. "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\CONFIG\POWERSHELL\Registration\sharepoint.ps1"
      	}
      
      	function Start-EnterpriseSearch([string]$settingsFile = "Configurations.xml") {
      		#SLN: Added support for local host
      		[xml]$config = (Get-Content $settingsFile) -replace( "localhost", $env:computername )
      		$svcConfig = $config.Services.EnterpriseSearchService 
      	 
      		$searchSvc = Get-SPEnterpriseSearchServiceInstance -Local
      		if ($searchSvc -eq $null) {
      			throw "Unable to retrieve search service."
      		}
      
      		#SLN: Create the network share (will report an error if exist)
      		#default to primitives 
      		$s = """" + $svcConfig.ShareName + "=" + $svcConfig.IndexLocation + """"
      		Write ("Creating network share " + $s)
      		net share $s "/GRANT:WSS_WPG,CHANGE"
      
      
      		#SLN: Does NOT set the service account, uses the default as Set-SPEnterpriseSearchService 
      		# have a hard time understanding it without an actual secure password (which you don't have by looking up the 
      		# manager service account).
      		
      		#Write-Host "Getting $($svcConfig.Account) account for search service..."
      		#$searchSvcManagedAccount = (Get-SPManagedAccount -Identity $svcConfig.Account -ErrorVariable err -ErrorAction SilentlyContinue)
      		#if ($err) {
      		#    $searchSvcAccount = Get-Credential $svcConfig.Account 
      		#    $searchSvcManagedAccount = New-SPManagedAccount -Credential $searchSvcAccount
      		#}
      
      		Get-SPEnterpriseSearchService | Set-SPEnterpriseSearchService  `
      		  -ContactEmail $svcConfig.ContactEmail -ConnectionTimeout $svcConfig.ConnectionTimeout `
      		  -AcknowledgementTimeout $svcConfig.AcknowledgementTimeout -ProxyType $svcConfig.ProxyType `
      		  -IgnoreSSLWarnings $svcConfig.IgnoreSSLWarnings -InternetIdentity $svcConfig.InternetIdentity -PerformanceLevel $svcConfig.PerformanceLevel
      		
      
      		Write-Host "Setting default index location on search service..."
      
      		$searchSvc | Set-SPEnterpriseSearchServiceInstance -DefaultIndexLocation $svcConfig.IndexLocation -ErrorAction SilentlyContinue -ErrorVariable err
      
      		$svcConfig.EnterpriseSearchServiceApplications.EnterpriseSearchServiceApplication | ForEach-Object {
      			$appConfig = $_
      
      			#Try and get the application pool if it already exists
      			$pool = Get-ApplicationPool $appConfig.ApplicationPool
      			$adminPool = Get-ApplicationPool $appConfig.AdminComponent.ApplicationPool
      
      			$searchApp = Get-SPEnterpriseSearchServiceApplication -Identity $appConfig.Name -ErrorAction SilentlyContinue
      
      			if ($searchApp -eq $null) {
      				Write-Host "Creating enterprise search service application..."
      				$searchApp = New-SPEnterpriseSearchServiceApplication -Name $appConfig.Name `
      					-DatabaseServer $appConfig.DatabaseServer `
      					-DatabaseName $appConfig.DatabaseName `
      					-FailoverDatabaseServer $appConfig.FailoverDatabaseServer `
      					-ApplicationPool $pool `
      					-AdminApplicationPool $adminPool `
      					-Partitioned:([bool]::Parse($appConfig.Partitioned)) `
      					-SearchApplicationType $appConfig.SearchServiceApplicationType
      			} else {
      				Write-Host "Enterprise search service application already exists, skipping creation."
      			}
      
      			$installCrawlSvc = (($appConfig.CrawlServers.Server | where {$_.Name -eq $env:computername}) -ne $null)
      			$installQuerySvc = (($appConfig.QueryServers.Server | where {$_.Name -eq $env:computername}) -ne $null)
      			$installAdminCmpnt = (($appConfig.AdminComponent.Server | where {$_.Name -eq $env:computername}) -ne $null)
      			$installSyncSvc = (($appConfig.SearchQueryAndSiteSettingsServers.Server | where {$_.Name -eq $env:computername}) -ne $null)
      
      			if ($searchSvc.Status -ne "Online" -and ($installCrawlSvc -or $installQuerySvc)) {
      				$searchSvc | Start-SPEnterpriseSearchServiceInstance
      			}
      
      			if ($installAdminCmpnt) {
      				Write-Host "Setting administration component..."
      				Set-SPEnterpriseSearchAdministrationComponent -SearchApplication $searchApp -SearchServiceInstance $searchSvc
      			}
      
      			$crawlTopology = Get-SPEnterpriseSearchCrawlTopology -SearchApplication $searchApp | where {$_.CrawlComponents.Count -gt 0 -or $_.State -eq "Inactive"}
      
      			if ($crawlTopology -eq $null) {
      				Write-Host "Creating new crawl topology..."
      				$crawlTopology = $searchApp | New-SPEnterpriseSearchCrawlTopology
      			} else {
      				Write-Host "A crawl topology with crawl components already exists, skipping crawl topology creation."
      			}
      	 
      			if ($installCrawlSvc) {
      				$crawlComponent = $crawlTopology.CrawlComponents | where {$_.ServerName -eq $env:ComputerName}
      				if ($crawlTopology.CrawlComponents.Count -eq 0 -and $crawlComponent -eq $null) {
      					$crawlStore = $searchApp.CrawlStores | where {$_.Name -eq "$($appConfig.DatabaseName)_CrawlStore"}
      					Write-Host "Creating new crawl component..."
      					$crawlComponent = New-SPEnterpriseSearchCrawlComponent -SearchServiceInstance $searchSvc -SearchApplication $searchApp -CrawlTopology $crawlTopology -CrawlDatabase $crawlStore.Id.ToString() -IndexLocation $appConfig.IndexLocation
      				} else {
      					Write-Host "Crawl component already exist, skipping crawl component creation."
      				}
      			}
      
      			$queryTopology = Get-SPEnterpriseSearchQueryTopology -SearchApplication $searchApp | where {$_.QueryComponents.Count -gt 0 -or $_.State -eq "Inactive"}
      
      			if ($queryTopology -eq $null) {
      				Write-Host "Creating new query topology..."
      				$queryTopology = $searchApp | New-SPEnterpriseSearchQueryTopology -Partitions $appConfig.Partitions
      			} else {
      				Write-Host "A query topology with query components already exists, skipping query topology creation."
      			}
      
      			if ($installQuerySvc) {
      				$queryComponent = $queryTopology.QueryComponents | where {$_.ServerName -eq $env:ComputerName}
      				#if ($true){ #$queryTopology.QueryComponents.Count -eq 0 -and $queryComponent -eq $null) {
      				if ($queryTopology.QueryComponents.Count -eq 0 -and $queryComponent -eq $null) {
      					$partition = ($queryTopology | Get-SPEnterpriseSearchIndexPartition)
      					Write-Host "Creating new query component..."
      					$queryComponent = New-SPEnterpriseSearchQueryComponent -IndexPartition $partition -QueryTopology $queryTopology -SearchServiceInstance $searchSvc -ShareName $svcConfig.ShareName
      					Write-Host "Setting index partition and property store database..."
      					$propertyStore = $searchApp.PropertyStores | where {$_.Name -eq "$($appConfig.DatabaseName)_PropertyStore"}
      					$partition | Set-SPEnterpriseSearchIndexPartition -PropertyDatabase $propertyStore.Id.ToString()
      				} else {
      					Write-Host "Query component already exist, skipping query component creation."
      				}
      			}
      
      			if ($installSyncSvc) {            
      				#SLN: Updated to new syntax
      				Start-SPServiceInstance (Get-SPServiceInstance | where { $_.TypeName -eq "Search Query and Site Settings Service"}).Id
      			}
      
      			#Don't activate until we've added all components
      			$allCrawlServersDone = $true
      			$appConfig.CrawlServers.Server | ForEach-Object {
      				$server = $_.Name
      				$top = $crawlTopology.CrawlComponents | where {$_.ServerName -eq $server}
      				if ($top -eq $null) { $allCrawlServersDone = $false }
      			}
      
      			if ($allCrawlServersDone -and $crawlTopology.State -ne "Active") {
      				Write-Host "Setting new crawl topology to active..."
      				$crawlTopology | Set-SPEnterpriseSearchCrawlTopology -Active -Confirm:$false
      
      				Write-Host -ForegroundColor Red "Waiting on Crawl Components to provision..."
      
      				while ($true) {
      					$ct = Get-SPEnterpriseSearchCrawlTopology -Identity $crawlTopology -SearchApplication $searchApp
      					$state = $ct.CrawlComponents | where {$_.State -ne "Ready"}
      					if ($ct.State -eq "Active" -and $state -eq $null) {
      						break
      					}
      
      					Write-Host -ForegroundColor Red "Waiting on Crawl Components to provision..."
      					Start-Sleep 5
      				}
      
      				# Need to delete the original crawl topology that was created by default
      				$searchApp | Get-SPEnterpriseSearchCrawlTopology | where {$_.State -eq "Inactive"} | Remove-SPEnterpriseSearchCrawlTopology -Confirm:$false
      			}
      
      			$allQueryServersDone = $true
      			$appConfig.QueryServers.Server | ForEach-Object {
      				$server = $_.Name
      				$top = $queryTopology.QueryComponents | where {$_.ServerName -eq $server}
      				if ($top -eq $null) { $allQueryServersDone = $false }
      			}
      
      			#Make sure we have a crawl component added and started before trying to enable the query component
      			if ($allCrawlServersDone -and $allQueryServersDone -and $queryTopology.State -ne "Active") {
      				Write-Host "Setting query topology as active..."
      				$queryTopology | Set-SPEnterpriseSearchQueryTopology -Active -Confirm:$false -ErrorAction SilentlyContinue -ErrorVariable err
      
      				Write-Host -ForegroundColor Red "Waiting on Query Components to provision..."
      				while ($true) {
      					$qt = Get-SPEnterpriseSearchQueryTopology -Identity $queryTopology -SearchApplication $searchApp
      					$state = $qt.QueryComponents | where {$_.State -ne "Ready"}
      					if ($qt.State -eq "Active" -and $state -eq $null) {
      						break
      					}
      
      					Write-Host -ForegroundColor Red "Waiting on Query Components to provision..."
      					Start-Sleep 5
      				}
      
      				# Need to delete the original query topology that was created by default
      				$searchApp | Get-SPEnterpriseSearchQueryTopology | where {$_.State -eq "Inactive"} | Remove-SPEnterpriseSearchQueryTopology -Confirm:$false
      			}
      
      			$proxy = Get-SPEnterpriseSearchServiceApplicationProxy -Identity $appConfig.Proxy.Name -ErrorAction SilentlyContinue
      			if ($proxy -eq $null) {
      				Write-Host "Creating enterprise search service application proxy..."
      				$proxy = New-SPEnterpriseSearchServiceApplicationProxy -Name $appConfig.Proxy.Name -SearchApplication $searchApp -Partitioned:([bool]::Parse($appConfig.Proxy.Partitioned))
      			} else {
      				Write-Host "Enterprise search service application proxy already exists, skipping creation."
      			}
      
      			if ($proxy.Status -ne "Online") {
      				$proxy.Status = "Online"
      				$proxy.Update()
      			}
      
      			$proxy | Set-ProxyGroupsMembership $appConfig.Proxy.ProxyGroup
      		}
      	}	 
      	 
      	function Set-ProxyGroupsMembership([System.Xml.XmlElement[]]$groups, [Microsoft.SharePoint.Administration.SPServiceApplicationProxy[]]$InputObject)
      	{
      		begin {}
      		process {
      			$proxy = $_
      			
      			#Clear any existing proxy group assignments
      			Get-SPServiceApplicationProxyGroup | where {$_.Proxies -contains $proxy} | ForEach-Object {
      				$proxyGroupName = $_.Name
      				if ([string]::IsNullOrEmpty($proxyGroupName)) { $proxyGroupName = "Default" }
      				$group = $null
      				[bool]$matchFound = $false
      				foreach ($g in $groups) {
      					$group = $g.Name
      					if ($group -eq $proxyGroupName) { 
      						$matchFound = $true
      						break 
      					}
      				}
      				if (!$matchFound) {
      					Write-Host "Removing ""$($proxy.DisplayName)"" from ""$proxyGroupName"""
      					$_ | Remove-SPServiceApplicationProxyGroupMember -Member $proxy -Confirm:$false -ErrorAction SilentlyContinue
      				}
      			}
      			
      			foreach ($g in $groups) {
      				$group = $g.Name
      
      				$pg = $null
      				if ($group -eq "Default" -or [string]::IsNullOrEmpty($group)) {
      					$pg = [Microsoft.SharePoint.Administration.SPServiceApplicationProxyGroup]::Default
      				} else {
      					$pg = Get-SPServiceApplicationProxyGroup $group -ErrorAction SilentlyContinue -ErrorVariable err
      					if ($pg -eq $null) {
      						$pg = New-SPServiceApplicationProxyGroup -Name $name
      					}
      				}
      				
      				$pg = $pg | where {$_.Proxies -notcontains $proxy}
      				if ($pg -ne $null) { 
      					Write-Host "Adding ""$($proxy.DisplayName)"" to ""$($pg.DisplayName)"""
      					$pg | Add-SPServiceApplicationProxyGroupMember -Member $proxy 
      				}
      			}
      		}
      		end {}
      	}
      
      	function Get-ApplicationPool([System.Xml.XmlElement]$appPoolConfig) {
      		#Try and get the application pool if it already exists
      		#SLN: Updated names
      		$pool = Get-SPServiceApplicationPool -Identity $appPoolConfig.Name -ErrorVariable err -ErrorAction SilentlyContinue
      		if ($err) {
      			#The application pool does not exist so create.
      			Write-Host "Getting $($appPoolConfig.Account) account for application pool..."
      			$managedAccount = (Get-SPManagedAccount -Identity $appPoolConfig.Account -ErrorVariable err -ErrorAction SilentlyContinue)
      			if ($err) {
      				$accountCred = Get-Credential $appPoolConfig.Account
      				$managedAccount = New-SPManagedAccount -Credential $accountCred
      			}
      			Write-Host "Creating application pool $($appPoolConfig.Name)..."
      			$pool = New-SPServiceApplicationPool -Name $appPoolConfig.Name -Account $managedAccount
      		}
      		return $pool
      	}
      	
    3. Execute “Start-EnterpriseSearch “<path>\searchconfig.xml””
    4. Wait for a few minutes and watch for errors
    5. After the script is run, c:\Program Files\Microsoft Office Servers\14.0\Data\Office Server\Application should be shared as specified in “ShareName”.
      Also, the search account needs read/write access to the share.
      If this did not happen, there will be errors in the event and search won’t crawl

Post-installation:

  • Create web applications:

    	$appPoolName = "SharePoint Content Application Pool"
    	$appPoolUserName = "domain\SP_Service"
    	$farmAccount = "domain\SP_Admin"
    
    	Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
    
    	## Get application pool
    	$appPool = Get-SPServiceApplicationPool -Identity $appPoolName -EA 0
    	if($appPool -eq $null)
    	{
    	  Write-Host "Creating Service Application Pool..."
    	 
    	  $appPoolAccount = Get-SPManagedAccount -Identity $appPoolUserName -EA 0
    	  if($appPoolAccount -eq $null)
    	  {
    		  Write-Host "Please supply the password for the Service Account..."
    		  $appPoolCred = Get-Credential $appPoolUserName
    		  $appPoolAccount = New-SPManagedAccount -Credential $appPoolCred -EA 0
    	  }
    	 
    	  $appPoolAccount = Get-SPManagedAccount -Identity $appPoolUserName -EA 0
    	 
    	  if($appPoolAccount -eq $null)
    	  {
    		Write-Host "Cannot create or find the managed account $appPoolUserName, please ensure the account exists."
    		Exit -1
    	  }
    	 
    	  New-SPServiceApplicationPool -Name $appPoolName -Account $appPoolAccount -EA 0 > $null	
    	}
    
    
    	## Create web applications
    	# My Site
    	New-SPWebApplication -Name "My Sites" -Port 80 -HostHeader "mysite.contoso.co.za" -ApplicationPool $appPoolName -AuthenticationMethod "NTLM" -DatabaseName "SharePoint_Content_MySite_tmp" -Url "http://mysite.contoso.co.za" -Confirm:$false #-SecureSocketsLayer:$true
    	New-SPSite -Name "My Site" -Url "http://mysite.contoso.co.za:80" -OwnerAlias $farmAccount -Template "SPSMSITEHOST#0" -ContentDatabase "SharePoint_Content_MySite_tmp" -Confirm:$false
    	New-SPManagedPath -RelativeURL "personal" -WebApplication "http://mysite.contoso.co.za:80"
    
    	New-SPWebApplication -Name "Intranet" -Port 80 -HostHeader "intranet.contoso.co.za" -ApplicationPool $appPoolName -AuthenticationMethod "NTLM" -DatabaseName "SharePoint_Content_Intranet" -Url "http://intranet.contoso.co.za/" -Confirm:$false
    	
  • Upgrade
    See my other blog: https://jasondicker.wordpress.com/2010/10/13/my-sharepoint-2010-upgrade-experiences/

    	$webUrl = "http://intranet.contoso.co.za"
    	$databaseServer = "dbservername"
    	$databaseName = "SharePoint_Content_Intranet"
    	$oldDatabaseName = "SharePoint_Content_Intranet_tmp"
    
    	Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
    
    	function deleteSPFeature([Microsoft.SharePoint.SPSite]$site=$(throw 'Parameter -site is missing!'),[string]$id=$(throw 'Parameter -id is missing'))
    	{
    		$f = $site.Features | where {$_.DefinitionId -like $id}
    		if ($f -ne $null) {
    			"Removing feature '$id'..."
    			$s.Features.Remove($f.DefinitionId, $true)
    		}
    	}
    
    	function deleteSPFile([Microsoft.SharePoint.SPWeb]$web=$(throw 'Parameter -web is missing!'),[string]$filename=$(throw 'Parameter -filename is missing'))
    	{
    		$f = Get-SPWeb $web.Url | select -Expand Lists | select -Expand Items | where {$_.Name -eq $filename}
    		if ($f -ne $null)
    		{
    			"Deleting $filename..."    
    			$f.Delete()        
    		}
    		
    		$f = Get-SPWeb $web.Url | select -Expand RecycleBin | where {$_.Name -eq $filename}
    		if ($f -ne $null)
    		{
    			"Deleting $filename from recycle bin..."    
    			$f.Delete()        
    		}    
    	}
    
    	$webapp = get-spwebapplication $webUrl
    
    	Test-SPContentDatabase -Name $databasename -WebApplication $webUrl
    	Dismount-SPContentDatabase -Identity $oldDatabaseName -Confirm:$false 
    	Mount-SPContentDatabase -name $databasename -WebApplication $webUrl -Updateuserexperience
    
    	foreach ($s in $webapp.Sites)
    	{
    		Set-SPSiteAdministration $s.Url -OwnerAlias "contoso\spadmin"
    
    		# Visual upgrade
    		$site = Get-SPSite $s.Url
    		$site.VisualUpgradeWebs()
    	}
    
    	# remove missing features & webparts
    	foreach ($s in $webapp.Sites)
    	{
    		deleteSPFeature $s "fc5e2840-0b48-42eb-9ad7-076f5add58ad" #Hide the View All Site Content link
    		deleteSPFeature $s "60ed2117-acbf-4d8b-a2d2-f2cdabeee7ca" #SPOShowBirthdayWebPart
    		deleteSPFeature $s "daf910f9-f378-4059-92e8-0f1d571d3c6a" #Infowise Birthday List
    			
    		deleteSPFile $s.RootWeb "Microsoft.Office.Excel.WebUI.dwp"  
    		deleteSPFile $s.RootWeb "UsersBirthday.webpart"
    		deleteSPFile $s.RootWeb "SPOShowBirthdayWebPart.webpart"
    		deleteSPFile $s.RootWeb "VASC-core.css"
    	}
    
    	"Operation complete."
    	
  • Configure Super user account
    	
    	#Create accounts and add to user policy for web application. See, http://technet.microsoft.com/en-us/library/ff758656.aspx 
    	Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
    
    	$superUserAccount = "domain\SP_SuperUser"
    	$superReaderAccount = "domain\SP_SuperReader"
    
    	$wa = Get-SPWebApplication -Identity "http://intranet.contoso.co.za"
    	$userOrGroup = $superUserAccount 
    	$policy = $wa.Policies.Add($userOrGroup, $userOrGroup) 
    	$policy.PolicyRoleBindings.Add($wa.PolicyRoles.GetSpecialRole([Microsoft.SharePoint.Administration.SPPolicyRoleType]::FullControl)) 
    	$userOrGroup = $superReaderAccount 
    	$policy = $wa.Policies.Add($userOrGroup, $userOrGroup) 
    	$policy.PolicyRoleBindings.Add($wa.PolicyRoles.GetSpecialRole([Microsoft.SharePoint.Administration.SPPolicyRoleType]::FullRead)) 
    	$wa.Properties["portalsuperuseraccount"] = $superUserAccount
    	$wa.Properties["portalsuperreaderaccount"] = $superReaderAccount
    	$wa.Update()
    
    	IISRESET
    	

Other tasks:

  • Check the event logs, ULS logs & Health Analyser for issues.
  • Start/stop applicable services on each server:
  • SharePoint Foundation Help Search (On search server, set service/crawl account…)
  • Usage & Health -> enable health data collection
  • Either delete or move controltemplates\taxonomypicker.ascx to _deleted folder. This is to remove related errors in the event logs.
  • Search:
    • Set crawl account to “SP_SearchCrawl”
    • Setup search crawl schedules
  • User Profile Synchronization:
    • Configure Synchronization Connections
    • Configure MySites url in User Profile Synchronization Service
    • Setup crawl schedule for User Profile Synchronization
  • Configure alternate access urls
  • Configure super user accounts:
  • Configure outbound email settings
  • Remove User Profile Service user from Administrators group

Common post-installation errors: http://globaljosh.wordpress.com/

This process is by no mean 100% complete and I’m refining it every time I perform an installation. Please give me your thoughts. I hope it helps some of you out there.
Jason

Advertisements

My SharePoint 2010 upgrade experiences

October 13, 2010 11 comments
This is an attempt to document my SharePoint 2010 upgrade experiences. At the time of writing, there weren’t many case studies with regards to upgrading a highly customized intranet. I have posted my findings in the hope that it will help someone else and get feedback.
 
The existing environment:
  • 1 SharePoint 2007 farm with 2 WFE servers, 1 App server, 1 database cluster
  • Highly customized with custom developed features/site definitions/list event handlers etc..
  • 3 web applications with 96 site collections and 35 content databases in total
  • MySites/Share Services Provider etc..
 

Approach:
As I couldn’t afford to compromise the current environment’s availability, the gradual database attach approach was used.

 

Steps:

  • Installed & configured SharePoint 2010 farm on new environment
  • Ran stsadm.exe -o preupgradecheck & fixed issues
  • Backed-up existing Content/MySite & SSP databases
  • Restored Content/MySite & SSP databases on new environment
  • Installed custom features on new environment
  • Ran Test-SPContentDatabase powershell command on each content database & fixed issues
  • Ran Mount-SPContentDatabase powershell command to perform the upgrade on each content database
  • Checked upgrade logs for issues
  • Reviewed SharePoint upgrade status: Central Administration > Upgrade Status
  • Verify upgrade and review upgraded sites – http://technet.microsoft.com/en-us/library/cc424972.aspx
  • Checked Health Analyzer for Missing Server Dependency issues
  • Manually go through the sites and confirm everything is working properly i.e workflow, custom features etc..
 

PRE-UPGRADE STEPS:

Running stsadm.exe -p preupgradecheck produces a report of potential upgrade issues. Not all of these issues needs to be resolved for the upgrade to succeed, but you’d want to clean up your existing environment of missing dependencies etc.. This will save you a lot of headaches in the future. The web has a lot of information regarding the preupgradecheck tool, but I couldn’t find a lot of information about how to actually address these issues. Here are some of the methods I used:

Issue: Missing server file or server configuration issues

These issues are due to missing dependencies referenced by your farm. These dependencies could be missing features or webparts and can be removed by one of the following methods:
 
Directly from the SharePoint database (not recommended):
Remove dependency on custom site definitions: I had a couple of custom site definitions (10000-10006) and replaced it with a blank site (47):

UPDATE [Webs] SET webtemplate = 47 WHERE webtemplate >= 10000 and webtemplate <= 10006

Delete unknown feature references from Features table:

DELETE FROM [Features] where FeatureId = 'ec5bd384-ea53-442f-9c78-5421dc4b7148'

Delete unknown setupfiles (webparts) from AllDocs table:

DELETE FROM [AllDocs] where SetupPath = 'Features\Custom.RSSViewer\RSSViewer.webpart'

Delete unknown webparts from Webparts table:

DELETE FROM [WebParts] where tp_WebPartTypeId = '9f7c2f41-e4d5-bd75-8db3-78bce3ef96a6' 

Delete missing assemblies:

DELETE FROM [EventReceivers] where [Assembly] = 'SPUserPoll.Business.Components, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b504d4b6c1e1a6e5'
 
Uninstall missing features via command line:
stsadm.exe -o deactivatefeature / stsadm.exe -o uninstallfeature 

 

Remove invalid webpart references:
You can manually delete the invalid webparts files from web part gallery or recycle bin. The webparts may be referenced by pages, so the following command can help you track down which pages are referencing the webparts: stsadm.exe -o enumallwebs -includewebparts > N:\enumwebs.txt. Find the page and open in the browser, add ?contents=1 to the url and manually delete the webpart if you see an error webpart on the page. If you can’t find the erroneous webpart, use the following SQL to determine where the webpart is referenced. I had a problem with an invalid webpart reference on a deleted page in the site collection’s recycle bin. I used the following SQL to determine which page was referencing the webpart:

SELECT * FROM [WebParts] where tp_WebPartTypeId = '25603dac-dee4-e4b0-5518-e9ac034dba57' -- search for the invalid webpart id & use the tp_SiteID & tp_PageUrlId values below
SELECT * FROM [Sites] where Id = '58B834C9-5682-4FA5-92EB-4D1F6CEB4CDC' -- tp_SiteID
SELECT * FROM [AllDocs] where Id = '0C22E0E5-CF32-4096-9869-26657162A23F' -- tp_PageUrlId

I then browsed to the site and could not find the page. I figured the page was deleted, so I found it in the site collection’s recycle bin. After deleting the page from the recycle bin my problem was resolved!

 

Remove invalid event receiver:
There’s no API/Interface to remove this, so unfortunately the only way I know of is to delete it directly from the database (this method is not recommended as it’s not support by Mircrosoft)

DELETE FROM [EventReceivers] WHERE [Assembly] like 'Intranet.Surveys.ResponseEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=75f0cae6eba692a7'
 

Powershell (recommended):
I wrote the following powershell script to do the following: set my user as the site collection admin on all sites, remove unknown features, remove invalid webparts:

$12HiveDir = "${env:CommonProgramFiles}\Microsoft Shared\web server extensions\12\"
cd $12HiveDir
[void][reflection.assembly]::Loadwithpartialname("Microsoft.SharePoint") out-null
[void][reflection.assembly]::Loadwithpartialname("Microsoft.Office.Server.Search") out-null
[void][reflection.assembly]::Loadwithpartialname("Microsoft.Office.Server") out-null

# Returns the SPWebApplication at the specified URL
function get-spwebapplication ([String]$webUrl=$(throw 'Parameter -webUrl is missing!'))
{
 return [Microsoft.SharePoint.Administration.SPWebApplication]::Lookup($webUrl)
}

# Returns the SPSite at the specified URL
function get-spsite ([String]$webUrl=$(throw 'Parameter -webUrl is missing!'))
{
 return New-Object -TypeName "Microsoft.SharePoint.SPSite" -ArgumentList "$webUrl"
}

# Returns the SPSite object from the specified URL
function get-spweb ([String]$webUrl=$(throw 'Parameter -webUrl is missing!'))
{
 $site = New-Object -TypeName "Microsoft.SharePoint.SPSite" -ArgumentList "$webUrl"
 return $site.OpenWeb()
}

# Returns the SPList object from the specified URL and list name
function get-splist ([String]$webUrl=$(throw 'Parameter -webUrl is missing!'), [String]$listName=$(throw 'Parameter -listName is missing!'))
{
 $site = New-Object -TypeName "Microsoft.SharePoint.SPSite" -ArgumentList "$webUrl"
 $web = $site.OpenWeb()

 return $web.Lists[$listName]
}

function delete-spfeature([Microsoft.SharePoint.SPSite]$site=$(throw 'Parameter -site is missing!'), [string]$id=$(throw 'Parameter -id is missing!'))
{
 $f = $site.Features where {$_.DefinitionId -like $id}
 if ($f -ne $null) {
 "Removing unknown feature '$id'..."
 $s.Features.Remove($f.DefinitionId, $true)
 }
}

function delete-spfile([Microsoft.SharePoint.SPSite]$site=$(throw 'Parameter -site is missing!'), [string]$filename=$(throw 'Parameter -filename is missing!'))
{
 $f = Get-SPWeb $site.Url Select -Expand Lists Select -Expand Items Where {$_.Title -eq $filename}

 if ($f -ne $null) {
 "Deleting $filename..."
 $f.Delete()
 }

 $f = Get-SPWeb $s.Url Select -Expand RecycleBin where {$_.Title -eq $filename}
 if ($f -ne $null) {
 "Deleting $filename from recycle bin..."
 $f.Delete()
 }
}

$webapp = get-spwebapplication http://localhost:11000
foreach ($s in $webapp.Sites)
{
 "$s"

 "Setting site collection administrator..."
 STSADM.EXE -o siteowner -url $s.Url.ToString() -secondarylogin ho\jadicker

 # Delete files
 delete-spfile $s "RssViewer.webpart"

 # Rename "Resource" content type of Applications Template Types feature
 $f = Get-SPWeb $s.Url Select -Expand ContentTypes where {$_.Name -eq "Resource"}

 if ($f -ne $null) {
 "Renaming 'Resource' Content Type..."
 $f.Name = "Resource2"
 $f.Update()
}

# Remove features
delete-spfeature $s "a3765e3b-5718-47dc-9ef3-af6effece076" #unknown
delete-spfeature $s "ec5bd384-ea53-442f-9c78-5421dc4b7148" #unknown
delete-spfeature $s "977df490-79ab-4b60-a744-b7cb1aa05db3" #Corporate.SiteHandler.Begin
delete-spfeature $s "c83c232d-86d7-494b-af23-1d9c0ab15cd9" #Crporate.SiteHandler.End
delete-spfeature $s "b020eb72-ab95-4c53-8ed4-fd72ad89cdad" #Branding

"`n"
}

$webapp = get-spwebapplication http://localhost:10600
foreach ($s in $webapp.Sites)
{
 "$s"

 "Setting site collection administrator..."
 STSADM.EXE -o siteowner -url $s.Url.ToString() -secondarylogin ho\jadicker

 # Delete files
 delete-spfile $s "RssViewer.webpart"

 # Remove features
 delete-spfeature $s "b020eb72-ab95-4c53-8ed4-fd72ad89cdad" #Branding

 "`n"
}

"Operation Complete"

Once your existing environment is cleaned-up, you can proceed with the actual upgrade.

 

UPGRADE STEPS:

 
  • Restore the Content/MySite & SSP databases on new environment
  • Install custom features on new environment. Some of these feature may not work correctly in SharePoint 2010, so you’ll have to exercise caution here… Some features were too problematic for me, so I decided to deactivate them from my sites, upgrade, re-design the features, then activate them again.
  • Test each databases in with powershell command (always open a new instance of powershell): e.g. Test-SPContentDatabase -name Intranet_WSS_Content_Corporate_11000 -webapplication http://spwfe:11000 > c:\test-contentdabase-11000.txt
  • Check for above issues
  • Upgrade each databases with powershell command (always open a new instance of powershell): e.g Mount-SPContentDatabase -Name Intranet_WSS_Content_Corporate_11000 -WebApplication http://spwfe:11000 -UpdateUserExperience
  • I found that using the -UpdateUserExperience parameter works better for performing an visual upgrade as opposed to doing it after the upgrade. In my case, the new V4.Master master pages were not uploaded into the masterpage galleries when using the latter approach.
  • I then wrote a Powershell script to upgrade my SSP database:
$appPool = "SharePoint User Profile Service Application"
$appPoolAccount = "ho\moss_dev_svc_usr"
$serviceApplicationName = "User Profile Service Application"
$serviceApplicationProxyName = "User Profile Service Application Proxy"
$profileDBName = "SharePoint_UserProfile"

"Creating application pool..."
New-SPServiceApplicationPool -Name $appPool -Account $appPoolAccount
"Creating User Profile service and upgrading SSP database..."
$id = New-SPProfileServiceApplication -applicationpool $appPool -Name $serviceApplicationName -Profiledbname $profileDBName #[-Profiledbserver ]

"Creating User Profile service proxy..."
New-SPProfileServiceApplicationProxy -ServiceApplication $id.Id -Name $serviceApplicationProxyName -DefaultProxyGroup

After that I had to verify the upgrade by reviewing the log files, health analyzer, central administration etc. and once everything seemed fine, I discovered more issues by manually going through all the sites and fixing issues as I found them. I will cover some of these issues in later posts.

 

And that in a nutshell is some of the pain I had to go through to upgrade our intranet. I hope this helps you folks out there!

Categories: SharePoint, Upgade Tags: ,

Common SharePoint Document Conversion issues

October 13, 2010 4 comments

This post describes solutions for the common errors you may encounter while
working with the Document Conversion service in SharePoint 2007. Although the
post was intended for SharePoint 2007, it also applies to SharePoint 2010.

Firstly, ensure the configuration is correct:

  • Go to SharePoint Central Administration -> Application Management ->
    Document conversions (under the External Service Connections section) and verify if document conversions is enabled for the Web Application and if there is a Load Balancer Server defined.
  • Check in Administrative Tool -> Services if the Office Document
    Conversion Launcher Service is running and is running under the Local System
    account.
  • Check in Administrative Tool -> Services if the Office Document
    Conversions Load Balancer Service is running and is running under the Network
    Service account.
  • Check if Microsoft Office SharePoint Server 2007 is not installed on a
    domain controller: document conversion is not supported in such a configuration
    (you could have this problem if you are trying out some stuff on a local VPC for
    example).
  • Check if the Microsoft Word document is saved in the 2007 version (extension
    .docx). The document conversion won’t work for Microsoft Word documents saved in
    a previous version.
  • Check if the publishing features are enabled for the SharePoint site on
    which you try to use the document conversion functionality.
  • Verify the configuration of the content type of your Microsoft Word
    document: it should be configured properly for document conversion. (Manage
    document conversion for this content type).

NB: The Document Conversion services need to be started in the correct order:
In Central Administration > Operations > Services on Server
Select the application server
Stop Document Conversions Launcher Service
Stop Document Conversions Load Balancer Service
Start Document Conversions Load Balancer Service
Start Document Conversions Launcher Service

To ensure the Document Conversion services are always stared in the correct order, perform the following steps on the machine running the document conversion services:

In the registry, HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesDCLauncher, create a
DependOnService multi-string value key with a value of DCLoadBalancer

NB: Service accounts must remain on it’s default setting. The load balancer service needs to run as network service and the launcher service needs to run as Local System (not LocalService) on every machine that you want to run conversions on.

 

Problem:
You may receive the following error if the Document Conversions Launcher Service was
started before the Document Conversions Load Balancer Service:

The attempt to create a page from that document failed
with the following error: Converting the document to a page failed. The
converter framework returned the following error: CE_BACKENDUNAVAILABLE

Resolution:
The Document Conversion services need to be started in the correct order. See above.

 

Problem:
You may receive a CE_DISKWRITEERROR error if the services are not running under default security account.

Resolution:
See above. If the problem persists do the following:

  • Ensure that the HVU_machinename user is not disabled
  • Grant the HVU_machinename user the ‘Allow log on locally’ policy in
    gredit.msc
  • Grant the HVU_machinename user write access on the folder specified in the
    event log: c:Program FilesMicrosoft Office Servers12.0BinHtmlTrLauncher

 

Problem:
You may receive a general CE_OTHER error if the Document Conversion configuration is incorrect.

Resolution:
Ensure the above configuration settings. Also check the ULS logs & Event logs.

 

Problem:
Only Site Collection administrators can successfully convert documents, some users receive an error page or the conversion page “hangs” when they don’t have the necessary
permisions.

Resolution:

  • This usually happens when the user does not have read access to the Site
    Collection’s Master Page Gallery. Go to Site Settings > Master pages and page
    layouts > Settings > Permissions for this document library and make the
    list inherit permissions from it’s parent web site.
  • Users may receive the following error when not part of the Site Collection’s
    Designers group:

An error was encountered performing this operation. You may re-try the operation, and you may need to clean up the half-created data first before re-trying. If the problem persists, please contact your system administrator.

 

Additional info from http://dotnet.org.za/doublej/archive/2008/12/03/sharepoint-2007-getting-the-document-conversion-services-started.aspx:

Event ID: 6102, LoadBalancer.RegisterLauncher failed:  Unable to connect to the remote server
Event ID: 6066, Couldn’t Register with Load Balancer:  Unable to
connect to the remote server
Event ID: 6072, Failed to create the protected
output directory
Event ID: 6062, Found 2 valid ip addresses for this
machine.  Choosing this one:  x.x.x.x

Solving Event 6072
This error happens when the account running the launcher service can’t create a cache
folder in C:Program FilesMicrosoft Office Servers12.0Bin. The folder that
it’s trying to create is called HtmlTrLauncher.
Each time the service is
started, this folder gets delete and re-created, to the service account needs to
be able to create folders in the bin folder.
To do this, first check what
account is running the launcher service. In Central Administration, go to
operationsàService Accounts and select “document conversions launcher service”
in the windows service drop down box. (alternatively, you can look in at the
Office Document Conversions Launcher Service in the windows service
console)
Check what account it is using to start the service. (in my case it
was network service)
Go to the folder C:Program FilesMicrosoft Office
Servers12.0Bin and right click and select “sharing and security”. Click the
security tab and click add.
Add the user “Network Service” (or what every
user you are using to start the service) and grant it “Modify”
permissions.

Solving Event 6062
Open the Launcher and Load Balancer .config files in the office server bin folder (usually C:Program FilesMicrosoft Office Servers12.0Bin)
In the launcher file (Microsoft.Office.Server.Conversions.Launcher.exe.config) comment in the key “keyIPExclude” and set the value to the ip address(s) that you want to exclude.
For example, <add key=”keyIPExclude” value=”192.168.115.14″/>
In the load balancer file (Microsoft.Office.Server.Conversions.LoadBalancer.exe.config) add the ip exclude key to the <LoadBalancerSettings> section. For example,
<add key=”keyIPExclude” value=”192.168.115.14″ />
If you have multiple IP’s that you want to exclude use the following syntax for the key value <add key=”keyIPExclude” value=” (192.168.115.14)|( 192.168.115.15)”/>

Solving Event 6102 and 6066
This error is seems to occur when the load balancer and the launcher servers are started on the same server.
They are occurring because the launcher is starting before the load balancer. To
solve this, we simply need to add a service dependency in windows.
1.  Run regedit
2.  Navigate to HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices and locate the service (usually called DCLauncher)
3. Open the ‘DependOnService’ key on the
right side. If the service does not have a ‘DependOnService’ key, then create
one by right-clicking and selecting New > Multi-String Value.
4. In the value field, enter the string DCLoadBalancer (the name of the load balancer
service)
5. Click OK, close your registry and restart your machine.