September 1, 2014

SharePoint 2010 to SharePoint 2013 PowerShell Migration

On May 19, 2014 I was blessed with the opportunity of assisting Corporate One Federal Credit Union as contractor. My first assignment with the company I would go on to become full-time with in December of 2014 was migrating and mapping users from SharePoint 2007 to SharePoint 2013.

With this project my main focus was successfully migrating the users to the new version of SharePoint AND mapping the users to the new domain as part of a company merge. When building out a new SharePoint environment I like to script the full SharePoint build using PowerShell. The main purpose of not using the wizard, is that the PowerShell route allows for more customization. One big piece is that we can name the databases to our liking and not worry about the default database naming convention the wizards creates that looks like DBNAME_9013975098075098353. To accomplish the task of scripting everything from installing the farm to adding the service application I build out a folder structure of scripts. You can view the complete script at the botton of this page.

Although scripting the PowerShell commands does take a little time in building out for a particular environment, the mapping of users in this project was my biggest challenge. To accomplish this I built a script that essentially used the Move-SPUser cmdlet to map the users from DomainA to DomainB. Using a csv file I was able to map users quickly which worked very well.

Here is the code I used to magically map the users :)

$inputFile = Import-Csv (Read-Host "Enter location of mapping accounts CSV file: ")

[string]$url = (Read-Host "Enter the URL of the Web Application: ")

foreach($line in $inputFile)

{ $user = Get-SPUser -web $url -Identity $line.OriginalAccount

if($user -eq $null)

{ Write-Host "User not found"}

else

{ Move-SPUser -Identity $user -NewAlias $line.NewAccount -IgnoreSID}

}

Complete migration script used to create service accounts, apps, app pools, and sites.

Start-Transcript -Path c:\SharePoint2013_Installation.txt

$databaseServerName = "EAGLES1"

$searchServerName = "RAMS1"

# Create New Configuration and Admin Databases

New-SPConfigurationDatabase -DatabaseName SP2013_Config -DatabaseServer $databaseServerName -AdministrationContentDatabaseName SP2013_Admin_Content

Write-Host "Configuration Database Created"

# Run PSCONFIG

Write-Host "Installing Services and Features..."

Initialize-SPResourceSecurity

Install-SPService

Install-SPFeature -AllExistingFeatures

Install-SPHelpCollection -All

Install-SPApplicationContent

# Create Central Administration

Write-Host "Creating Central Administration..."

New-SPCentralAdministration -Port 2013 -WindowsAuthProvider Kerberos

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

# Fix DCOM error in event log

Write-Host "Fixed DCOM Error in Event Log"

$permission = "NT AUTHORITY\NETWORK SERVICE","READ","ALLOW"

$path = "C:\Program Files\Microsoft Office Servers\15.0"

$acl = Get-Acl -Path $path

$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission

$acl.AddAccessRule($accessRule)

$acct = New-Object System.Security.Principal.NTAccount('CORPONE\sp_install')

$acl.SetOwner($acct)

Set-Acl $path $acl

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

# Managed Accout Password

Write-Host "Creating Managed Accounts..."

$accountpassword = 'masked'

$accountname = 'CORPONE\sp_serviceapps'

$password = ConvertTo-SecureString  $accountpassword -AsPlainText -Force

$account = New-Object system.management.automation.pscredential $accountname, $password

New-SPManagedAccount -Credential $account

$accountpassword = 'masked'

$accountname = 'CORPONE\sp_webapps'

$account = New-Object system.management.automation.pscredential $accountname, $password

New-SPManagedAccount -Credential $account

$accountpassword = 'masked'

$accountname = 'CORPONE\sp_userprofile'

$account = New-Object system.management.automation.pscredential $accountname, $password

New-SPManagedAccount -Credential $account

$accountpassword = 'masked'

$accountname = 'CORPONE\sp_content'

$account = New-Object system.management.automation.pscredential $accountname, $password

New-SPManagedAccount -Credential $account

$accountpassword = 'masked'

$accountname = 'CORPONE\sp_superuser'

$account = New-Object system.management.automation.pscredential $accountname, $password

New-SPManagedAccount -Credential $account

$accountpassword = 'masked'

$accountname = 'CORPONE\sp_superreader'

$account = New-Object system.management.automation.pscredential $accountname, $password

New-SPManagedAccount -Credential $account

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

#Create OnePortal Web Application

Write-Host "Creating OnePortal Web Application..."

New-SPWebApplication -Name "SharePoint-TestOnePortal" -Port 80 -HostHeader oneportal -URL "http://testoneportal" -DatabaseName SP2013_DELETE -DatabaseServer $databaseServerName -ApplicationPool "SharePoint Web App Pool" -ApplicationPoolAccount (Get-SPManagedAccount "CORPONE\sp_webapps") -AuthenticationMethod Kerberos

#Create OnePortal Team Site

Write-Host "Creating OnePortal Team Site..."

New-SPSite -Name "One Portal" -URL "http://testoneportal" -OwnerAlias "CORPONE\sp_install" -Template STS#0

#Create MySite Web Application

