Automating Exchange 2016 installation with Desired State Configuration

Hi, folks!

There is a good example of Exchange installation inside of help files for xExchange module but it’s actually not valid for Exchange 2016:

  • no installation for server roles and features = configuration fails
  • Exchange 2016 does not have separate client access role anymore = wrong installation parameters and setup fails
  • UCMA is required to be installed = errors during prerequisite check up
  • not optimal LCM parameters
  • no certificate management
  • there is no variables passing via command line = not suitable for unattended setup

So here is the fixed version of one .

/Has been tested on VM with up-to-date domain joined 2012 R2 guest machine.

//If you are not yet familiar with PowerShell DSC it’s recommended to review some facts before setting up and then do some additional steps:

0) Step for lazy persons Улыбка . Download link for  all-in-one zip file

1) Install the following update (only for PowerShell v3 and v4.0) :

PackageManagement PowerShell Modules Preview – March 2016

2) Import or verify that the required modules are available :

  • xExchange . It’s  a custom module for installation and configuration Exchange environment (installation, DAG, settings and more)
  • WindowsFeature . Built-in DSC resource that ensures and installs windows server roles/features
  • Package . Built-in DSC resource to install program packages (msi,exe and etc)
  • xPendingReboot. Custom module that reboots system if it is in the “pending reboot” status.
  • To list installed custom DSC resources:
    Get-DscResource|? {$_.ModuleName -NotMatch "PSDesired"}
    
  • To install custom DSC (internet connectivity is required):
    Install-Module xExchange
    
  • I prefer to save module for the further usage and then install or just copy to one of the PS module’s path
    #save module to pre-created folder
    
    Save-Module xExchange -Path C:\DSC\Modules
    
    #Copy module to the one of the following folders (../Program Files/.. is recommended)
    
    $env:PSModulePath
    
    C:\Users\username\Documents\WindowsPowerShell\Modules;
    C:\Program Files\WindowsPowerShell\Modules;
    C:\Windows\system32\WindowsPowerShell\v1.0\Modules
    

3) Prepare folders. Script uses the following paths:

  • “C:\Exch”  – Exchange binaries,
  • “C:\ExchInstall\Cert” – required files for import certificate
  • “C:\UCMA” – UCMA installation files

4) Download Exchange media and copy setup files (C:\Exch in my case)

5) Extract UCMA package  to another folder (script uses C:\UCMA)

6) (optional) Prepare certificate for securing MOF files. I use this module  to create one and then export PFX and CER-files to “C:\ExchInstall\Cert”.

Note: If you don’t want to secure your MOF files you can comment out related strings in the main script (step 6, see comment blocks)

. .\New-SelfSignedCertificateEx.ps1
New-SelfsignedCertificateEx `
    -Subject 'CN=localhost' `
    -EKU 'Document Encryption' `
    -KeyUsage 'KeyEncipherment, DataEncipherment' `
    -SAN localhost `
    -FriendlyName 'DSC certificate' `
    -Exportable `
    -StoreLocation 'LocalMachine' `
    -StoreName 'My' `
    -KeyLength 2048 `
    -ProviderName 'Microsoft Enhanced Cryptographic Provider v1.0' `
    -AlgorithmName 'RSA' `
    -SignatureAlgorithm 'SHA256'

6) Create the new script (ps1) which contains the following strings

Note: RebootNodeIfNeeded has been set to “True” so LCM have rights to reboot your machine automatically.

 <#
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |w|w|w|.|r|l|e|v|c|h|e|n|k|o|.|c|o|m|
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                                                                                                    

::Exchange 2016 Installation (DSC)
::Required modules: xExchange and xPendingReboot

 #>

#Variables
    param ()
      #Domain and Netbios Names
      $domainname=$args[0] #or get-domain if domain is existed.
      $netbios=$DomainName.split(“.”)[0]

	  #Creds for Exchange install acoount
	  $pwd = ConvertTo-SecureString "Pass123" -AsPlainText -Force
      $Creds = New-Object System.Management.Automation.PSCredential ("$netbios\Administrator", $pwd)

      #Import the certificate for securing MOF (optional. related strings can be just commented out)
      $CertPW=ConvertTo-SecureString “Pass123” -AsPlainText -Force
      Import-PfxCertificate -Password $certpw -CertStoreLocation Cert:\LocalMachine\My -FilePath C:\ExchInstall\cert\publickey.pfx

#DSC starts here
Configuration InstallExchange

