Deploying a Multi-Server SharePoint Farm with PowerShell Desired State Configuration

In this article we will cover the process of writing a DSC Configuration with SharePointDSC and deploying it to multiple servers to create a SharePoint 2016 farm (note that this would also work for SharePoint 2013 with minor changes to the SPFarm block). We will be using a Push Refresh mode, meaning that the Configuration will be manually applied to our servers, and not using a Pull Server to centrally manage the configuration. Using this approach, if our configuration was to change, it would need to be manually re-pushed onto the servers in the farm. While I believe that in most cases, you will wish to use a Pull refresh mode along with an Enterprise Pull Server to manage your SharePoint deployments, we are using a Push mode to keep things simple for the sake of this article.

The article will cover a scenario I will be demonstrating over at SPTechCon Austin next week. In this demo, I have a very small multi-server SharePoint 2016 farm that is made up of one dedicated SQL Server 2016 (SPTechCon-SQL), one Web Front-End (SPTechCon-WFE1), and one Application Server (SPTechCon-APP1). The configuration script will be built on a separate machine named (SPTechCon-Pull) and will be remotely applied to the servers in my farm from that machine. The figure below gives you a complete overview of the landscape of my demo.

Every server in my farm is a Windows Server 2016 Datacenter instance. As mentioned above, SPTechCon-SQL has SQL Server 2016 installed on it, and both SharePoint boxes (SPTechCon-WFE1 and SPTechCon-APP1) have the SharePoint 2016 bits installed on them (PSConfig was not run, just the SP2016 bits were installed).

As part of the demo, I will be using the following DSC configuration script to deploy my farm:

Configuration SPTechCon-OnPrem
{
    Import-DSCResource -ModuleName SharePointDSC

    $farmAccount = Get-Credential -UserName "contoso\sp_farm" -Message "Farm Account"
    $adminAccount = Get-Credential -UserName "contoso\sp_admin" -Message "Admin Account"

	Node SPTechCon-WFE1
	{
        SPFarm SPFarm 
        { 
            DatabaseServer           = "SPTechCon-SQL"
            FarmConfigDatabaseName   = "SP_Config" 
            Passphrase               = $farmAccount 
            FarmAccount              = $farmAccount
            AdminContentDatabaseName = "SP_AdminContent" 
            PsDSCRunAsCredential     = $farmAccount
            ServerRole               = "WebFrontEnd"
            Ensure                   = "Present"
            RunCentralAdmin          = $true
            CentralAdministrationPort = 7777
        }

        SPManagedAccount FarmAccount
        {
            AccountName = $farmAccount.UserName
            Account = $farmAccount
            PsDSCRunAsCredential     = $farmAccount
            DependsOn = "[SPFarm]SPFarm"
        }

        SPManagedAccount AdminAccount
        {
            AccountName = $adminAccount.UserName
            Account = $adminAccount
            PsDSCRunAsCredential     = $farmAccount
            DependsOn = "[SPFarm]SPFarm"
        }

        SPServiceAppPool SharePoint80
        {
            Name = "SharePoint - 80"
            ServiceAccount = $adminAccount.UserName
            PsDSCRunAsCredential     = $farmAccount
            DependsOn = "[SPManagedAccount]FarmAccount"
        }

        SPWebApplication RootWebApp
        {
            Name = "RootWebApp"
            ApplicationPool = "SharePoint - 80"
            ApplicationPoolAccount = $adminAccount.UserName
            Url = "http://SPTechCon-WFE1"
            DatabaseServer = "SPTechCon-SQL"
            DatabaseName = "WebApp-SharePoint-80"
            Port = 80
            PsDSCRunAsCredential = $farmAccount
            DependsOn = "[SPServiceAppPool]SharePoint80"
        }

        SPSite RootSite
        {
            Url = "http://SPTechCon-WFE1"
            OwnerAlias = $adminAccount.UserName
            Template = "STS#0"         
            PsDSCRunAsCredential = $farmAccount
            DependsOn = "[SPWebApplication]RootWebApp"
        }
	}
    Node SPTechCon-APP1
	{
        SPFarm SPFarm 
        { 
            DatabaseServer           = "SPTechCon-SQL"
            FarmConfigDatabaseName   = "SP_Config" 
            Passphrase               = $farmAccount 
            FarmAccount              = $farmAccount
            AdminContentDatabaseName = "SP_AdminContent" 
            PsDSCRunAsCredential     = $farmAccount
            ServerRole               = "Application"
            Ensure                   = "Present"
            RunCentralAdmin          = $false
        }
        SPServiceInstance BusinessDataConnectivityServiceInstance
        {
            Name = "Business Data Connectivity Service";
            Ensure = "Present";
            PsDSCRunAsCredential = $farmAccount;
        }
    }
}
$ConfigData = @{
    AllNodes = @(
        @{
            NodeName = "SPTechCon-WFE1"
            PSDscAllowPlainTextPassword = $True
            PSDscAllowDomainUser = $true
        },
        @{
            NodeName = "SPTechCon-APP1"
            PSDscAllowPlainTextPassword = $True
            PSDscAllowDomainUser = $true
        }
    )
}
SPTechCon-OnPrem -ConfigurationData $ConfigData
Start-DSCConfiguration SPTechCon-OnPrem -Wait -Verbose -Force

