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.

SCOM 2012 SP1 Installation Steps (Powershell)

Demo servers:

SCOM: scom01.demo.local
SQL+Reporting: sql01.demo.local
AD: ad01.demo.local

Accounts for SCOM:

demo\scom.aa – Action service account
demo\scom.dw – Data Writer
demo\scom.dr – Data Reader
demo\scom.das – Data Action Service Account

Prepare SQL Server:

SCOM requires at least SQL Server 2008 R2 (for SCOM 2012) and 2008 R2 SP1 (SCOM 2012 SP1)
Using a different version of SQL Server for different Operations Manager features is not supported
SQL Server collation settings for all databases must be one of the following: SQL_Latin1_General_CP1_CI_AS, French_CI_AS, Cyrillic_General_CI_AS, Chinese_PRC_CI_AS, Japanese_CI_AS, Traditional_Spanish_CI_AS, or Latin1_General_CI_AS. No other collation settings are supported

For SCOM Operational Database you must have:

Supported version of SQL Server
Installed Database Services with SQL Server Full Text Search feature!

For SCOM Reporting:

Supported version of SQL Server
Installed and configured Reporting Services

Important: if you planning SCOM Reporting component you MUST install one locally on SQL Server with Reporting services. Don’t try to install Reporting remotely to SQL instance. (honestly, I tried :)).  You will receive: NO SSRS Instances on SCOM MS Server.

I won’t show you how to install SQL Server. Just don’t forget to meet all requirements above.

Prepare SCOM server:

1) Install supported server OS (in my case, server 2012 Std)
2) Join to domain

Add-Computer -DomainName demo.local -Credential demo\demoadm
Restart-Computer

3) Update the server
4) Install required software (D is drive, where Server 2012 has mounted)

Install-WindowsFeature RSAT-AD-Powershell,Web-Asp-Net,Web-Asp-Net45,Net-Framework-Core,Web-Static-Content,Web-Default-Doc,Web-Dir-Browsing,Web-Http-Errors,Web-Http-Logging,Web-Request-Monitor,Web-Filtering,Web-Stat-Compression,Web-Metabase,Web-Windows-Auth,Web-CGI,Web-ISAPI-Ext,Web-ISAPI-Filter,Net-WCF-HTTP-Activation45 -Source D:\Sources\SxS
Set-Location C:\Windows\Microsoft.NET\Framework64\v4.0.30319
.\aspnet_regiis.exe -r

4) Open TCP ports 5723,5724,80,443 in firewall. Ports 5723,5724 are for Management Server , 80 and 443 are for Web Console.

New-NetFirewallRule -Name "SCOM MS" -DisplayName "SCOM MS" -Profile Domain -Direction Inbound -LocalPort 5723,5724 -Protocol TCP -Action Allow
New-NetFirewallRule -Name "SCOM WS" -DisplayName "SCOM WS" -Profile Domain -Direction Inbound -LocalPort 80,433 -Protocol TCP -Action Allow

5) Create required services accounts.

Basically, SCOM uses the management server action account (scom.aa) and System Center Data Access service account (scom.das). You can use one account for both services, but Microsoft recommends to use two separate accounts for the best security. If you install Reporting SCOM component , you are prompted for two additional accounts, the Data Warehouse Write account (scom.dww)  and the Data Reader account (scom.dr). Scom.aa and scom.das must be added to the local Administrators group on Management server and Operational Database. Scom.dww and scom.dr must have logon rights on SQL server where operational and reporting databases located.

$adcn=(Get-ADDomain).DistinguishedName
$ouname=read-host "Type OU where you want to create users:"
New-AdUser SCOMDataAccessAccount -SamAccountName scom.aa -AccountPassword (ConvertTo-SecureString -AsPlainText "Password1" -Force) -PasswordNeverExpires $true -Enabled $true -Path "CN=$ouname,$adcn"
New-AdUser SCOMDataAccess -SamAccountName scom.das -AccountPassword (ConvertTo-SecureString -AsPlainText "Password1" -Force) -PasswordNeverExpires $true -Enabled $true -Path "CN=$ouname,$adcn"
New-AdUser SCOMDataReader -SamAccountName scom.dr -AccountPassword (ConvertTo-SecureString -AsPlainText "Password1" -Force) -PasswordNeverExpires $true -Enabled $true -Path "CN=$ouname,$adcn"
New-AdUser SCOMDataWriteWareHouse -SamAccountName scom.dww -AccountPassword (ConvertTo-SecureString -AsPlainText "Password1" -Force) -PasswordNeverExpires $true -Enabled $true -Path "CN=$ouname,$adcn"
New-AdGroup -Name SCOMLocalAdm -GroupScope Global -GroupCategory Security
Add-AdGroupMember SCOMLocalAdm scom.aa,scom.das

