SharePoint DSC 1.9.0.0 is Released

The latest version of the SharePoint DSC module has been released this last Wednesday, October 5th. You can now obtain the latest bits of the module by running:

Install-Module SharePointDSC

If you wish to update the configurations on a given SharePoint farm to run these latest bits, make sure each .MOF file is first recompiled using the latest package and that the new module bits are copied to every server in the farm.

Here are some of the major changes that were introduced in this version:

  • SPServiceIdentity: A new DSC Resource has been introduced in the module to represent the managed account that is assigned to a service instance.
  • SPWebAppSiteUseAndDeletion: Fixed an issue with the scheduling where is was incorrectly setting the delays in weeks instead of in days.
  • SPWebAppGeneralSettings: Fixed an issue where web applications that weren’t assigned a TimeZone were incorrectly returning -1 instead of $null.
  • SPProductUpdate: Fixed an issue for updating a SharePoint 2013 farm were the resource was always complaining that the farm was missing the OSearch16 (SharePoint 2016 version).
  • Several other fixes related to the Get-TargetResource methods not properly returning values.

Along with the SharePointDSC 1.9.0.0 release, the SharePoint Orchestrator script for ReverseDSC, which allows you to extract the configuration out of an existing SharePoint 2013 or 2016 farm, has also been updated. To leanr more about what is new in the ReverseDSC Orchestrator Script, take a look at my previous blog post What’s New With SharePointDSC.Reverse 1.9.0.0

Patching your SharePoint Farm with PowerShell DSC

Patching a SharePoint 2013/2016 farm with the help of PowerShell Desired State Configuration (DSC) is a common ask I get from customers almost every single time I deliver a DSC engagement. As part of the SharePointDSC module, we offer two main resources to help you automate the patching process for your farm: SPProductUpdate and SPConfigWizard.

  • SPProductUpdate resource is responsible for installing the patch’s bits onto a server in the farm. It is the equivalent of manually running the installer for a Cummulative/Public update onto the given server. It is very important to note that declaring a resource block of this type in your DSC configuration ONLY installs it on the given node. You need to make sure that this resource block gets defined on every server in your farm to make sure all servers have the bits installed on them. This resource allows you to speed up the installation process on the various nodes by automatically shutting down the various Search Services that normally slow down the installation process. In order to shutdown those services during the installation, you need to specify the ShutdownServices parameter to $true
  • SPConfigWizard on the other hand, is the equivalent of running PSConfig on a given server. It is responsible for committing the installed bits into the configuration database to finalize the farm’s upgrade process. Just like the SPProductUpdate resource, this one needs to be defined against every server in the farm.

Patching Process

In this article, I will demo the process of patching a SharePoint 2016 farm, however the process is the same if you wish to patch a SharePoint 2013 farm. To properly demonstrate the patching process, I will be using a SharePoint 2016 RTM farm, and will be patching it to the September 2017 Public Update, which includes the Feature Pack 2 bits.

  1. The first step is to go an download the SharePoint 2016 – September 2017 Public Update from the web. Decide where you wish to save it. My recommendation is to put it on a Shared Network Location that all servers will be able to access. However, you need to understand the implications of running the Update installer from a Network location using DSC, because your installation process may get stuck due to the User Account Control protection. I’ve put together a short article that lists the most common gotchas for when using DSC and solutions to them. In my case, the file will be put under \\DSC-Share\SP16-Sept16PU\sts2016-kb4011127-fullfile-x64-glb.exe
  2. The second step is to add the DSC Resource blocks into your PowerShell configuration script. The recommendation here is for you to put them right after the SharePoint binaries have been installed via SPInstall, and right before your are actually attempting to have the server join the farm via SPFarm. This would also be the recommendation as far as location within the script for where to install the Language Packs. That is if you are using DSC to install your farm from the ground up.

    For this article however, I am going to demonstrate the case where you already have a SharePoint 2016 Farm built and all you are trying to do in apply a Public Update on it via DSC. The following is the complete script I will be using to achieve this:

    Configuration SP2016September2017PU
    {
        Import-DscResource -ModuleName "SharePointDSC" -ModuleVersion "1.9.0.0"
        $CredsspFarm = Get-Credential -Message "Farm Account"
    
        Node $AllNodes.NodeName
        {
            SPProductUpdate Sept2017PU
            {
                SetupFile = "\\DSC-Share\SP16-Sept16PU\sts2016-kb4011127-fullfile-x64-glb.exe"
                ShutdownServices = $true
                Ensure = "Present"
                PsDscRunAscredential = $CredsspFarm
            }
    
            SPConfigWizard PSConfig
            {
                Ensure = "Present"
                PsDscRunAscredential = $CredsspFarm
            }
        }
    }
    
    $ConfigurationData = @{
        AllNodes = @(
            @{
                NodeName = "SPWFE1"
                PSDscAllowPlainTextPassword = $true;
                PSDscAllowDomainUser = $true;
            },
            @{
                NodeName = "SPWFE2"
                PSDscAllowPlainTextPassword = $true;
                PSDscAllowDomainUser = $true;
            },
            @{
                NodeName = "SPAPP1"
                PSDscAllowPlainTextPassword = $true;
                PSDscAllowDomainUser = $true;
            }
        )
     }
    
    SP2016September2017PU -ConfigurationData $ConfigurationData
    
  3. Initiate the Start-DSCConfiguration SP2016September2017PU -Wait -Verbose -Force cmdlet to initiate the configuration of the servers in the farm.

