SharePoint 2016 farm configuration using PowerShell

With the arrival of SharePoint 2016, farm configuration changed a bit. A new feature was added which allows you to choose the role of the server when you create a new SharePoint farm, or when you are joining a server to an existing farm. This feature is called MinRole. In PowerShell, there are 2 cmdlets which are involved in the creation of a farm or in the joining in an existing farm.

These cmdlets have a new parameter -LocalServerRole which accepts a Microsoft.SharePoint.Administration.SPServerRole value.

New-SPConfigurationDatabase  -DatabaseName $ConfigDBName -DatabaseServer $DatabaseServer -AdministrationContentDatabaseName $AdminContentDBName -FarmCredentials $FarmCredential -Passphrase $Passphrase -LocalServerRole $ServerRole
Connect-SPConfigurationDatabase -DatabaseServer $DBServer -DatabaseName $DBName -PassPhrase $SecurePassPhrase -LocalServerRole $ServerRole

I created 2 complete scripts which use these cmdlets. These scripts have a parameter -SPVersion which accepts 3 values: 2010, 2013, and 2016. This makes these scripts usable for SharePoint 2010, 2013, and 2016. When 2016 is specified, the user will be prompted to select the role.

Update 04/10/2016 : The Join-Farm script has been updated. After adding a server to a farm, there are 2 services which are not started immediately:

  • SharePoint Timer Service
  • App Fabric Caching Service

The script has been updated to check for these services and will start them if needed. The App Fabric Caching service is obviously only started if the server has been chosen to be a distributed cache host.

Update 10/11/2016 : I have updated the scripts below somewhat.

  • They now include the extra 2 server roles which came with Feature Pack 1.
  • The parameters are changed to be a bit more dynamic. For example, you now have a switch parameter to indicate if it’s a 2010, 2013 or 2016 farm. Depending on that switch, a different set of parameters is applicable.

Farm Configuration Script

<#
.SYNOPSIS
    SharePoint Farm Configuration.

.DESCRIPTION
    Configures the local SharePoint farm:
        - Create the configuration database
        - Secure SharePoint resources
        - Install Services
        - Install Features
        - Provision Central Administration
        - Install Help Collection
        - Install Application Content

.NOTES
    File Name: Configure-Farm.ps1
    Author   : Bart Kuppens
    Version  : 2.5
	
.PARAMETER DatabaseServer
    Specifies the name of the server where the configuration database will be created.
	
.PARAMETER ConfigDBName
    Specifies the name of the SharePoint Configuration database.
	
.PARAMETER AdminContentDBName
    Specifies the name of the SharePoint Administration Content Database.
	
.PARAMETER CentralAdminPort
    Specifies the number of the port for the Central Administration web application
	
.PARAMETER AuthProvider
    Specifies the name of the authenticationprovider which will be used to create the
    Central Administration web application ("NTLM" or "KERBEROS")

.PARAMETER FarmCredential
    Specifies the "domain\username" to be used as the Farm account. If omitted, you will be prompted to 
    provide a valid domain account."

.PARAMETER SP2010
    Specified when a new farm is created for SharePoint 2010.

.PARAMETER SP2013
    Specified when a new farm is created for SharePoint 2013.

.PARAMETER SP2016
    Specified when a new farm is created for SharePoint 2016.

.PARAMETER IsDistributedCacheHost
    Specified when this server will be a Distributed Cache Host.
    For SP2016 farms, this parameter is only important when a "Custom" ServerRole is required and this local server needs to be
    a DistributedCache server.

.PARAMETER ServerRole
    Specifies the role of the first server in the new farm.
    Possible values: Custom, WebFrontEnd, Application, DistributedCache, SingleServerFarm, Search, 
                     ApplicationWithSearch, WebFrontEndWithDistributedCache
    
    IMPORTANT!!! The roles 'ApplicationWithSearch' and 'WebFrontEndWithDistributionCache' are only valid 
                 when Feature Pack 1 has been installed (KB3127940 & KB3127942)

