Examples/EndToEndExample/10-OngoingConfiguration.ps1

<#
.EXAMPLE
    This example shows how to configure ongoing configuration.
#>


$ConfigurationData = @{
    AllNodes = @(
        @{
            #region Common Settings for All Nodes
            NodeName        = '*'

            <#
                The location of the exported public certificate which will be used to encrypt
                credentials during compilation.
                CertificateFile = 'C:\public-certificate.cer'
            #>


            # Thumbprint of the certificate being used for decrypting credentials
            Thumbprint      = '39bef4b2e82599233154465323ebf96a12b60673'

            # The paths to the CSV files generated by the Server Role Requirements Calculator
            ServersCsvPath               = "$($PSScriptRoot)\Calculators\Lab\Servers.csv"
            MailboxDatabasesCsvPath      = "$($PSScriptRoot)\Calculators\Lab\MailboxDatabases.csv"
            MailboxDatabaseCopiesCsvPath = "$($PSScriptRoot)\Calculators\Lab\MailboxDatabaseCopies.csv"

            # The base file server UNC path that will be used for copying things like certificates, Exchange binaries, and Jetstress binaries
            FileServerBase = '\\rras-1.contoso.local\Binaries'

            #endregion
        }

        #region Individual Node Settings
        #region DAG01 Nodes
        @{
            NodeName        = 'e15-1'
            Fqdn            = 'e15-1.contoso.local'
            Role            = 'AdditionalDAGMember'
            DAGId           = 'DAG01'
            CASId           = 'Site1CAS'
            ServerNameInCsv = 'e15-1'
        }

        @{
            NodeName        = 'e15-2'
            Fqdn            = 'e15-2.contoso.local'
            Role            = 'AdditionalDAGMember'
            DAGId           = 'DAG01'
            CASId           = 'Site1CAS'
            ServerNameInCsv = 'e15-2'
        }

        @{
            NodeName        = 'e15-3'
            Fqdn            = 'e15-3.contoso.local'
            Role            = 'FirstDAGMember'
            DAGId           = 'DAG01'
            CASId           = 'Site2CAS'
            ServerNameInCsv = 'e15-3'
        }

        @{
            NodeName        = 'e15-4'
            Fqdn            = 'e15-4.contoso.local'
            Role            = 'AdditionalDAGMember'
            DAGId           = 'DAG01'
            CASId           = 'Site2CAS'
            ServerNameInCsv = 'e15-4'
        }
        #endregion
    );

    #region DAG Settings
    DAG01 = @(
        @{
            DAGName                              = 'DAG01'
            AutoDagTotalNumberOfServers          = 12
            AutoDagDatabaseCopiesPerVolume       = 4
            DatabaseAvailabilityGroupIPAddresses = '192.168.1.31', '192.168.2.31'
            WitnessServer                        = 'e14-1.contoso.local'
            DbNameReplacements                   = @{"nn" = "01"}
            Thumbprint                           = "0079D0F68F44C7DA5252B4779F872F46DFAF0CBC"
        }
    )
    #endregion

    #region CAS Settings
    # Settings that will apply to all CAS
    AllCAS = @(
        @{
            ExternalNamespace = 'mail.contoso.local'
        }
    )

    # Settings that will apply only to Quincy CAS
    Site1CAS = @(
        @{
            InternalNamespace          = 'mail-site1.contoso.local'
            AutoDiscoverSiteScope      = 'Site1'
            InstantMessagingServerName = 'l15-1.contoso.local'
            DefaultOAB                 = "Default Offline Address Book (Site1)"
        }
    );

    # Settings that will apply only to Phoenix CAS
    Site2CAS = @(
        @{
            InternalNamespace          = 'mail-site2.contoso.local'
            AutoDiscoverSiteScope      = 'Site2'
            InstantMessagingServerName = 'l15-2.contoso.local'
            DefaultOAB                 = "Default Offline Address Book (Site2)"
        }
    );
    #endregion
}