That was easy enough wasn’t it? Now, whenever a new update comes in that you wish to apply to your farm, simply update the SetupFile parameter’s value to the new PU file. DO NOT ever include more than one SPProduct update block for a given server in your DSC configuration. Updates in SharePoint are cumulative, meaning that if your goal is to update a farm to the October 2017 PU, you don’t need to install the September 2017 PU first.

How to Get Started with SharePointDSC

The goal of this article is to help people interested in learning how to use PowerShell Desired State Configuration (DSC) to configure their SharePoint environment get started. While it is totally possible for you to configure a SharePoint Farm on an environment that has PowerShell 4.0 installed on, it is our recommendation that you try to use PowerShell 5+ as much as possible, as it offers a lot of improvements on the DSC side. The example covered in this article will be a Single Server SharePoint 2016 farm deployed with SQL Server 2016, on Windows Server 2016. We will be using DSC in push mode, meaning that we will manually execute the Start-DSCConfiguration cmdlet on the environment, and will ensure all dependent DSC Modules are put on the server prior to attempting to configure it.

The end-goal for this article, is to have a brand new Windows Server 2016 virtual machine with nothing on it to begin with, and then let DSC do the following automatically:

  • Install and configure Active Directory Domain Services;
  • Create all required SharePoint accounts;
  • Install SQL Server 2016;
  • Install the SharePoint 2016 Prerequisites;
  • Install SharePoint 2016;
  • Install the SharePoint 2016 French Language Pack;
  • Install the SharePoint 2016 Security Update (KB3115299); This update needs to be extracted in the updates folder of the SharePoint installation (slipstreamed).
  • Configure the SharePoint Farm;

The binaries to install SharePoint and SQL Server will be put on a Shared location, to which our Virtual Machine will have access to. Also, the Security Update (KB3115299) is required for the farm to get properly configured. Without it, you will get the following error thrown when calling the SPFarm DSC Block (at the New-SPConfigurationDatabase step): An error occurred while getting information about the user sp_farm at server contoso.com: The RPC server is unavailable. This installation will be slipstreamed within the SharePoint 2016 installation binaries.

Prerequisites

In this section we will cover the various prerequisites that have to be in place before initiating the DSC configuration.

Shared Location

In the current example, I will create a first Virtual Machine that will act as a file server. The SharePoint 2016 binaries, the SQL Server 2016 binaries, the Windows SXS folder, and the SharePoint 2016 language packs will be put on it. The Virtual Machine will be named DSC-Share, and will expose the following Shared Folders:

  • \\DSC-Share\Media\SP2016Binaries
  • \\DSC-Share\Media\SP2016LanguagePack
  • \\DSC-Share\Media\SQL2016Binaries
  • \\DSC-Share\Media\SXS (Needs to contain the SXS content of the Windows Server 2012 R2 installation Media)
SharePoint 2016 and SQL 2016 Binaries on Shared Drive

SharePoint 2016 and SQL 2016 Binaries on Shared Drive

The SXS folder contains the /Sources/SXS content from the Windows Server 2012 R2 installation media. It contains files that are required by the Prerequisites installer to install the .NET 3.5 components. During the DSC process, the SXS folder will be copied from the Remote Network Share onto the local disk. This is required for the Windows Feature to be properly installed on the local server.