{
        Import-DscResource -Module xExchange
        Import-DscResource -Module xPendingReboot

    Node $AllNodes.NodeName
    {
        #Sets certificate for LCM on every node
        LocalConfigurationManager
        {
            CertificateId      = $AllNodes.Thumbprint
            RebootNodeIfNeeded = $true
            ConfigurationMode = 'ApplyOnly'
        }

        #Installs Required Components for Exchange (note: there is 1 planned automatic reboot)
        WindowsFeature ASHTTP
        {
            Ensure = 'Present'
            Name = 'AS-HTTP-Activation'
        }
        WindowsFeature DesktopExp
        {
            Ensure = 'Present'
            Name = 'Desktop-Experience'
        }
         WindowsFeature NetFW45
        {
            Ensure = 'Present'
            Name = 'NET-Framework-45-Features'
        }
           WindowsFeature RPCProxy
        {
            Ensure = 'Present'
            Name = 'RPC-over-HTTP-proxy'
        }
            WindowsFeature RSATClus
        {
            Ensure = 'Present'
            Name = 'RSAT-Clustering'
        }
            WindowsFeature RSATClusCmd
        {
            Ensure = 'Present'
            Name = 'RSAT-Clustering-CmdInterface'
        }
            WindowsFeature RSATClusMgmt
        {
            Ensure = 'Present'
            Name = 'RSAT-Clustering-Mgmt'
        }
           WindowsFeature RSATClusPS
        {
            Ensure = 'Present'
            Name = 'RSAT-Clustering-PowerShell'
        }
           WindowsFeature WebConsole
        {
            Ensure = 'Present'
            Name = 'Web-Mgmt-Console'
        }
            WindowsFeature WAS
        {
            Ensure = 'Present'
            Name = 'WAS-Process-Model'
        }
            WindowsFeature WebAsp
        {
            Ensure = 'Present'
            Name = 'Web-Asp-Net45'
        }
           WindowsFeature WBA
        {
            Ensure = 'Present'
            Name = 'Web-Basic-Auth'
        }
           WindowsFeature WCA
        {
            Ensure = 'Present'
            Name = 'Web-Client-Auth'
        }
          WindowsFeature WDA
        {
            Ensure = 'Present'
            Name = 'Web-Digest-Auth'
        }
          WindowsFeature WDB
        {
            Ensure = 'Present'
            Name = 'Web-Dir-Browsing'
        }
           WindowsFeature WDC
        {
            Ensure = 'Present'
            Name = 'Web-Dyn-Compression'
        }
           WindowsFeature WebHttp
        {
            Ensure = 'Present'
            Name = 'Web-Http-Errors'
        }
           WindowsFeature WebHttpLog
        {
            Ensure = 'Present'
            Name = 'Web-Http-Logging'
        }
           WindowsFeature WebHttpRed
        {
            Ensure = 'Present'
            Name = 'Web-Http-Redirect'
        }
          WindowsFeature WebHttpTrac
        {
            Ensure = 'Present'
            Name = 'Web-Http-Tracing'
        }
          WindowsFeature WebISAPI
        {
            Ensure = 'Present'
            Name = 'Web-ISAPI-Ext'
        }
          WindowsFeature WebISAPIFilt
        {
            Ensure = 'Present'
            Name = 'Web-ISAPI-Filter'
        }
            WindowsFeature WebLgcyMgmt
        {
            Ensure = 'Present'
            Name = 'Web-Lgcy-Mgmt-Console'
        }
            WindowsFeature WebMetaDB
        {
            Ensure = 'Present'
            Name = 'Web-Metabase'
        }
            WindowsFeature WebMgmtSvc
        {
            Ensure = 'Present'
            Name = 'Web-Mgmt-Service'
        }
           WindowsFeature WebNet45
        {
            Ensure = 'Present'
            Name = 'Web-Net-Ext45'
        }
            WindowsFeature WebReq
        {
            Ensure = 'Present'
            Name = 'Web-Request-Monitor'
        }
             WindowsFeature WebSrv
        {
            Ensure = 'Present'
            Name = 'Web-Server'
        }
              WindowsFeature WebStat
        {
            Ensure = 'Present'
            Name = 'Web-Stat-Compression'
        }
               WindowsFeature WebStatCont
        {
            Ensure = 'Present'
            Name = 'Web-Static-Content'
        }
               WindowsFeature WebWindAuth
        {
            Ensure = 'Present'
            Name = 'Web-Windows-Auth'
        }
              WindowsFeature WebWMI
        {
            Ensure = 'Present'
            Name = 'Web-WMI'
        }
              WindowsFeature WebIF
        {
            Ensure = 'Present'
            Name = 'Windows-Identity-Foundation'
        }
              WindowsFeature RSATADDS
        {
            Ensure = 'Present'
            Name = 'RSAT-ADDS'
        }
        #Installs UCMA. Don't forget to change path it if it is required
        Package UCMA
        {
            Ensure= 'Present'
            Name = 'Microsoft Unified Communications Managed API 4.0, Core
                    Runtime 64-bit'
            Path= 'c:\UCMA\UcmaRuntimeSetup\ironmansetup.exe'
            ProductID= 'ED98ABF5-B6BF-47ED-92AB-1CDCAB964447'
            Arguments= '/q'

         }

        #Checks Exchange Setup Directory (can be changed it's necessary). No recurse.
        File ExchangeBinaries
        {
            Ensure          = 'Present'
            Type            = 'Directory'
            Recurse         = $false
            SourcePath = 'C:\Exch'
            DestinationPath = 'C:\Exch'
        }

        #Checks if a reboot is needed before installing Exchange
        xPendingReboot BeforeExchangeInstall
        {
            Name      = "BeforeExchangeInstall"

            DependsOn  = '[File]ExchangeBinaries'
        }

        #Does the Exchange install. Verify directory with exchange binaries
        xExchInstall InstallExchange
        {
            Path       = "C:\Exch\Setup.exe"
            Arguments  = "/mode:Install /role:Mailbox /OrganizationName:""$netbios"" /Iacceptexchangeserverlicenseterms"
            Credential = $Creds

            DependsOn  = '[xPendingReboot]BeforeExchangeInstall'
        }

        #Sees if a reboot is required after installing Exchange
        xPendingReboot AfterExchangeInstall
        {
            Name      = "AfterExchangeInstall"

            DependsOn = '[xExchInstall]InstallExchange'
        }
   }
}