.EXAMPLE
    PS > .\Configure-Farm.ps1 -DatabaseServer SHPDB -ConfigDBName SharePoint_Config_DB 
    -AdminContentDBName SharePoint_Administration_DB -CentralAdminPort 1111 -AuthProvider NTLM -SP2010

    DESCRIPTION
    -----------
    Will create a new SharePoint 2010 farm.

.EXAMPLE
    PS > .\Configure-Farm.ps1 -DatabaseServer SHPDB -ConfigDBName SharePoint_Config_DB 
    -AdminContentDBName SharePoint_Administration_DB -CentralAdminPort 1111 -AuthProvider NTLM -SP2013 -IsDistributedCacheHost

    DESCRIPTION
    -----------
    Will create a new SharePoint 2013 farm and set the local server as a distributed cache host.

.EXAMPLE
    PS > .\Configure-Farm.ps1 -DatabaseServer SHPDB -ConfigDBName SharePoint_Config_DB 
    -AdminContentDBName SharePoint_Administration_DB -CentralAdminPort 1111 -AuthProvider NTLM -SP2016 -ServerRole Application

    DESCRIPTION
    -----------
    Will create a new SharePoint 2016 farm and give the local server the "Application" server minrole.

.EXAMPLE
    PS > .\Configure-Farm.ps1 -DatabaseServer SHPDB -ConfigDBName SharePoint_Config_DB 
    -AdminContentDBName SharePoint_Administration_DB -CentralAdminPort 1111 -AuthProvider NTLM -SP2016 -ServerRole DistributedCache

    DESCRIPTION
    -----------
    Will create a new SharePoint 2016 farm and give the local server the "DistributedCache" server minrole.