Also, it is important for you to extract the Language pack in the specified folder. By default, when you download a SharePoint language pack, you get a file called serverlanguagepack.exe, however that won’t work with SharePointDSC. In order to properly extract its content you need to run the following command: .\serverlanguagepack.exe /extract:path. This will generate the folder structure expected by SharePointDSC.

SharePoint Virtual Machine

When I said earlier that the goal of this article was to start with a plain vanilla Virtual Machine with nothing installed on it….I lied. Just a tiny bit. Because we will be using DSC in Push mode for our example, the destination server (in my case named DSC-SP) needs to have all the required DSC modules installed on it first. The modules required for our example are the following:

  • xActiveDirectory
  • xNetworking
  • xSQLServer
  • SharePointDSC

The steps to get these properly installed on your server will differ depending on whether or not your Virtual Machine has internet connectivity or not.

Virtual Machine has Internet Connectivity

If your SharePoint server Virtual Machine has internet connectivity, then you are in luck. With the help of the Package Management component of PowerShell 5+, you can simply run the following cmdlets to have PowerShell automatically download the modules from the PowerShell Gallery:

Install-Module xActiveDirectory -Force
Install-Module xNetworking -Force
Install-Module xSQLServer -Force
Install-Module SharePointDSC -Force

Virtual Machine without Internet Connectivity

If your Virtual Machine doesn’t have internet connectivity, then you will have to manually copy the required modules inside the PowerShell modules repository. The easiest way to do that, is to download all the required module from a machine that has internet connectivity (see section just above), and then copy the downloaded modules manually onto the server. When you call the Install-Module cmdlet, PowerShell actually installs the specified module in C:\Program Files\WindowsPowerShell\Modules. Simply make sure you copy all the folders from that machine that has internet connectivity and from where you executed the Install-Module cmdlets, over to your SharePoint Virtual Machine, under the same path.

PowerShell DSC Modules

PowerShell DSC Modules

Set Network Share as being Part of the Intranet Zone