Write-Host "Creating MySite Web Application..."

New-SPWebApplication -Name "SharePoint-MySite" -Port 100 -HostHeader mysite -URL "http://mysite:100" -DatabaseName SP2013_Content_MySite -DatabaseServer $databaseServerName -ApplicationPool "SharePoint Web App Pool" -AuthenticationMethod Kerberos

#Create MySite Host Site

Write-Host "Creating MySite Host Site..."

New-SPSite -Name "MySite" -URL "http://mysite:100" -OwnerAlias "CORPONE\sp_install" -Template SPSMSITEHOST#0

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

# Writes all of your farm's incoming URLs to a server's local hosts file

# and points them to the server itself

# It also disables the LSA loopback check

#Make backup copy of the Hosts file with today's date

$hostsfile = 'C:\Windows\System32\drivers\etc\hosts'

$date = Get-Date -UFormat "%y%m%d%H%M%S"

$filecopy = $hostsfile + '.' + $date + '.copy'

Copy-Item $hostsfile -Destination $filecopy

Write-Host "Backup of the host file with todays date is created"

# Get a list of the AAMs and weed out the duplicates

$hosts = Get-SPAlternateURL | ForEach-Object {$_.incomingurl.replace("https://","").replace("http://","")} | where-Object { $_.tostring() -notlike "*:*" } | Select-Object -Unique

# Get the contents of the Hosts file

$file = Get-Content $hostsfile

$file = $file | Out-String

# write the AAMs to the hosts file, unless they already exist.

$hosts | ForEach-Object { if ($file.contains($_))

{Write-Host "Entry for $_ already exists. Skipping"} else

{Write-host "Adding entry for $_" ; add-content -path $hostsfile -value "127.0.0.1 `t $_ " }}

Write-Host "AAMs have been written to the host file"

# Disable the loopback check, since everything we just did will fail if it's enabled

New-ItemProperty HKLM:\System\CurrentControlSet\Control\Lsa -Name "DisableLoopbackCheck" -Value "1" -PropertyType dword

Write-Host "Disabled Loopback Check"

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

# Create the Service App Pool

New-SPServiceApplicationPool -Name "SharePoint Service App Pool" -Account CORPONE\sp_serviceapps

$apppool = Get-SPServiceApplicationPool "SharePoint Service App Pool"

# Set the default database server

$configdb = Get-SPDatabase | where type -EQ "SP2013_Config"

$dbserver = $configdb.NormalizedDataSource

# Create State Service

Write-Host "Provisioning State Service..."

New-SPStateServiceApplication -Name "State Service Application"

Get-SPStateServiceApplication  | New-SPStateServiceApplicationProxy -defaultproxygroup

Get-SPStateServiceApplication | New-SPStateServiceDatabase -Name "SP2013_State_Service" -Databaseserver $dbserver

Get-spdatabase | where-object {$_.type -eq "Microsoft.Office.Server.Administration.StateDatabase"} | initialize-spstateservicedatabase

# Create Usage and Health Data Collection Service

Write-Host "Provisioning Usage and Health Data Collection Service..."

New-SPUsageApplication -Name "Usage and Health Data Collection"

$proxy = Get-SPServiceApplicationProxy | where {$_.TypeName -eq "Usage and Health Data Collection Proxy"}

$proxy.Provision()

# Create Managed Metadata Service

Write-Host "Provisioning Managed Metadata Service..."

New-SPMetadataServiceApplication -Name "Managed Metadata Service" -ApplicationPool $apppool -DatabaseServer $dbserver -DatabaseName "SP2013_Metadata_Service"

New-SPMetadataServiceApplicationProxy -Name "Managed Metadata Service Proxy" -DefaultProxyGroup -ServiceApplication "Managed Metadata Service"

Get-SPServiceInstance | where-object {$_.TypeName -eq "Managed Metadata Web Service"} | Start-SPServiceInstance

# I can probably assign the variable and create the proxy in one step. Need to test

$saproxy = Get-SPServiceApplicationProxy | Where-Object { $_.typename -like "Managed*" }

$saproxy.Properties.IsDefaultSiteCollectionTaxonomy = $true

$saproxy.Update()

# Create Secure Store Service

Write-Host "Provisioning Secure Store Service..."

New-SPSecureStoreServiceApplication -ApplicationPool $apppool -AuditingEnabled:$false -DatabaseServer $databaseServerName -DatabaseName "SP2013_SecureStore_Service"-Name "Secure Store Service"

Get-SPServiceApplication | Where-Object {$_.typename -eq "Secure Store Service Application"} | New-SPSecureStoreServiceApplicationProxy -Name "Secure Store Service"

Get-SPServiceInstance | Where-Object { $_.TypeName -eq "Secure Store Service" } | Start-SPServiceInstance

# Create Business Connectivity Services

Write-Host "Provisioning Business Connectivity Services..."

$svcapp = New-SPBusinessDataCatalogServiceApplication -ApplicationPool $apppool -DatabaseName "SP2013_BusinessConnectivity_Service" -DatabaseServer $databaseServerName -Name "Business Connectivity Services"