Configuration Example
{
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullorEmpty()]
        [System.Management.Automation.PSCredential]
        $ExchangeAdminCredential,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullorEmpty()]
        [System.Management.Automation.PSCredential]
        $ExchangeCertCredential,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullorEmpty()]
        [System.Management.Automation.PSCredential]
        $ExchangeFileCopyCredential
    )

    # Import required DSC Modules
    Import-DscResource -Module xExchange
    Import-DscResource -Module xWebAdministration

    Import-Module -Name (Join-Path -Path (Split-Path -Parent (Split-Path -Parent $PSScriptRoot)) -ChildPath 'Modules\xExchangeCalculatorHelper.psm1')

    Node $AllNodes.NodeName
    {
        $dagSettings = $ConfigurationData[$Node.DAGId] # Get DAG settings for this node

        $casSettingsAll = $ConfigurationData.AllCAS # Get CAS settings for all sites
        $casSettingsPerSite = $ConfigurationData[$Node.CASId] # Get site specific CAS settings for this node

        # Copy an certificate .PFX that had been previously exported, import it, and enable services on it
        File CopyExchangeCert
        {
            Ensure          = 'Present'
            SourcePath      = "$($Node.FileServerBase)\Certificates\ExchangeCert.pfx"
            DestinationPath = 'C:\Binaries\Certificates\ExchangeCert.pfx'
            Credential      = $ExchangeFileCopyCredential
        }

        xExchExchangeCertificate Certificate
        {
            Thumbprint         = $dagSettings.Thumbprint
            Credential         = $ExchangeAdminCredential
            Ensure             = 'Present'
            AllowExtraServices = $true
            CertCreds          = $ExchangeCertCredential
            CertFilePath       = 'C:\Binaries\Certificates\ExchangeCert.pfx'
            Services           = 'IIS', 'POP', 'IMAP', 'SMTP'
            DependsOn          = '[File]CopyExchangeCert'
        }

        ###CAS specific settings###
        # The following section shows how to configure commonly configured URL's on various virtual directories
        xExchClientAccessServer CAS
        {
            Identity                       = $Node.NodeName
            Credential                     = $ExchangeAdminCredential
            AutoDiscoverServiceInternalUri = "https://$($casSettingsPerSite.InternalNamespace)/autodiscover/autodiscover.xml"
            AutoDiscoverSiteScope          = $casSettingsPerSite.AutoDiscoverSiteScope
        }

        xExchActiveSyncVirtualDirectory ASVdir
        {
            Identity    = "$($Node.NodeName)\Microsoft-Server-ActiveSync (Default Web Site)"
            Credential  = $ExchangeAdminCredential
            ExternalUrl = "https://$($casSettingsAll.ExternalNamespace)/Microsoft-Server-ActiveSync"
            InternalUrl = "https://$($casSettingsPerSite.InternalNamespace)/Microsoft-Server-ActiveSync"
        }

        xExchEcpVirtualDirectory ECPVDir
        {
            Identity    = "$($Node.NodeName)\ecp (Default Web Site)"
            Credential  = $ExchangeAdminCredential
            ExternalUrl = "https://$($casSettingsAll.ExternalNamespace)/ecp"
            InternalUrl = "https://$($casSettingsPerSite.InternalNamespace)/ecp"
        }

        xExchMapiVirtualDirectory MAPIVdir
        {
            Identity                 = "$($Node.NodeName)\mapi (Default Web Site)"
            Credential               = $ExchangeAdminCredential
            ExternalUrl              = "https://$($casSettingsAll.ExternalNamespace)/mapi"
            InternalUrl              = "https://$($casSettingsPerSite.InternalNamespace)/mapi"
            IISAuthenticationMethods = 'Ntlm', 'OAuth', 'Negotiate'
        }

        xExchOabVirtualDirectory OABVdir
        {
            Identity    = "$($Node.NodeName)\OAB (Default Web Site)"
            Credential  = $ExchangeAdminCredential
            ExternalUrl = "https://$($casSettingsAll.ExternalNamespace)/oab"
            InternalUrl = "https://$($casSettingsPerSite.InternalNamespace)/oab"
        }

        xExchOutlookAnywhere OAVdir
        {
            Identity                           = "$($Node.NodeName)\Rpc (Default Web Site)"
            Credential                         = $ExchangeAdminCredential
            ExternalClientAuthenticationMethod = 'Negotiate'
            ExternalClientsRequireSSL          = $true
            ExternalHostName                   = $casSettingsAll.ExternalNamespace
            IISAuthenticationMethods           = 'Basic', 'Ntlm', 'Negotiate'
            InternalClientAuthenticationMethod = 'Ntlm'
            InternalClientsRequireSSL          = $true
            InternalHostName                   = $casSettingsPerSite.InternalNamespace
        }

        # Configure OWA Lync Integration in the web.config
        xWebConfigKeyValue OWAIMCertificateThumbprint
        {
            WebsitePath   = 'IIS:\Sites\Exchange Back End\owa'
            ConfigSection = 'AppSettings'
            Ensure        = 'Present'
            Key           = 'IMCertificateThumbprint'
            Value         = $dagSettings.Thumbprint
        }

        xWebConfigKeyValue OWAIMServerName
        {
            WebsitePath   = 'IIS:\Sites\Exchange Back End\owa'
            ConfigSection = 'AppSettings'
            Ensure        = 'Present'
            Key           = 'IMServerName'
            Value         = $casSettingsPerSite.InstantMessagingServerName
        }

        # Sets OWA url's, and enables Lync integration on the OWA front end directory
        xExchOwaVirtualDirectory OWAVdir
        {
            Identity                              = "$($Node.NodeName)\owa (Default Web Site)"
            Credential                            = $ExchangeAdminCredential
            ExternalUrl                           = "https://$($casSettingsAll.ExternalNamespace)/owa"
            InternalUrl                           = "https://$($casSettingsPerSite.InternalNamespace)/owa"
            InstantMessagingEnabled               = $true
            InstantMessagingCertificateThumbprint = $dagSettings.Thumbprint
            InstantMessagingServerName            = $casSettingsPerSite.InstantMessagingServerName
            InstantMessagingType                  = 'Ocs'
            DependsOn                             = '[xExchExchangeCertificate]Certificate' # Can't configure the IM cert until it's valid
        }

        xExchWebServicesVirtualDirectory EWSVdir
        {
            Identity             = "$($Node.NodeName)\EWS (Default Web Site)"
            Credential           = $ExchangeAdminCredential
            ExternalUrl          = "https://$($casSettingsAll.ExternalNamespace)/ews/exchange.asmx"
            InternalNLBBypassUrl = "https://$($Node.Fqdn)/ews/exchange.asmx"
            InternalUrl          = "https://$($casSettingsPerSite.InternalNamespace)/ews/exchange.asmx"
        }

        ###Mailbox Server settings###
        $dbMap          = Get-DBMapFromServersCsv -ServersCsvPath $Node.ServersCsvPath `
                                              -ServerNameInCsv $Node.ServerNameInCsv `
                                              -DbNameReplacements $dagSettings.DbNameReplacements

        $primaryDbList  = Get-DBListFromMailboxDatabasesCsv -MailboxDatabasesCsvPath $Node.MailboxDatabasesCsvPath `
                                                        -ServerNameInCsv $Node.ServerNameInCsv `
                                                        -DbNameReplacements $dagSettings.DbNameReplacements

        $copyDbList     = Get-DBListFromMailboxDatabaseCopiesCsv -MailboxDatabaseCopiesCsvPath $Node.MailboxDatabaseCopiesCsvPath `
                                                             -ServerNameInCsv $Node.ServerNameInCsv `
                                                             -DbNameReplacements $dagSettings.DbNameReplacements

        # Create all mount points on the server
        xExchAutoMountPoint AMP
        {
            Identity                       = $Node.NodeName
            AutoDagDatabasesRootFolderPath = 'C:\ExchangeDatabases'
            AutoDagVolumesRootFolderPath   = 'C:\ExchangeVolumes'
            DiskToDBMap                    = $dbMap
            SpareVolumeCount               = 1
            VolumePrefix                   = 'EXVOL'
        }

        # Create primary databases
        foreach ($DB in $primaryDbList)
        {
            # Need to define a unique ID for each database
            $resourceId = "MDB_$($DB.Name)"

            xExchMailboxDatabase $resourceId
            {
                Name                            = $DB.Name
                Credential                      = $ExchangeAdminCredential
                EdbFilePath                     = $DB.DBFilePath
                LogFolderPath                   = $DB.LogFolderPath
                Server                          = $Node.NodeName
                CircularLoggingEnabled          = $true
                DatabaseCopyCount               = $dagSettings.AutoDagDatabaseCopiesPerVolume
                OfflineAddressBook              = $casSettingsPerSite.DefaultOAB
                SkipInitialDatabaseMount        = $true
                DependsOn                       = '[xExchAutoMountPoint]AMP' # Can't create databases until the mount points exist
            }
        }

        # Configure the copies
        foreach ($DB in $copyDbList)
        {
            # Unique ID for the xWaitForMailboxDatabase resource
            $waitResourceId = "WaitForDB_$($DB.Name)"

            # Unique ID for the xMailboxDatabaseCopy resource
            $copyResourceId = "MDBCopy_$($DB.Name)"

            # Need to wait for a primary copy to be created before we add a copy
            xExchWaitForMailboxDatabase $waitResourceId
            {
                Identity   = $DB.Name
                Credential = $ExchangeAdminCredential
            }

            xExchMailboxDatabaseCopy $copyResourceId
            {
                Identity                        = $DB.Name
                Credential                      = $ExchangeAdminCredential
                MailboxServer                   = $Node.NodeName
                ActivationPreference            = $DB.ActivationPreference
                # ReplayLagTime = $DB.ReplayLagTime #Note that ReplayLagTime is being excluded for the ongoing configuration so that it's easier to disable lags, if necessary
                AllowServiceRestart             = $false
                DependsOn                       = "[xExchWaitForMailboxDatabase]$($waitResourceId)"
            }
        }
    }

    # This first section only configures a single DAG node, the first member of the DAG.
    # The first member of the DAG will be responsible for DAG creation and maintaining its configuration
    Node $AllNodes.Where{$_.Role -eq 'FirstDAGMember'}.NodeName
    {
        $dagSettings = $ConfigurationData[$Node.DAGId] # Look up and retrieve the DAG settings for this node

        # Create the DAG
        xExchDatabaseAvailabilityGroup DAG
        {
            Name                                 = $dagSettings.DAGName
            Credential                           = $ExchangeAdminCredential
            AutoDagTotalNumberOfServers          = $dagSettings.AutoDagTotalNumberOfServers
            AutoDagDatabaseCopiesPerVolume       = $dagSettings.AutoDagDatabaseCopiesPerVolume
            AutoDagDatabasesRootFolderPath       = 'C:\ExchangeDatabases'
            AutoDagVolumesRootFolderPath         = 'C:\ExchangeVolumes'
            DatacenterActivationMode             = 'DagOnly'
            DatabaseAvailabilityGroupIPAddresses = $dagSettings.DatabaseAvailabilityGroupIPAddresses
            ManualDagNetworkConfiguration        = $false
            ReplayLagManagerEnabled              = $true
            SkipDagValidation                    = $true
            WitnessDirectory                     = 'C:\FSW'
            WitnessServer                        = $dagSettings.WitnessServer
        }
    }
}