In summary, that script will automatically create the SharePoint 2016 farm, assign the Web Front-End MinRole to SPTechCon-WFE1, create a Web Application on port 80, and a root site collection, add SPTechCon-APP1 to the farm with the Application MinRole and have it run the Business Connectivity Service. Nothing too complicated, again to keep the demo focused and concise. Now, if you take a look at the last two lines of the script, you see that we are passing ConfigurationData to our Configuration method to ensure passwords can be passed as plain text. In an enterprise context, you will normally want to encrypt the credentials using a certificate. In our case here, I omitted to specify a certificate for simplicity sake.

Let us now head onto our SPTechCon-Pull machine, which is noting but a windows 10 machine hosted on the same domain as our servers to be configured. You will need to make sure that this machine has the SharePointDSC modules installed on it, because it will be required in order for us to compile our MOF file from this server. Installing the module is as easy as running the following cmdlet if your machine has internet connectivity:

Install-Module SharePointDSC

If you machine doesn’t have internet connectivity, then you will need to manually copy the SharePointDSC module onto the machine, under C:\Program Files\WindowsPowerShell\Modules\.

Upon executing the script above, you will be prompted to enter the credentials for the Farm account, which is required to execute the configuration steps, as well as for the admin account’s credentials, which I use as the owner of my site collection. Using remoting, PowerShell will remotely contact the two SharePoint servers and initiate the configuration. After a few minutes, you should see that the execution completed (see figure below).

You should also be able to navigate to the site collection we created (in our case at http://sptechcon-wfe1/) or to central administration, which based on our script, is hosted on SPTechCon-WFE1 and exposed through port 7777.

What is important for you to take away from this example, is that you don’t have to physically go on each server node that are part of your DSC configuration script in order to push the configuration onto it. This can all be done remotely from a machine that is external to the farm, as long as that machine has the SharePointDSC bits installed on it.

5 thoughts on “Deploying a Multi-Server SharePoint Farm with PowerShell Desired State Configuration

  1. Is there a specific reason that your SharePoint Farm is using Windows Server 2016 Datacenter and not Windows Server 2016 Standard

  2. Hi Nik,

    G’day mate!

    I am trying to install SP2013 following your instructions. It is failing with an error saying “PowerShell DSC resource MSFT_SPFarm failed to execute Test-TargetResource functionality with error message: Server role is only supported in SharePoint 2016.”. Could you please let me know what changes need to be done for SPFarm resource for SP2013 installation.

    Cheers.

  3. Hi Nik, thank you for inspiring article.

    To be specific, the machine where you execute mof-file should not necessarily run SharePoint binaries. I only installed SharePoint DSC resources on my admin machine and executed the configuration from there, it worked perfectly.

Leave a Reply

Your email address will not be published. Required fields are marked *