#DSC Configuration data
$ConfigData=@{
    AllNodes = @(

        @{
            NodeName = "*"
				  #Replace thumbprint with yours or use precreated cert
                  CertificateFile = "C:\ExchInstall\cert\publickey.cer"
                  Thumbprint = "FF0693E72BD283298323DF34B2A848F0F1B48E67"
                  PSDscAllowPlainTextPassword = $true
        }

        @{
            NodeName = "localhost"
        }
    );
}

if ($Creds -eq $null)
{
   #if creds are empty -> write to log Application/mozno udalit')
   New-EventLog –LogName Application –Source “Exchange Installation”
   Write-EventLog –LogName Application –Source “Exchange Installation” –EntryType Error –EventID 1 –Message “Credentials are empty”

}

#Compiles the example
InstallExchange -ConfigurationData $ConfigData -Creds $Creds

#Sets up LCM on target computers to decrypt credentials, and to allow reboot during resource execution
Set-DscLocalConfigurationManager -Path .\InstallExchange -Verbose

#Pushes configuration and waits for execution
Start-DscConfiguration -Path .\InstallExchange -Verbose -Wait

7) Run the script with the mandatory <domainname> parameter

Example: 

.\InstallExchange.ps1 contoso.com

8) Wait while LCM applies DSC configuration.

To retrieve the the current status use:

Get-DSCLocalConfigurationManager

and

  • read logs (Applications and Services Logs – Microsoft – Windows – Desired State Configuration)
  • Exchange creates it’s own setup logs on your system drive . check them in case of unexpected errors.

Until then,

have a nice weekend!

P.S. I have updated this script with DAG configuration and etc.. I’ll publish a new post later. Be in touch.

How to make VMM highly available

Virtual Machine Manager is the core component of a medium- or large-sized virtualization platform. If you have a lot of hosts and virtual instances , private/hybrid clouds or network virtualization, having highly available VMM is strongly recommended. In this post we will discuss how satisfy all requirements for VMM High availability and set up 2 VMM HA instances.

Hardware and settings behind this post

  • 1 Hyper-V host (TP5, CU2)
  • 1 DC (domainlab.com, guest)
  • 2 VMM (VMM01, VMM 02 , guest)
  • 1 SQL Server (SQL01, guest)
  • internal vSwitches
  • all guests and hosts are up-to-date (Windows Update, no exotic  KBs)
  • user for setup: domain/ent administrator

Prepare your environment for VMM HA

1) VMM creates database to keep it’s configuration data, so remote SQL Server instance with Standard edition at least is required.

TIP:  to remove single point of failure I’d recommend to set up SQL Server HA. AlwaysOn FCI and AG are supported.

2) open 445 and 1433 ports on one or more SQL Servers (if your SQL is in HA)

For Windows Firewall (please note I use Domain Profile here):

New-NetFirewallRule -Name "SQL Server 445" -DisplayName "SQL Server 445" -Profile Domain -Direction Inbound -LocalPort 445 -Protocol TCP -Action Allow
New-NetFirewallRule -Name "SQL Server 1433" -DisplayName "SQL Server 1433" -Profile Domain -Direction Inbound -LocalPort 1433 -Protocol TCP -Action Allow

3) create service account for VMM Service and add one to the local Administrator group on each VMM host

