Examples/PostInstallationConfiguration/PostInstallationConfiguration.ps1
<#
.EXAMPLE This example shows how to configure exchange after installation. This script shows examples of how to utilize most resources in the xExchange module. Where possible, configuration settings have been entered directly into this script. That was done for all settings which will be common for every server being configured. Settings which may be different, like for DAG's, CAS in different sites, or for individual servers, are defined in EndToEndExample-Config.psd1. #> $ConfigurationData = @{ AllNodes = @( @{ NodeName = '*' <# NOTE! THIS IS NOT RECOMMENDED IN PRODUCTION. This is added so that AppVeyor automatic tests can pass, otherwise the tests will fail on passwords being in plain text and not being encrypted. Because it is not possible to have a certificate in AppVeyor to encrypt the passwords we need to add the parameter 'PSDscAllowPlainTextPassword'. NOTE! THIS IS NOT RECOMMENDED IN PRODUCTION. See: http://blogs.msdn.com/b/powershell/archive/2014/01/31/want-to-secure-credentials-in-windows-powershell-desired-state-configuration.aspx #> PSDscAllowPlainTextPassword = $true <# The location of the exported public certifcate 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' } #Individual target nodes are defined next @{ NodeName = 'e15-1' Fqdn = 'e15-1.mikelab.local' Role = 'FirstDAGMember' DAGId = 'DAG1' #Used to determine which DAG settings the servers should use. Corresponds to DAG1 hashtable entry below. CASId = 'Site1CAS' #Used to determine which CAS settings the server should use. Corresponds to Site1CAS hashtable entry below. #DB's that should be on the same disk must be in the same string, and comma separated. In this example, DB1 and DB2 will go on one disk, and DB3 and DB4 will go on another DiskToDBMap = 'DB1,DB2','DB3,DB4' #Configure the databases whose primary copies will reside on this server PrimaryDBList = @{ DB1 = @{Name = 'DB1'; EdbFilePath = 'C:\ExchangeDatabases\DB1\DB1.db\DB1.edb'; LogFolderPath = 'C:\ExchangeDatabases\DB1\DB1.log'}; DB3 = @{Name = 'DB3'; EdbFilePath = 'C:\ExchangeDatabases\DB3\DB3.db\DB3.edb'; LogFolderPath = 'C:\ExchangeDatabases\DB3\DB3.log'} } #Configure the copies next. CopyDBList = @{ DB2 = @{Name = 'DB2'; ActivationPreference = 2; ReplayLagTime = '00:00:00'}; DB4 = @{Name = 'DB4'; ActivationPreference = 2; ReplayLagTime = '00:00:00'} } } @{ NodeName = 'e15-2' Fqdn = 'e15-2.mikelab.local' Role = 'AdditionalDAGMember' DAGId = 'DAG1' CASID = 'Site1CAS' DiskToDBMap = 'DB1,DB2','DB3,DB4' PrimaryDBList = @{ DB2 = @{Name = 'DB2'; EdbFilePath = 'C:\ExchangeDatabases\DB2\DB2.db\DB2.edb'; LogFolderPath = 'C:\ExchangeDatabases\DB2\DB2.log'}; DB4 = @{Name = 'DB4'; EdbFilePath = 'C:\ExchangeDatabases\DB4\DB4.db\DB4.edb'; LogFolderPath = 'C:\ExchangeDatabases\DB4\DB4.log'} } CopyDBList = @{ DB1 = @{Name = 'DB1'; ActivationPreference = 2; ReplayLagTime = '00:00:00'}; DB3 = @{Name = 'DB3'; ActivationPreference = 2; ReplayLagTime = '00:00:00'} } } ); #Settings that are unique per DAG will go in separate hash table entries. DAG1 = @( @{ ###DAG Settings### DAGName = 'TestDAG1' AutoDagTotalNumberOfServers = 4 AutoDagDatabaseCopiesPerVolume = 2 DatabaseAvailabilityGroupIPAddresses = '192.168.1.99','192.168.2.99' ManualDagNetworkConfiguration = $true ReplayLagManagerEnabled = $true SkipDagValidation = $true WitnessServer = 'e14-1.mikelab.local' #xDatabaseAvailabilityGroupNetwork params #New network params DAGNet1NetworkName = 'MapiNetwork' DAGNet1ReplicationEnabled = $false DAGNet1Subnets = '192.168.1.0/24','192.168.2.0/24' DAGNet2NetworkName = 'ReplNetwork' DAGNet2ReplicationEnabled = $true DAGNet2Subnets = '10.10.10.0/24','10.10.11.0/24' #Old network to remove OldNetworkName = 'MapiDagNetwork' #Certificate Settings Thumbprint = '7D959B3A37E45978445F8EC8F01D200D00C3141F' CertFilePath = 'c:\certexport1.pfx' Services = 'IIS','POP','IMAP','SMTP' } ); #CAS settings that are unique per site will go in separate hash table entries as well. Site1CAS = @( @{ InternalNLBFqdn = 'mail-site1.mikelab.local' ExternalNLBFqdn = 'mail.mikelab.local' #ClientAccessServer Settings AutoDiscoverSiteScope = 'Site1' #OAB Settings OABsToDistribute = 'Default Offline Address Book - Site1' #OWA Settings InstantMessagingServerName = 'lync-site1.mikelab.local' } ); Site2CAS = @( @{ InternalNLBFqdn = 'mail-site2.mikelab.local' ExternalNLBFqdn = 'mail.mikelab.local' #ClientAccessServer Settings AutoDiscoverSiteScope = 'Site2' #OAB Settings OABsToDistribute = 'Default Offline Address Book - Site2' #OWA Settings InstantMessagingServerName = 'lync-site2.mikelab.local' } ); } Configuration Example { param ( [Parameter(Mandatory = $true)] [ValidateNotNullorEmpty()] [System.Management.Automation.PSCredential] $ExchangeAdminCredential, [Parameter(Mandatory = $true)] [ValidateNotNullorEmpty()] [System.Management.Automation.PSCredential] $ExchangeCertCredential ) Import-DscResource -Module xExchange #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 = $dagSettings.ManualDagNetworkConfiguration ReplayLagManagerEnabled = $dagSettings.ReplayLagManagerEnabled SkipDagValidation = $true WitnessDirectory = 'C:\FSW' WitnessServer = $dagSettings.WitnessServer } #Add this server as member xExchDatabaseAvailabilityGroupMember DAGMember { MailboxServer = $Node.NodeName Credential = $ExchangeAdminCredential DAGName = $dagSettings.DAGName SkipDagValidation = $true DependsOn = '[xExchDatabaseAvailabilityGroup]DAG' } #Create two new DAG Networks xExchDatabaseAvailabilityGroupNetwork DAGNet1 { Name = $dagSettings.DAGNet1NetworkName Credential = $ExchangeAdminCredential DatabaseAvailabilityGroup = $dagSettings.DAGName Ensure = 'Present' ReplicationEnabled = $dagSettings.DAGNet1ReplicationEnabled Subnets = $dagSettings.DAGNet1Subnets DependsOn = '[xExchDatabaseAvailabilityGroupMember]DAGMember' #Can't do work on DAG networks until at least one member is in the DAG... } xExchDatabaseAvailabilityGroupNetwork DAGNet2 { Name = $dagSettings.DAGNet2NetworkName Credential = $ExchangeAdminCredential DatabaseAvailabilityGroup = $dagSettings.DAGName Ensure = 'Present' ReplicationEnabled = $dagSettings.DAGNet2ReplicationEnabled Subnets = $dagSettings.DAGNet2Subnets DependsOn = '[xExchDatabaseAvailabilityGroupMember]DAGMember' #Can't do work on DAG networks until at least one member is in the DAG... } #Remove the original DAG Network xExchDatabaseAvailabilityGroupNetwork DAGNetOld { Name = $dagSettings.OldNetworkName Credential = $ExchangeAdminCredential DatabaseAvailabilityGroup = $dagSettings.DAGName Ensure = 'Absent' DependsOn = '[xExchDatabaseAvailabilityGroupNetwork]DAGNet1','[xExchDatabaseAvailabilityGroupNetwork]DAGNet2' #Dont remove the old one until the new one is in place } } #Next we'll add the remaining nodes to the DAG Node $AllNodes.Where{$_.Role -eq 'AdditionalDAGMember'}.NodeName { $dagSettings = $ConfigurationData[$Node.DAGId] #Look up and retrieve the DAG settings for this node #Can't join until the DAG exists... xExchWaitForDAG WaitForDAG { Identity = $dagSettings.DAGName Credential = $ExchangeAdminCredential } xExchDatabaseAvailabilityGroupMember DAGMember { MailboxServer = $Node.NodeName Credential = $ExchangeAdminCredential DAGName = $dagSettings.DAGName SkipDagValidation = $true DependsOn = '[xExchWaitForDAG]WaitForDAG' } } #This section will handle configuring all non-DAG specific settings, including CAS and MBX settings. Node $AllNodes.NodeName { $dagSettings = $ConfigurationData[$Node.DAGId] #Look up and retrieve the DAG settings for this node $casSettings = $ConfigurationData[$Node.CASId] #Look up and retrieve the CAS settings for this node #Thumbprint of the certificate used to decrypt credentials on the target node LocalConfigurationManager { CertificateId = $Node.Thumbprint } ###General server settings### #This section licenses the server xExchExchangeServer EXServer { Identity = $Node.NodeName Credential = $ExchangeAdminCredential ProductKey = '12345-12345-12345-12345-12345' AllowServiceRestart = $true } #This imports a certificate .PFX that had been previously exported, and enabled services on it xExchExchangeCertificate Certificate { Thumbprint = $dagSettings.Thumbprint Credential = $ExchangeAdminCredential Ensure = 'Present' AllowExtraServices = $false CertCreds = $ExchangeCertCredential CertFilePath = $dagSettings.CertFilePath Services = $dagSettings.Services } ###CAS specific settings### xExchClientAccessServer CAS { Identity = $Node.NodeName Credential = $ExchangeAdminCredential AutoDiscoverServiceInternalUri = "https://$($casSettings.InternalNLBFqdn)/autodiscover/autodiscover.xml" AutoDiscoverSiteScope = $casSettings.AutoDiscoverSiteScope } #Install features that are required for xExchActiveSyncVirtualDirectory to do Auto Certification Based Authentication WindowsFeature WebClientAuth { Name = 'Web-Client-Auth' Ensure = 'Present' } WindowsFeature WebCertAuth { Name = 'Web-Cert-Auth' Ensure = 'Present' } #This example shows how to enable Certificate Based Authentication for ActiveSync xExchActiveSyncVirtualDirectory ASVdir { Identity = "$($Node.NodeName)\Microsoft-Server-ActiveSync (Default Web Site)" Credential = $ExchangeAdminCredential AutoCertBasedAuth = $true AutoCertBasedAuthThumbprint = $dagSettings.Thumbprint BasicAuthEnabled = $false ClientCertAuth = 'Required' ExternalUrl = "https://$($casSettings.ExternalNLBFqdn)/Microsoft-Server-ActiveSync" InternalUrl = "https://$($casSettings.InternalNLBFqdn)/Microsoft-Server-ActiveSync" WindowsAuthEnabled = $false AllowServiceRestart = $true DependsOn = '[WindowsFeature]WebClientAuth','[WindowsFeature]WebCertAuth','[xExchExchangeCertificate]Certificate' #Can't configure CBA until we have a valid cert, and have required features } #Ensures forms based auth and configures URLs xExchEcpVirtualDirectory ECPVDir { Identity = "$($Node.NodeName)\ecp (Default Web Site)" Credential = $ExchangeAdminCredential BasicAuthentication = $true ExternalAuthenticationMethods = 'Fba' ExternalUrl = "https://$($casSettings.ExternalNLBFqdn)/ecp" FormsAuthentication = $true InternalUrl = "https://$($casSettings.InternalNLBFqdn)/ecp" WindowsAuthentication = $false AllowServiceRestart = $true } #Configure URL's and for NTLM and negotiate auth xExchMapiVirtualDirectory MAPIVdir { Identity = "$($Node.NodeName)\mapi (Default Web Site)" Credential = $ExchangeAdminCredential ExternalUrl = "https://$($casSettings.ExternalNLBFqdn)/mapi" IISAuthenticationMethods = 'NTLM','Negotiate' InternalUrl = "https://$($casSettings.InternalNLBFqdn)/mapi" AllowServiceRestart = $true } #Configure URL's and add any OABs this vdir should distribute xExchOabVirtualDirectory OABVdir { Identity = "$($Node.NodeName)\OAB (Default Web Site)" Credential = $ExchangeAdminCredential ExternalUrl = "https://$($casSettings.ExternalNLBFqdn)/oab" InternalUrl = "https://$($casSettings.InternalNLBFqdn)/oab" OABsToDistribute = $casSettings.OABsToDistribute AllowServiceRestart = $true } #Configure URL's and auth settings xExchOutlookAnywhere OAVdir { Identity = "$($Node.NodeName)\Rpc (Default Web Site)" Credential = $ExchangeAdminCredential ExternalClientAuthenticationMethod = 'Ntlm' ExternalClientsRequireSSL = $true ExternalHostName = $casSettings.ExternalNLBFqdn IISAuthenticationMethods = 'Ntlm' InternalClientAuthenticationMethod = 'Ntlm' InternalClientsRequireSSL = $true InternalHostName = $casSettings.InternalNLBFqdn AllowServiceRestart = $true } #Ensures forms based auth and configures URLs and IM integration xExchOwaVirtualDirectory OWAVdir { Identity = "$($Node.NodeName)\owa (Default Web Site)" Credential = $ExchangeAdminCredential BasicAuthentication = $true ExternalAuthenticationMethods = 'Fba' ExternalUrl = "https://$($casSettings.ExternalNLBFqdn)/owa" FormsAuthentication = $true InstantMessagingEnabled = $true InstantMessagingCertificateThumbprint = $dagSettings.Thumbprint InstantMessagingServerName = $casSettings.InstantMessagingServerName InstantMessagingType = 'Ocs' InternalUrl = "https://$($casSettings.InternalNLBFqdn)/owa" WindowsAuthentication = $false AllowServiceRestart = $true DependsOn = '[xExchExchangeCertificate]Certificate' #Can't configure the IM cert until it's valid } #Turn on Windows Integrated auth for remote powershell connections xExchPowerShellVirtualDirectory PSVdir { Identity = "$($Node.NodeName)\PowerShell (Default Web Site)" Credential = $ExchangeAdminCredential WindowsAuthentication = $true AllowServiceRestart = $true } #Configure URL's xExchWebServicesVirtualDirectory EWSVdir { Identity = "$($Node.NodeName)\EWS (Default Web Site)" Credential = $ExchangeAdminCredential ExternalUrl = "https://$($casSettings.ExternalNLBFqdn)/ews/exchange.asmx" InternalUrl = "https://$($casSettings.InternalNLBFqdn)/ews/exchange.asmx" AllowServiceRestart = $true } ###Transport specific settings### #Create a custom receive connector which could be used to receive SMTP mail from internal non-Exchange mail servers xExchReceiveConnector CustomConnector1 { Identity = "$($Node.NodeName)\Internal SMTP Servers to $($Node.NodeName)" Credential = $ExchangeAdminCredential Ensure = 'Present' AuthMechanism = 'Tls','ExternalAuthoritative' Bindings = '0.0.0.0:25' MaxMessageSize = '25MB' PermissionGroups = 'AnonymousUsers','ExchangeServers' RemoteIPRanges = '192.168.1.101','192.168.1.102' TransportRole = 'FrontendTransport' Usage = 'Custom' } #Ensures that Exchange built in AntiMalware Scanning is enabled or disabled xExchAntiMalwareScanning AMS { Enabled = $true Credential = $ExchangeAdminCredential } ###Mailbox Server settings### #Create database and volume mount points for AutoReseed xExchAutoMountPoint AMP { Identity = $Node.NodeName AutoDagDatabasesRootFolderPath = 'C:\ExchangeDatabases' AutoDagVolumesRootFolderPath = 'C:\ExchangeVolumes' DiskToDBMap = $Node.DiskToDBMap SpareVolumeCount = 1 VolumePrefix = 'EXVOL' } #Create primary databases foreach ($DB in $Node.PrimaryDBList.Values) { $resourceId = "MDB_$($DB.Name)" #Need to define a unique ID for each database xExchMailboxDatabase $resourceId { Name = $DB.Name Credential = $ExchangeAdminCredential EdbFilePath = $DB.EdbFilePath LogFolderPath = $DB.LogFolderPath Server = $Node.NodeName CircularLoggingEnabled = $true DatabaseCopyCount = 4 DeletedItemRetention = '7.00:00:00' IssueWarningQuota = '5120MB' ProhibitSendQuota = '5300MB' ProhibitSendReceiveQuota = '5500MB' AllowServiceRestart = $true DependsOn = '[xExchAutoMountPoint]AMP' #Can"t create databases until the mount points exist } } #Create the copies foreach ($DB in $Node.CopyDBList.Values) { $waitResourceId = "WaitForDB_$($DB.Name)" #Unique ID for the xWaitForMailboxDatabase resource $copyResourceId = "MDBCopy_$($DB.Name)" #Unique ID for the xMailboxDatabaseCopy resource #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 AllowServiceRestart = $true DependsOn = "[xExchWaitForMailboxDatabase]$($waitResourceId)" } } } } |