New-SPBusinessDataCatalogServiceApplicationProxy -Name "Business Connectivity Services Proxy" -ServiceApplication $svcapp

Get-SPServiceInstance | Where-Object { $_.TypeName -eq "Business Data Connectivity Service" } | Start-SPServiceInstance

# Application Management Service Variables

$appname = "App Management Service"

$dbname = "SP2013_AppManagement_Service"

# Create App Management Service

Write-Host "Provisioning Application Management Service..."

$sa = New-SPAppManagementServiceApplication -ApplicationPool $apppool -Name $appname -DatabaseName $dbname

New-SPAppManagementServiceApplicationProxy -ServiceApplication $sa -Name "$appname Proxy"

Get-SPServiceInstance | Where-Object { $_.typename -eq "App Management Service" } | Start-SPServiceInstance

Write-Host "Application Management Service Provisioned and Started"

# Create Word Automation Services

Write-Host "Creating Word Conversion Service and Proxy..."

New-SPWordConversionServiceApplication -Name "Word Automation Services" -ApplicationPool $apppool -DatabaseServer $databaseServerName -DatabaseName "SP2013_WordAutomation_Services" -Default > $null

Get-SPServiceInstance | where-object {$_.TypeName -eq "Word Automation Services"} | Start-SPServiceInstance > $null

# Create Work Management Service Application and Proxy

Write-Host "Creating Work Management Service Application and Proxy..."

$WMServiceApp = New-SPWorkManagementServiceApplication -Name "Work Management Service Application" -ApplicationPool $apppool

New-SPWorkManagementServiceApplicationProxy -Name "Work Management Service Proxy" -ServiceApplication $WMServiceApp

# Add sp_farm to Logon on Locally

$accountToAdd = "CORPONE\sp_farm"

$sidstr = $null

try {

$ntprincipal = new-object System.Security.Principal.NTAccount "$accountToAdd"

$sid = $ntprincipal.Translate([System.Security.Principal.SecurityIdentifier])

$sidstr = $sid.Value.ToString()

} catch {

$sidstr = $null

}

Write-Host "Account: $($accountToAdd)" -ForegroundColor DarkCyan

if( [string]::IsNullOrEmpty($sidstr) ) {

Write-Host "Account not found!" -ForegroundColor Red

exit -1

}

Write-Host "Account SID: $($sidstr)" -ForegroundColor DarkCyan

$tmp = [System.IO.Path]::GetTempFileName()

Write-Host "Export current Local Security Policy" -ForegroundColor DarkCyan

secedit.exe /export /cfg "$($tmp)"

$c = Get-Content -Path $tmp

$currentSetting = ""

foreach($s in $c) {

if( $s -like "SeInteractiveLogonRight*") {

$x = $s.split("=",[System.StringSplitOptions]::RemoveEmptyEntries)

$currentSetting = $x[1].Trim()

}

}

if( $currentSetting -notlike "*$($sidstr)*" ) {

Write-Host "Modify Setting ""Allow Logon Locally""" -ForegroundColor DarkCyan

if( [string]::IsNullOrEmpty($currentSetting) ) {

$currentSetting = "*$($sidstr)"

} else {

$currentSetting = "*$($sidstr),$($currentSetting)"

}

Write-Host "$currentSetting"

$outfile = @"

[Unicode]

Unicode=yes

[Version]

signature="`$CHICAGO`$"

Revision=1

[Privilege Rights]

SeInteractiveLogonRight = $($currentSetting)

"@

$tmp2 = [System.IO.Path]::GetTempFileName()

Write-Host "Import new settings to Local Security Policy" -ForegroundColor DarkCyan

$outfile | Set-Content -Path $tmp2 -Encoding Unicode -Force

#notepad.exe $tmp2

Push-Location (Split-Path $tmp2)

try {

secedit.exe /configure /db "secedit.sdb" /cfg "$($tmp2)" /areas USER_RIGHTS

#write-host "secedit.exe /configure /db ""secedit.sdb"" /cfg ""$($tmp2)"" /areas USER_RIGHTS "

} finally {

Pop-Location

}

} else {

Write-Host "NO ACTIONS REQUIRED! Account already in ""Allow Logon Locally""" -ForegroundColor DarkCyan

}

Write-Host "Done." -ForegroundColor DarkCyan

# Start a bunch of service instances

Get-SPServiceInstance | Where-Object { $_.typename -eq "Claims to Windows Token Service" } | Start-SPServiceInstance

Get-SPServiceInstance | Where-Object { $_.typename -eq "Excel Calculation Services" } | Start-SPServiceInstance

Get-SPServiceInstance | Where-Object { $_.typename -eq "Machine Translation Service" } | Start-SPServiceInstance

Get-SPServiceInstance | Where-Object { $_.typename -eq "Visio Graphics Service" } | Start-SPServiceInstance

Write-Host "Claims to Windows Token Service Started"

Write-Host "Excel Calculation Services Started"

Write-Host "Machine Translation Service Started"

Write-Host "Visio Graphics Service Started"

Write-Host "Service Application are Created!"

Stop-Transcript