#>
[CmdletBinding()]
param(
    [parameter(ParameterSetName="2010",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2013",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [ValidateNotNullOrEmpty()]
    [string]$DatabaseServer,
    [parameter(ParameterSetName="2010",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2013",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [ValidateNotNullOrEmpty()]
    [string]$ConfigDBName,
    [parameter(ParameterSetName="2010",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2013",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [ValidateNotNullOrEmpty()]
    [string]$AdminContentDBName,
    [parameter(ParameterSetName="2010",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2013",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [ValidateNotNullOrEmpty()]
    [string]$CentralAdminPort,
    [parameter(ParameterSetName="2010",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2013",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [ValidateSet("NTLM","Kerberos")]
    [string]$AuthProvider,
    [parameter(ParameterSetName="2010",Mandatory=$false,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2013",Mandatory=$false,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2016",Mandatory=$false,ValueFromPipeLine=$false)]
    [PSCredential]$FarmCredential,
    [parameter(ParameterSetName="2010",Mandatory=$true,ValueFromPipeLine=$false)]
    [switch]$SP2010,
    [parameter(ParameterSetName="2013",Mandatory=$true,ValueFromPipeLine=$false)]
    [switch]$SP2013,
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [switch]$SP2016,
    [parameter(ParameterSetName="2013",Mandatory=$false,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2016",Mandatory=$false,ValueFromPipeLine=$false)]
    [switch]$IsDistributedCacheHost,
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [ValidateSet("Custom","WebFrontEnd","Application","DistributedCache","SingleServerFarm","Search","ApplicationWithSearch","WebFrontEndWithDistributedCache")]
    [string]$ServerRole
)

# Load the SharePoint PowerShell snapin if needed
if ((Get-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null)
{
    Add-PSSnapin Microsoft.SharePoint.PowerShell
}

# Get the Farm Credentials needed for the configuration
if ($FarmCredential -eq $null)
{
    $FarmCredential = Get-Credential -Message "Enter the Farm Account credentials"
    if ($FarmCredential -eq $null)
    {
        Write-Host -ForegroundColor Red "No Farm Credentials supplied, halting farm configuration!"
        break
    }
}

# Get the Passphrase for the configuration
$Passphrase = Read-Host -AsSecureString "Enter the Farm Configuration passphrase"
if ($Passphrase -eq $null)
{
    Write-Host -ForegroundColor Red "No passphrase supplied, halting farm configuration!"
    break
}

# Start configuration
Write-Progress -Activity "SharePoint Farm Configuration" -Status "Creating SharePoint configuration database" -PercentComplete 20
if ($SP2016)
{
    if ($IsDistributedCacheHost)
    {
        New-SPConfigurationDatabase -DatabaseName $ConfigDBName -DatabaseServer $DatabaseServer -AdministrationContentDatabaseName $AdminContentDBName -FarmCredentials $FarmCredential -Passphrase $Passphrase -LocalServerRole $ServerRole -ErrorVariable err
    }
    else
    {
        New-SPConfigurationDatabase -DatabaseName $ConfigDBName -DatabaseServer $DatabaseServer -AdministrationContentDatabaseName $AdminContentDBName -FarmCredentials $FarmCredential -Passphrase $Passphrase -LocalServerRole $ServerRole -SkipRegisterAsDistributedCacheHost -ErrorVariable err
    }
}
else
{
    if ($SP2013)
    {
        if ($IsDistributedCacheHost)
        {
            New-SPConfigurationDatabase -DatabaseName $ConfigDBName -DatabaseServer $DatabaseServer -AdministrationContentDatabaseName $AdminContentDBName -FarmCredentials $FarmCredential -Passphrase $Passphrase -ErrorVariable err
        }
        else
        {
            New-SPConfigurationDatabase -DatabaseName $ConfigDBName -DatabaseServer $DatabaseServer -AdministrationContentDatabaseName $AdminContentDBName -FarmCredentials $FarmCredential -Passphrase $Passphrase -SkipRegisterAsDistributedCacheHost -ErrorVariable err
        }
    }
    else
    {
        New-SPConfigurationDatabase -DatabaseName $ConfigDBName -DatabaseServer $DatabaseServer -AdministrationContentDatabaseName $AdminContentDBName -FarmCredentials $FarmCredential -Passphrase $Passphrase -ErrorVariable err
    }
}
Write-Progress -Activity "SharePoint Farm Configuration" -Status "Verifying farm creation" -PercentComplete 30
$spfarm = Get-SPFarm

if ($spfarm -ne $null) 
{   
    Write-Progress -Activity "SharePoint Farm Configuration" -Status "Securing SharePoint resources" -PercentComplete 40
    Initialize-SPResourceSecurity -ErrorVariable err            
        
    Write-Progress -Activity "SharePoint Farm Configuration" -Status "Installing services" -PercentComplete 50    
    Install-SPService -ErrorVariable err
        
    Write-Progress -Activity "SharePoint Farm Configuration" -Status "Installing features" -PercentComplete 60    
    Install-SPFeature -AllExistingFeatures -ErrorVariable err > $null
        
    Write-Progress -Activity "SharePoint Farm Configuration" -Status "Provisioning Central Administration" -PercentComplete 70    
    New-SPCentralAdministration -Port $CentralAdminPort -WindowsAuthProvider $AuthProvider -ErrorVariable err
        
    Write-Progress -Activity "SharePoint Farm Configuration" -Status "Installing Help" -PercentComplete 80      
    Install-SPHelpCollection -All -ErrorVariable err
        
    Write-Progress -Activity "SharePoint Farm Configuration" -Status "Installing application content" -PercentComplete 90      
    Install-SPApplicationContent -ErrorVariable err
} 
else 
{ 
    Write-Error "ERROR: $err"
}

Join Farm Script

<#
.SYNOPSIS
    Join a server in an existing SharePoint farm.

.DESCRIPTION
    Join a server in an existing SharePoint farm

.NOTES
    File Name: Join-Farm.ps1
    Author   : Bart Kuppens
    Version  : 2.5
	
.PARAMETER DBServer
    Specifies the name of the database server where the configuration database of the farm is located.
	
.PARAMETER DBName
    Specifies the name of the configuration database of the farm where this server needs to be joined to.
	
.PARAMETER PassPhrase
    The Farm passphrase.

.PARAMETER SP2010
    Specified when a new farm is created for SharePoint 2010.

.PARAMETER SP2013
    Specified when a new farm is created for SharePoint 2013.

.PARAMETER SP2016
    Specified when a new farm is created for SharePoint 2016.

.PARAMETER IsDistributedCacheHost
    Specified when this server will be a Distributed Cache Host.
    For SP2016 farms, this parameter is only important when a "Custom" ServerRole is required and this local server needs to be
    a DistributedCache server.

.PARAMETER ServerRole
    Specifies the role of the first server in the new farm.
    Possible values: Custom, WebFrontEnd, Application, DistributedCache, SingleServerFarm, Search, 
                     ApplicationWithSearch, WebFrontEndWithDistributedCache
    
    IMPORTANT!!! The roles 'ApplicationWithSearch' and 'WebFrontEndWithDistributionCache' are only valid 
                 when Feature Pack 1 has been installed (KB3127940 & KB3127942)

.EXAMPLE
    PS > .\Join-Farm.ps1 -DBServer SHPDB -DBName SharePoint_Config_DB -PassPhrase "blabla" -SP2010

    DESCRIPTION
    -----------
    Will create a new SharePoint 2010 farm.

.EXAMPLE
    PS > .\Join-Farm.ps1 -DBServer SHPDB -DBName SharePoint_Config_DB -PassPhrase "blabla" -SP2013

    DESCRIPTION
    -----------
    Will create a new SharePoint 2013 farm but will not configure the current server as a DistributedCache Host

.EXAMPLE
    PS > .\Join-Farm.ps1 -DBServer SHPDB -DBName SharePoint_Config_DB -PassPhrase "blabla" -SP2016 -ServerRole Search

    DESCRIPTION
    -----------
    Will create a new SharePoint 2016 farm and give it a "Search" server role.

#>
[CmdletBinding()]
param(
    [parameter(ParameterSetName="2010",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2013",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [ValidateNotNullOrEmpty()]
    [string]$DBServer,
    [parameter(ParameterSetName="2010",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2013",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [ValidateNotNullOrEmpty()]
    [string]$DBName,
    [parameter(ParameterSetName="2010",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2013",Mandatory=$true,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [ValidateNotNullOrEmpty()]
    [string]$PassPhrase,
    [parameter(ParameterSetName="2010",Mandatory=$true,ValueFromPipeLine=$false)]
    [switch]$SP2010,
    [parameter(ParameterSetName="2013",Mandatory=$true,ValueFromPipeLine=$false)]
    [switch]$SP2013,
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [switch]$SP2016,
    [parameter(ParameterSetName="2013",Mandatory=$false,ValueFromPipeLine=$false)]
    [parameter(ParameterSetName="2016",Mandatory=$false,ValueFromPipeLine=$false)]
    [switch]$IsDistributedCacheHost,
    [parameter(ParameterSetName="2016",Mandatory=$true,ValueFromPipeLine=$false)]
    [ValidateSet("Custom","WebFrontEnd","Application","DistributedCache","SingleServerFarm","Search","ApplicationWithSearch","WebFrontEndWithDistributedCache")]
    [string]$ServerRole
)

# Load the SharePoint PowerShell snapin if needed
if ((Get-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null)
{
    Add-PSSnapin Microsoft.SharePoint.PowerShell
}

$SecurePassPhrase = ConvertTo-SecureString $PassPhrase -AsPlainText -Force

try 
{
    Write-Host "Joining the farm..."
    if ($SP2016)
    {
        if ($IsDistributedCacheHost)
        {
            Connect-SPConfigurationDatabase -DatabaseServer $DBServer -DatabaseName $DBName -PassPhrase $SecurePassPhrase -LocalServerRole $ServerRole
        }
        else
        {
            Connect-SPConfigurationDatabase -DatabaseServer $DBServer -DatabaseName $DBName -PassPhrase $SecurePassPhrase -LocalServerRole $ServerRole -SkipRegisterAsDistributedCacheHost
        }
    }
    else
    {
        if ($SP2013)
        {
            if ($IsDistributedCacheHost)
            {
                Connect-SPConfigurationDatabase -DatabaseServer $DBServer -DatabaseName $DBName -PassPhrase $SecurePassPhrase
            }
            else
            {
                Connect-SPConfigurationDatabase -DatabaseServer $DBServer -DatabaseName $DBName -PassPhrase $SecurePassPhrase -SkipRegisterAsDistributedCacheHost
            }
        }
        else
        {
            Connect-SPConfigurationDatabase -DatabaseServer $DBServer -DatabaseName $DBName -PassPhrase $SecurePassPhrase
        }
    }

    Write-Host "Installing Help"
    Install-SPHelpCollection -All

    Write-Host "Securing SharePoint resources"
    Initialize-SPResourceSecurity

    Write-Host "Installing services"
    Install-SPService

    Write-Host "Installing features"
    Install-SPFeature -AllExistingFeatures

    Write-Host "Installing application content"
    Install-SPApplicationContent

    # Start Services if needed
    Write-Host "Checking status SharePoint Timer service"
    $timersvc = Get-Service SPTimerV4
    if ($timersvc.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Running)
    {
        Write-Host "   SharePoint Timer Service not running... starting the service"
        $timersvc.Start()
    }

    if (($SPVersion -eq "2013" -or $SPVersion -eq "2016") -and ($IsDistributedCacheHost))
    {
        Write-Host "Checking status Distributed Cache Service"
        $distributedCacheSvc = Get-Service AppFabricCachingService
        if ($distributedCacheSvc.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Running)
        {
            Write-Host "   AppFabric Caching Service not running... starting the service"
            $distributedCacheSvc.Start()
        }
    }
} 
catch 
{
    Write-Host "Server was not joined in the farm"
}

 

By Bart

Bart is a certified SharePoint consultant / architect at CTG Belgium NV with a broad professional experience in IT, a background in software development with a specialisation in Microsoft products and technologies and a solid knowledge and experience in Microsoft SharePoint Products and Technologies. He started as a COBOL developer on a mainframe environment and grew into software development for Windows platforms. Participated in projects varying from migrations of existing applications to development of Web applications and Windows applications. Became fascinated by the SharePoint 2007 platform and strongly believed in the added business value of this platform. Is since then fully committed to SharePoint and focuses on SharePoint implementations, migrations, integrations, design and coaching. Stays on top of new developments within the SharePoint technology stack and related technologies.

10 comments

    1. It can be done since it’s just provisioning or deprovisioning the Central Admin Service on the new server. But there are some additional steps to be completed as well. You need to update the AAM for CA because this is not changed automatically. And you need to change the URL for CA in the registry on all farm servers to point to the new server. So, there’s a little more to it than just starting the service. But it can be done. Spencer Harbar has an article on what you need to do to change CA to a different server.

  1. Thank U for the reply Bart,

    1.when i executed this script there was no errors everything was fine but when i go and check the Appfabric service its not started and i tried manually to start using (start-service AppFabricCachingService -PassThru) showing error as cannot start the service in this computer
    2.”Microsoft SharePoint Foundation Administration”,”Microsoft SharePoint Foundation Timer both services” not started in “Services in Server” page the status showing empty
    (Timerservices status showing Running(checked By PowerShell)

      1. Bart,

        Below are the services running in this server also there is one more Front end server apart from it in both servers running same services, in both servers Central Administration running is that common in Min Role topology ? as i said earlier “SharePoint Foundation Administration”,”Microsoft SharePoint Foundation Timer” status is empty after reboot…

        Claims to Windows Token Service Started
        Microsoft SharePoint Foundation Web Application
        Central Administration
        Application Discovery and Load Balancer Service

  2. Hi Bart,

    I have connected new wfe server and i selected YES option when it asks to host Distributedcache but after the server ready when i check the services it just running WFE services only not running Distributed Cache service, please let me know if anything missing.

    Best Regards,

    Shan

     

     

    1. Hello Shan,
      this is correct. You will probably notice also that the SharePoint Timer Service is not started as well. I noticed the same thing last week. I have already updated the Join-Farm script to start both services after adding the server to the farm, if they are stopped. I haven’t had the chance to update the post yet with the updated version of the script. I will do this today. Thanks for reminding me. 🙂

Comments are closed.