By default, the network share won’t be recognized as a trusted location. If you were to navigate to it from your SharePoint server and try to execute a program from it, you will get prompted with a Security Warning prompt that allows you to trust the file. PowerShell DSC is faced with the same issue in the background and this actually causes the process to hang. In order for PowerShell Desired State Configuration to be able to properly execute remote executable such as the SharePoint Prerequisite Installer, you need to add your network share to the Intranet zone in Internet Explorer. Simply launch the IE options, switch to the security tab, select Intranet, click on Sites and add the path to your network share (in my case file://dsc-share).

The Script

The following DSC script will be used to configure our environment. Its variables will be passed as Configuration data (defined in the next section below). The script itself is very self-explanatory and I will not go over each section in details. Note that for an offline installation, the script expects to see the following files in the prerequisiteinstallerfile folder in the root of your SharePoint 2016 binary installation folder:

  • AppFabric-KB3092423-x64-ENU.exe
  • dotNetFx45_Full_setup.exe
  • MicrosoftIdentityExtensions-64.msi
  • NDP453-KB2969351-x86-x64-AllOS-ENU.exe
  • setup_msipc_x64.exe
  • sqlncli.msi
  • Synchronization.msi
  • vc_redist.x64.exe
  • vcredist_x64.exe
  • WcfDataServices.exe
  • WindowsServerAppFabricSetup_x64.exe
SharePoint 2016 Prerequisites

SharePoint 2016 Prerequisites

You will also notice that at the bottom of the screen there is a section that will automatically compile a Meta-Mof file to configure the Local Configuration Manager (LCM) process on that machine so that it will automatically reboot the server when needed (prerequisites, domain-join, etc.) and automatically pickup the configuration where it left it upon being restarted.

SPStandAlone.ps1

Configuration SPStandAlone
{
    Import-DscResource -ModuleName PSDesiredStateConfiguration
    Import-DscResource -ModuleName xActiveDirectory
    Import-DSCResource -ModuleName xNetworking
    Import-DSCResource -ModuleName xSQLServer
    Import-DscResource -ModuleName SharePointDSC
 
    #region Credentials
    $Script:FarmAdmin = Get-Credential -Username "contoso\sp_farm" -Message "Farm Admin"
    $Script:FarmDomainAdmin = Get-Credential -Username "contoso\administrator" -Message "Domain Administrator"   
    #endregion
 
    node $AllNodes.NodeName
    {
        xFireWall SQLFirewallRule
        {
            Name = "AllowSQLConnection"
            DisplayName = 'Allow SQL Connection'
            Group = 'DSC Configuration Rules'
            Ensure = 'Present'
            Enabled = 'True'
            Profile = ('Domain') 
            Direction = 'InBound'
            LocalPort = ('1433') 
            Protocol = 'TCP'
            Description = 'Firewall Rule to allow SQL communication'
            DependsOn = @("[xADDomain]Domain","[xADUser]FarmAdmin")
        }
 
        WindowsFeature ADDS
        {
            Name = "AD-Domain-Services"
            IncludeAllSubFeature = $true
            Ensure = "Present"
        }
 
        WindowsFeature ADDSTools
        {
            Name = 'RSAT-AD-Tools'
            IncludeAllSubFeature = $true
            Ensure = "Present"
        }
 
        xADDomain Domain
        {
            DomainName = $AllNodes.DomainName
            DomainAdministratorCredential = $Script:FarmDomainAdmin
            SafemodeAdministratorPassword = $Script:FarmDomainAdmin
            DependsOn = "[WindowsFeature]ADDS"
        }
 
        xADUser FarmAdmin
        {
            DomainName = $AllNodes.DomainName
            Username = $Script:FarmAdmin.UserName.Replace(($AllNodes.DomainNetBIOS + "\"),"")
            Password = $Script:FarmAdmin
            PasswordNeverExpires = $true
            DependsOn = "[xADDomain]Domain"
        }
         
        xSQLServerSetup SQLSetup
        {
            InstanceName = "MSSQLServer"
            SourcePath = $AllNodes.SQLBinaryPath
            Features = "SQLENGINE"
            InstallSharedDir = "C:\Program Files\Microsoft SQL Server"
            SQLSysAdminAccounts = $Script:FarmAdmin.UserName
            SQLSvcAccount = $Script:FarmDomainAdmin
            AgtSvcAccount = $Script:FarmDomainAdmin
            PSDscRunAsCredential = $Script:FarmDomainAdmin
            DependsOn = @("[xADDomain]Domain","[xADUser]FarmAdmin","[xFirewall]SQLFirewallRule")
        }

	File SXSFolder
	{
	    SourcePath = $AllNodes.SXSRemotePath
	    Type = "Directory"
	    DestinationPath = $AllNodes.SxsLocalPath
	    Recurse = $true;
	    Credential = $Script:FarmDomainAdmin
	    Force = $true
	    PSDSCRunAsCredential = $Script:FarmDomainAdmin
	}
 
        SPInstallPrereqs SPPrereqs
        {
            InstallerPath = $AllNodes.SharePointBinaryPath + "\prerequisiteinstaller.exe"
            OnlineMode = $false
            SQLNCli = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\sqlncli.msi"
            DOTNETFX = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\dotNetfx45_Full_setup.exe"
            NETFX = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\NDP453-KB2969351-x86-x64-AllOS-ENU.exe"
            Sync = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\Synchronization.msi"
            AppFabric = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\WindowsServerAppFabricSetup_x64.exe"
            IDFX11 = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\MicrosoftIdentityExtensions-64.msi"
            MSIPCClient = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\setup_msipc_x64.exe"
            WCFDataServices56 = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\WcfDataServices.exe"
            KB3092423 = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\AppFabric-KB3092423-x64-ENU.exe"
            MSVCRT11 = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\vcredist_x64.exe"
            MSVCRT14 = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\vc_redist.x64.exe"
            ODBC = $AllNodes.SharePointBinaryPath + "\prerequisiteinstallerfiles\msodbcsql.msi"
            DependsOn = @("[xSQLServerSetup]SQLSetup","[File]SXSFolder")
	    SXSPath = $AllNodes.SXSLocalPath
            PSDSCRunAsCredential = $Script:FarmDomainAdmin
        }
 
        SPInstall InstallSharePoint 
        { 
             Ensure = "Present" 
             BinaryDir = $AllNodes.SharePointBinaryPath 
             ProductKey = $AllNodes.ProductKey
             DependsOn = @("[SPInstallPrereqs]SPPrereqs", "[xFirewall]SQLFirewallRule")
 	     PSDSCRunasCredential = $Script:FarmDomainAdmin
        }
         
        SPInstallLanguagePack InstallLPBinaries
        {
            BinaryDir = $AllNodes.LanguagePackPath
            Ensure = "Present"
            DependsOn = "[SPInstall]InstallSharePoint"
            PsDscRunAsCredential = $Script:FarmDomainAdmin
        }
         
        SPFarm SharePointFarm
        {
            Passphrase = New-Object System.Management.Automation.PSCredential ('Passphrase', (ConvertTo-SecureString $AllNodes.Passphrase -AsPlainText -Force));
            AdminContentDatabaseName = "SP2016_CENTRAL_ADMIN";
            FarmAccount = $Script:FarmAdmin;
            FarmConfigDatabaseName = "SP2016_Config";
            CentralAdministrationPort = 7777;
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
            CentralAdministrationAuth = "NTLM";
            RunCentralAdmin = $True;
	    ServerRole = "SingleServerFarm"
            Ensure = "Present";
            DatabaseServer = $AllNodes.NodeName;
            DependsOn = @("[SPInstallLanguagePack]InstallLPBinaries");
        }
        SPManagedAccount b3c4904a-3e85-4ddd-896b-1359901667e7
        {
            Account = $Script:FarmAdmin;
            AccountName = $Script:FarmAdmin.Username;
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
            Ensure = "Present";
            EmailNotification = 5;
            PreExpireDays = 2;
        }
	
        SPServiceAppPool SearchServiceAppPool
        {
            Name = "SP2016-Search";
            ServiceAccount = $Script:FarmAdmin.Username;
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
            Ensure = "Present";
        }  
        SPWebApplication SP2016
        {
            DatabaseName = "SP2016-Content";
            Url = "http://" + $AllNodes.NodeName + "/";
            ApplicationPool = "SP2016-AppPool";
            Path = "C:\inetpub\wwwroot\wss\VirtualDirectories\80";
            UseSSL = $False;
            AllowAnonymous = $False;
            Name = "SP2016";
            AuthenticationMethod = "NTLM";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
            ApplicationPoolAccount = $Script:FarmAdmin.Username;
            Ensure = "Present";
            Port = "80";
            DatabaseServer = $AllNodes.NodeName;
            AuthenticationProvider = "Windows Authentication";
        }
        SPServiceAppPool MMS        
        {
            Name = "MMS";
            ServiceAccount = $Script:FarmAdmin.Username;
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
            Ensure = "Present";
        }  
        SPContentDatabase SP2016-Content
        {
            Enabled = $True;
            MaximumSiteCount = 5000;
            Name = "SP2016-Content";
            Ensure = "Present";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
            WarningSiteCount = 2000;
            DatabaseServer = $AllNodes.NodeName;
            WebAppUrl = "http://" + $AllNodes.NodeName;
        }                    
        SPQuotaTemplate 10bac15d-d097-471a-b09c-82a63d1818bb
        {
            Name = "10GB";
            MaximumUsagePointsSolutions = 300;
            Ensure = "Present";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
            StorageMaxInMB = 10240;
            WarningUsagePointsSolutions = 275;
            StorageWarningInMB = 8192;
        }   
        SPSite 50721b23-6892-4353-a104-814a4295ea42
        {
            OwnerAlias = $Script:FarmAdmin.Username;
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
            Url = "http://" + $AllNodes.NodeName
            Language = 1033;
            QuotaTemplate = "10GB";
            CompatibilityLevel = 15;
            Template = "STS#0";
            ContentDatabase = "SP2016-Content";
            DependsOn =  @("[SPWebApplication]SP2016");
        }
        SPSite 50721b23-6892-4353-a104-814a2395ea42
        {
            OwnerAlias = $Script:FarmAdmin.Username;
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
            Url = "http://" + $AllNodes.NodeName + "/sites/searchcenter"
            Language = 1033;
            QuotaTemplate = "10GB";
            CompatibilityLevel = 15;
            Template = "SRCHCEN#0";
            ContentDatabase = "SP2016-Content";
            DependsOn =  @("[SPWebApplication]SP2016");
        }
        SPServiceInstance CentralAdministrationInstance
        {
            Name = "Central Administration";
            Ensure = "Present";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
        }
        SPServiceInstance ManagedMetadataWebServiceInstance
        {
            Name = "Managed Metadata Web Service";
            Ensure = "Present";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
        }
        SPServiceInstance MicrosoftSharePointFoundationIncomingE-MailInstance
        {
            Name = "Microsoft SharePoint Foundation Incoming E-Mail";
            Ensure = "Present";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
        }
        SPServiceInstance MicrosoftSharePointFoundationWebApplicationInstance
        {
            Name = "Microsoft SharePoint Foundation Web Application";
            Ensure = "Present";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
        }
        SPServiceInstance MicrosoftSharePointFoundationWorkflowTimerServiceInstance
        {
            Name = "Microsoft SharePoint Foundation Workflow Timer Service";
            Ensure = "Present";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
        }
        SPServiceInstance SearchHostControllerServiceInstance
        {
            Name = "Search Host Controller Service";
            Ensure = "Present";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
        }
        SPServiceInstance SearchQueryandSiteSettingsServiceInstance
        {
            Name = "Search Query and Site Settings Service";
            Ensure = "Present";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
        }
        SPServiceInstance SharePointServerSearchInstance
        {
            Name = "SharePoint Server Search";
            Ensure = "Present";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
        }
        SPServiceInstance UserProfileServiceInstance
        {
            Name = "User Profile Service";
            Ensure = "Present";
            PsDSCRunAsCredential = $Script:FarmDomainAdmin;
        }
    }
}
 
#region LCM Config
[DSCLocalConfigurationManager()]
Configuration LCMConfig
{
    Node $env:ComputerName
    {
        Settings
        {
            ActionAfterReboot = 'ContinueConfiguration';
            RebootNodeIfNeeded = $true;
        }
    }
}
LCMConfig
Set-DscLocalConfigurationManager LCMConfig -Force -Verbose
#endregion
 
SPStandAlone -ConfigurationData .\SPStandAlone-ConfigData.psd1

The Configuration Data

If you pay close attention to the last line of the script above, you’ll notice that upon calling our DSC Configuration’s name (in our case SPStandAlone), that we are passing it a path to a .psd1 file for the -ConfigurationData parameter. This basically tells PowerShell Desired State Configuration that it needs to read the variables contained in that .psd1 file in order to properly compile itself.

That PowerShell Data File (.psd1) is where we will specify all of the variables for our environment. This allows us to keep the .ps1 script generic so that it can be used to generate 100’s of Virtual Machines having the same configuration without having to modify it for each one. We simply need to modify the .psd1 file in order for the changes to be picked up upon the MOF compilation job. In our example, we will be specifying the following content in our .psd1 file. Note how the script above is accessing each of these variables by using $AllNodes.<Variable>. This $AllNodes is a reserved keyword that allows us to access values in the ConfigurationData of any given DSC configuration script. You could also expand the .psd1 to include variables unique for a specific node, if your DSC script node ever defined more than one node (like it should be the case for most SharePoint farms).

SPStandAlone-ConfigData.psd1

@{
    AllNodes = @(    
    @{
        NodeName = $env:COMPUTERNAME;
        PSDscAllowPlainTextPassword = $true;
        PSDscAllowDomainUser = $true;

        #region Parameters
        Passphrase = "pass@word1"
        DomainName = "contoso.com"
        DomainNetBIOS = "contoso"
        ProductKey = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"  
        LanguagePackPath = "\\DSC-Share\Media\SP2016LanguagePack"
        SharePointBinaryPath = "\\DSC-Share\Media\SP2016Binaries"   
        SQLBinaryPath = "\\DSC-Share\Media\SQL2016Binaries"
        SXSLocalPath = "c:\SXS" # The content from the Network Share will be copied locally at that location; 
        SXSRemotePath = "\\DSC-Share\Media\SXS\" 
        #endregion  
    }
)}

Executing the DSC Script

This section describes the steps you need to take in order to initiate the deployment and configuration of your SharePoint 2016 Farm using the PowerShell Desired State Configuration scripts above.

  1. Copy both the SPStandAlone.ps1 and SPStandAlone-ConfigData.psd1 file onto the SharePoint server. In my case, I put hem both under C:\temp\.
    DSC Script and its associated Configuration data

    DSC Script and its associated Configuration data

  2. Open a new PowerShell console as an administrator and browse to the directory where you’ve copied the 2 files.
  3. Execute the SPStandAlone.ps1 script and provide both the SharePoint Farm Admin and Domain Admin credentials when prompted. Even though this user doesn’t yet exist, the credentials you provide here will be used to create the account in Active Directory.
    Compiling your SharePoint DSC MOF file

    Compiling your SharePoint DSC MOF file


    SharePoint DSC MOF File Generated

    SharePoint DSC MOF File Generated

  4. Your .MOF file has now been generated in a new folder named by our Configuration (SPStandAlone).
    SPStandAlone Compiled MOF File

    SPStandAlone Compiled MOF File


    All that is now left to do is to call the following PowerShell cmdlet to initiate the deployment process:

    Start-DSCConfiguration SPStandAlone -Force -Wait -Verbose
    

    The server will automatically reboot several times, and upon rebooting, you will loose the verbose PowerShell console, but don’t worry DSC is still being executed in the background. If you need to check the DSC execution logs, simply open Event Receiver and navigate to Applications and Services Logs > Microsoft > Windows > Desired State Configuration > Operational. After about an hour or so depending on the performance of your environment, you will have a fully working SharePoint 2016 Standalone machine.

Introducing Reverse DSC

Ever since becoming a Microsoft PowerShell MVP back in the summer of 2014, I have been heavily involved with various PowerShell Desired State Configuration (DSC) projects. The main initiative I have been involved with is the SharePointDSC module which is currently led by Brian Farnhill down in Australia. While my contributions to the core of the project have been limited, I have been spending numerous hours working on a new concept I came up with and which is very close to my heart. Reverse DSC is something I introduced back in late 2015 after spending some late night hours testing out my SharePointDSC scripts. It is the concept of extracting a DSC Configuration Script out of an existing environment in order to be able to better analyze it, replicate it or onboard it onto PowerShell DSC. Let me be very clear, this concept does not only apply to the SharePoint world; it applies to all software components that can be automated via DSC. I am of the opinion that this concept will be a game changer in the world of automation, and I strongly encourage you to read through this article to better understand the core concepts behind it.

Definitions

To get started, and to make sure we are all on the same page, let us define the following two terms:

  • Desired State: represents how we want a component to be configured. For example, the Desired State of a SharePoint Site (SPWeb) could be defining its title. The Desired State could in this case define that to be in its Desired State, a given Site needs to have a title of “Intranet”.
  • Current State: represents how a component is currently configured. In many cases the Current State can be the same as the Desired State, which is completely fine. PowerShell DSC aims at making sure that whenever the Current State is not equal to the Desired State, that we do everything in our power to bring the server node back in its Desired state.

Anatomy of a DSC Resource

Before we go any further, it is key to understand how DSC Resources work internally. Just as a refresher, a DSC Resource is responsible for configuring a specific component within a DSC module. For example, within the SharePointDSC module, the MSFT_SPWebApplication resource is responsible for configuring SharePoint Web Applications. Every DSC Resources are made of 3 core functions: Get-TargetResource, Test-TargetResource, and Set-TargetResource.

  • Set-TargetResource is the function responsible for bringing the server in its Desired State by configuring the given component represented by the resource. It is called on the initial configuration call (e.g. Start-DSCConfiguration for Push mode), and when the Local Configuration Manager (LCM) is in the ApplyAndAutocorrect mode and detects that the machine drifted away from its Desired State.
  • Get-TargetResource is the function responsible for analyzing what the current state is for the component represented by the DSC Resource.
  • Test-TargetResource is responsible for calling the Get-TargetResource function to obtain the current state, and compares it with the Desired State contained within the Local Configuration Manager. If it detects that the current state doesn’t match the Desired State, and the LCM is in ApplyAndAutocorrect mode, it will call the Set-TargetResource method to ensure the machine is brought back in its Desired State.

The figure above details the process of PowerShell DSC where the Local Configuration Manager is configured in ApplyAndAutocorrect mode. The LCM checks on a regular basis (defined by the Configuration Mode Frequency) to see if the server is still in its Desired State. To do so, it calls into the Test-TargetResource function. This function is aware of what the Desired State should be because it is stored in the LCM’s memory (use the Get-DSCConfiguration cmdlet to see what is in the LCM’s memory), but needs to call into the Get-TargetResource function to figure out what the current state is. Once that is done, the Test-TargetResource method has information about what both the Desired and Current states are and will compare them. If they are the same, we are done and we will check again later. If they differ, then we need to call into the Set-TargetResource method to try to bring the Current State back to being the same as the Desired State.

The Reverse DSC Concept

The magic of the Reverse DSC concept lies within the Get-TargetResource function. As explained in the section above, this function is responsible for obtaining information about the current state of the server node for a given component. So you may ask if the theory is that if, for example, I wanted to get information about all the Web Applications within my SharePoint environment, all I have to do is call into the Get-TargetResource function for the MSFT_SPWebApplication DSC Resource? Well, that is absolutely correct, and this is what Reverse DSC is all about. A Reverse DSC script is a dynamic PowerShell script that calls into the Get-TargetResource function for each DSC Resource contained within a DSC Module. In the case of SharePoint, that Reverse DSC script would be calling into the Get-TargetResource function for all DSC Resources listed in the following figure (note that the figure shows the components included in SharePointDSC v1.4).

The Reverse DSC script would then be responsible for compiling the current state of each DSC Resources into a complete DSC Configuration Script that would then represent the Current State of each components within our environment. If that ain’t cool, I don’t know what is!

Real-Life Usage

I am a Microsoft Premier Field Engineer, which means that most of my days are spent troubleshooting issues with my clients’ environments. When I came up with the idea of Reverse DSC, my main intent was to ask my clients to run the Reverse DSC script against their environment, and send me back the resulting DSC Configuration Script so that I can replicate their exact environment within my own lab to make it easier for me to troubleshoot their issues with my own set of tools. However, as it is often the case with any innovations, it ends up that the main use for it may be something totally different than what I originally anticipated. Here are some of the awesome real-life applications for Reverse DSC We can come up with:

  • Dev/Test: As mentioned above, one of the main use of Reverse DSC is to allow an as-is replica of an existing environment on-premises. Most organizations I work with don’t have good DEV and Quality Assurance environments that match their Production environment. Running the Reverse DSC script against the production environment will allow users to take the resulting scripts and create exact copies of that environment for DEV and Test purposes.
  • Azure Automation: Organizations that have an on-premises Production environment and that are looking at moving to the cloud (even if just for DEV/Test), can generate use the Reverse DSC script to generate the DSC Configuration matching their on-premises environment, and Publish it to Azure Automation to have Azure Virtual Machine created that will be an exact match of the on-premises environment.
  • Compare environments: How often have we heard the sentence: “It works on my machine!”. With Reverse DSC, we can now run the script against two environments and compare the resulting scripts to see what configuration settings differ between the two.
  • Documentation: While I don’t foresee this as being the most popular reason why organizations would be adopting Reverse DSC, it would still allow them to document (in DSC format) the configuration of an environment at any given point in time.
  • DSC On-boarding: This one is probably one of the key application for DSC adoption within an organization. Most companies today aren’t using DSC to automate the configuration of their environment and ensure they don’t drift away from the specified Desired State. By simply running the Reverse DSC script against an existing environment and then using the resulting script as its own Desired State Configuration script, will ensure the environment is now maintained by the DSC process. It is almost as if by running through this process you would tell the server: “Tell me what your Current state is. Oh and by the way, that Current State you just told me about has just become your Desired State”. By doing this, organization can then specify how the LCM should handle configuration drifts (ApplyAndMonitor or ApplyAndAutocorrect) and detect when the Current State (which is now also the Desired State) is drifting.

See it in Action

The Reverse DSC script for SharePoint is already a real thing. However it is still waiting final approval to become officially part of the SharePointDSC module. The following video shows the execution the Reverse DSC script against my SharePoint 2016 dev server.

Next Blog post in this series-> SharePoint Reverse DSC

SharePoint 2016 Feature Packs

Today at the Ignite conference in Atlanta, Microsoft shared more information about the vision for SharePoint. With SharePoint 2016, it is now possible for organizations to obtain and enable new features within their on-premises environments through the use of “Feature Packs”. In the past, we pretty much had to wait for Service Packs to be released before seeing new features make their way into the product. With Feature Packs, organizations can now activate new features directly into the on-premises product.

The first Feature Pack, scheduled to be made generally available in November of 2016, will introduce the following new features:

For IT Pros

  • Administrative logging: Allowing users to audit actions made in Central Administration;
  • MinRole Changes: Addition of new workloads to support small environments;
  • Unified Logging: Ability to combine logging from both on-premises and Office 365 environments;

For Users

  • OneDrive API Update: One Drive API 2.0 now available on-premises (allows for interaction with Drives and Items);

For Users

  • App Launcher Custom Tiles: Ability to add custom tiles to the App Launcher (waffle icon to left);
  • New OneDrive for Business UX: New User Experience in OneDrive for Business, matching the one introduced in Office 365 last year;
  • Hybrid Taxonomy: Allowing term stores to be unified between on-premises environments and Office 365;

box