#Use Powershell or dsa.msc
New-ADUser -Name "VMM Service Account" -GivenName "VMM SVC" -SamAccountName vmmsvc -UserPrincipalName vmmsvc@demolab.com -AccountPassword (Read-Host -AsSecureString "Type Password For Service Account")
#Use PS/CMD or lusrmgr.msc
ICM -ComputerName vmmservername {net localgroup administrators /add Demolab\VMMSVC}

4) as almost any clustered role in Windows Server, VMM HA is built on the top of the the well-known Failover-Clustering feature and some requirements are similar.

#Install Failover-Clustering feature on every VMM host
Install-WindowsFeature Failover-Clustering -IncludeManagementTools

TIP: it’s also recommended to add and prepare separate network for cluster heartbeats

5) Create a new cluster (cluadmins.msc or PS)

New-Cluster -Name VMMCL -Node VMM01, VMM02 -StaticAdress 192.168.10.40 -NoStorage -AdministrativeAccessPoint ActiveDirectoryAndDns -IgnoreNetwork 10.10.23.0/24

newclustervmm

6) Check that newly created cluster operates without any errors (cluadmins.msc/cluster core resources and cluster events)

image

7) VMM encrypts some data in the VMM database by using the Data Protection Application Programming Interface (DPAPI). For example, VMM encrypts Run As account credentials and passwords in guest operating system profiles. VMM also encrypts product key information in virtual hard disk properties for virtual machine role scenarios and configuration.

If you move VMM to another station, VMM will not retain the encrypted data. To be able to operate in HA mode, VMM requires Distributed Key Management which stores encryption data in AD DS.

To get it work you need to define the new container in ADDS (adsiedit.msc or PS)

TIP: The account with which you are installing VMM must have Full Control permissions to the VMMDKM container (use adsiedit.msc and security tab)

TIP: you need to create the container in the same domain as the user account with which you are installing VMM

#Get domain's distinguished name (example, "DC=contoso, DC=com")
$DN=(Get-AdDomain).DistinguishedName

#VMMDK container will be created at the root of domain context
New-ADObject -Name "VMMDKM" -Type Container -Path ($DN)

8) Download and install Windows ADK 8.1 with only Deployment Tools and Windows PE features on each VMM host

TIP:  you can download ADK files to a file share and use shared path to install ADK on the next VMM hosts. Timesaver.

adk81

VMM Installation

After you created a new cluster and added all of your VMM hosts to one, you are ready to run setup.exe from VMM media.

The steps are the same as for standalone installation. But there are some differences :

  • you cannot define library servers at the library configuration page. you must add them after setup from VMM console (HA File Server is recommended)
  • wizard automatically determinates (checks cluster membership) that you are going to create VMM HA (1st picture)
  • you need to define settings for VMM cluster role (name and IP address)
  • no option to store encryption keys on the local machine. DKM is selected by default.

Then you need to define

  • name, organization, product key
  • Windows Update settings (on/off)
  • SQL Connections settins (Name, Credentials and etc.)
  • Service account (vmmsvc , in my case) and password
  • DKM path (CN=VMMDKM, DC=demolab, DC=com)
  • cluster name (VMMHA) and it’s ip address

Repeat steps on each VMM host.

Download the latest UR (UR 10 for today) and install it then.

This slideshow requires JavaScript.

Open cluadmins.msc , go to Roles and verify that clustered role with the name VMMHA was created.

image

TIP: owner mode shows you current active VMM server for income connections. VMM HA uses active-passive model.

You can retrieve the active node from VMM console as well. Use FQDN of newly created cluster and default 8100 port as for connection string and check Fabric –Infrastructure – VMM Server section

TIP: it’s recommended to install VMM console on the remote station which is not a member of VMM HA cluster

image

Additional considerations

  • You can only have one implementation of a highly available VMM management server on a given failover cluster.
  • You can have VMM management servers installed on as many as sixteen nodes on a failover cluster, but there can only be one node active at any time.
  • You cannot perform a planned failover (for example, to install a security update or to do maintenance on a node of the cluster) by using the VMM console. To perform a planned failover, use Failover Cluster Manager.
  • During a planned failover, ensure that there are no tasks actively running on the VMM management server. Any running tasks will fail during a failover. Any failed jobs will not start automatically after a failover.
  • Any connections to a highly available VMM management server from the VMM console or the VMM Self-Service Portal (unavailable for new VMM versions (2012 SP1 and later)) will be lost during a failover. The VMM console will be able to reconnect automatically to the highly available VMM management server after a failover.

Thanks for reading.

Have a nice datacenter management!

P.S. don’t know how to upgrade old VMM even if it is installed on 2008 R2? Check my post.