6) I believe you already installed SQL Server instance and we are ready to add some changes for supporting communication between SCOM and SQL. The main goal my article to show you how we can use powershell and why it’s so cool. The first answer is we can do evertything without additional connections (RDP or something) to management servers.  Just create Powershell remote session and go!go!go! 🙂 .

7) Create firewall rules on SQL Server. Standart ports pack for SQL Server : 1433- database service, 1434 – sql browser, 4020 – sql broker. Additionally, we have to enable on WMI-WINMGMT-In-TCP rule. Then we add SCOMLocaladm group to Administrators group on SQL Server and create SQL logins for SCOM Data reader and SCOM Data Write accounts

$sqlsrv = read-host "Type FQDN of SQL Server:"
$cred = Read-Host "Define credential for connection fo SQL Server(Domain\user):"
$psrem = New-PSSession -ComputerName $sqlsrv -Credential $cred
Invoke-Command -Session $psrem -ScriptBlock{
Insall-WindowsFeature RSAT-AD-Powershell
$sqld=(Get-AdDomain).Name
Set-NetFirewallRule -Name WMI-WINMGMT-In-TCP -Enabled True
New-NetFirewallRule -Name "SQL Broker" -DisplayName "SQL Broker" -Profile Domain -Direction Inbound -LocalPort 4020 -Protocol TCP -Action Allow
New-NetFirewallRule -Name "SQL DB" -DisplayName "SQL Database" -Profile Domain -Direction Inbound -LocalPort 1433 -Protocol TCP -Action Allow
New-NetFirewallRule -Name "SQL Browser" -DisplayName "SQL Browser" -Profile Domain -Direction Inbound -LocalPort 1434 -Protocol TCP -Action Allow
net localgroup administrators $dname\SCOMLocalAdm /add
Invoke-SQLCmd -Query "CREATE LOGIN [$sqld\scom.dr] FROM WINDOWS"
Invoke-SQLCmd -Query "CREATE LOGIN [$sqld\scom.dww] FROM WINDOWS" }

Install SCOM MS,Web and Operations Consoles

Open wizard, next, next,type something, next,next,wait and blablabla . So boring…

Let’s use unattended installation!

setup.exe /silent /install
/components:OMServer,OMConsole,OMWebConsole
/ManagementGroupName: DemoManagementGroup
/SqlServerInstance: sql01\MSSQLSERVER
/DatabaseName: OperationalDatabase
/DWSqlServerInstance: sql01\MSSQLSERVER
/DWDatabaseName: SCOMDWDATABASE
/UseLocalSystemActionAccount /UseLocalSystemDASAccount
/DatareaderUser: demo\scom.dr
/DatareaderPassword: Password1
/DataWriterUser: demo\scom.dww
/DataWriterPassword: Password1
/AcceptEndUserLicenseAgreement
/WebSiteName: DefaultWebSite
/WebConsoleAuthorizationMode: Mixed
/SendODRReports: 0
/EnableErrorReporting: Never
/SendCEIPReports: 0
/UseMicrosoftUpdate: 1

Install SCOM Reporting

Before installation check your SSRS configuration (see my pictures)

ssrs_config_1
If you don’t database , click on “Change Database” and create new one
ssrs_config_2
Check Web Services URL and verify that it work from IE
ssrs_config_3
…and this URL

ssrs_config_4

To install Reporting use the following command:

setup.exe /silent /install /components:OMReporting

/ManagementServer: SCOM01.DEMO.LOCAL

/SRSInstance: SQL01\MSSQLSERVER

/DataReaderUser: demo\scom.dr

/DataReaderPassword: Password1

/SendODRReports:0

/UseMicrosoftUpdate: 1

After installation

If you use a domain account for scom data access service, you must register an SPN for each management server. Use the SETSPN command line tool.

setspn -a demo\scom01 demo\scom.das
setspn -a demo\scom01.demo.local demo\scom.das

P.S. Now you have got everything to create your first Powershell script. Go ahead! 🙂