ADLAB PowerShell source file: buildup-scom.ps1

(C) Ondrej Sevecek, 2019 - www.sevecek.com, ondrej@sevecek.com



#$global:outClass = 'main'

$libDir = Split-Path -parent $MyInvocation.MyCommand.Definition
& "$libDir\lib-common.ps1" -defaultConfig -rootDir $libDir -outFile scomLib
& "$libDir\lib-modifyActions.ps1"
& "$libDir\lib-buildup.ps1"
& "$libDir\lib-scom.ps1"

$vmName = $args[0]

DBG ("SCOM Installation library.")
Redirect-TempToOutput
Load-VMConfig

Find-MarkedVolumes
$global:installSourceMediaSC = '!sevecek-installation-source-media-SystemCenter.txt'
$global:installMediaVolumeSC = Find-MarkedVolume $global:installSourceMediaSC 3
DBG ('SystemCenter install media volume: {0}' -f $installMediaVolumeSC)

$appTag = 'scom'
$appConfig = $vmConfig.$appTag
$firstAppHost = Get-FirstAppHostInInstance $appTag $appConfig.instance 'waitParams'
$firstAppHostInInstance = Check-FirstAppHostInInstance $appTag $appConfig.instance


#====================
#====================


#====================
DBG ('Installing SCOM: {0}' -f $vmConfig.scom.instance)

$instRoot = Get-FirstPathFromWildcard (Join-Path $installMediaVolumeSC 'SCOM2012-R2')
$prereqRoot = Get-FirstPathFromWildcard (Join-Path $installMediaVolumeSC 'SCOM2012-R2-Prereq')
$customRoot = Join-Path $global:rootDir 'SCOM2012R2'


#================
DBG ('Install SCOM prerequisites')
Run-Process 'msiexec' ('-i "{0}" ALLUSERS=1 -qb' -f (Join-Path $prereqRoot 'SQLSysClrTypes2012.msi'))
Run-Process 'msiexec' ('-i "{0}" ALLUSERS=1 -qb' -f (Join-Path $prereqRoot 'ReportViewer2012Runtime.msi'))


#================

$roles = $appConfig.roles
$mgmtGroup = $appConfig.mgmtGroup

$dbInstance = $appConfig.sql.instance
$dbServerFQDN = Get-FirstAppHostInInstance 'sql' $dbInstance 'fqdn'
$sqlInstance = '{0}\{1}' -f $dbServerFQDN, $dbInstance

$scomOperationDB = $appConfig.opDB -replace '\W', '_'
$scomDataWarehouseDB = $appConfig.dwDB -replace '\W', '_'

$svcAccElement = $appConfig.SelectSingleNode('./svc[@appTag="action"]')
$actionAcc = Get-SAMLogin $svcAccElement.login $svcAccElement.domain
$actionAccPwd = $svcAccElement.pwd

$svcAccElement = $appConfig.SelectSingleNode('./svc[@appTag="das"]')
$dasAcc = Get-SAMLogin $svcAccElement.login $svcAccElement.domain
$dasAccPwd = $svcAccElement.pwd

$svcAccElement = $appConfig.SelectSingleNode('./svc[@appTag="dbreader"]')
$dataReaderAcc = Get-SAMLogin $svcAccElement.login $svcAccElement.domain
$dataReaderAccPwd = $svcAccElement.pwd     

$svcAccElement = $appConfig.SelectSingleNode('./svc[@appTag="dbwriter"]')
$dataWriterAcc = Get-SAMLogin $svcAccElement.login $svcAccElement.domain
$dataWriterAccPwd = $svcAccElement.pwd

$installationParameters = '/Silent /Install /Components:{0} /ManagementGroupName:{1} /SqlServerInstance:{2} /DatabaseName:{3} /DWSqlServerInstance:{2} /DWDatabaseName:{4} /ActionAccountUser:{5} /ActionAccountPassword:{6} /DASAccountUser:{7} /DASAccountPassword:{8} /DataReaderUser:{9} /DataReaderPassword:{10} /DataWriterUser:{11} /DataWriterPassword:{12} /EnableErrorReporting:Never /SendCEIPReports:0 /SendODRReports:0 /UseMicrosoftUpdate:0 /AcceptEndUserLicenseAgreement:1' -f $roles, $mgmtGroup, $sqlInstance, $scomOperationDB, $scomDataWarehouseDB, $actionAcc, $actionAccPwd, $dasAcc, $dasAccPwd, $dataReaderAcc, $dataReaderAccPwd, $dataWriterAcc, $dataWriterAccPwd
DBG ('Installation parameters: {0}' -f $installationParameters)


DBG ('Install SCOM server: {0}' -f (-not (Parse-BoolSafe $appConfig.doNotInstall)))
if (-not (Parse-BoolSafe $appConfig.doNotInstall)) {

  DBG ('Must wait for the DB server to complete first')
  Wait-Machine (Get-FirstAppHostInInstance 'sql' $dbInstance 'waitParams')
  
  [void] (Test-SQL $sqlInstance -encrypt $false)


  DBG ('SCOM setup log path will be: {0}' -f "$env:LOCALAPPDATA\SCOM\LOGS")
  Run-Process (Join-Path $instRoot 'setup.exe') $installationParameters


  DBG ('Import SCOM powershell module')
  DBGSTART
  Import-Module "$env:ProgramFiles\Microsoft System Center 2012 R2\Operations Manager\Powershell\operationsmanager\OperationsManager.psm1"
  DBGER $MyInvocation.MyCommand.Name $error
  DBGEND

  DBG ('Get the SCOM Admins user role')
  DBGSTART
  $scomAdminsRole = Get-SCOMUserRole | ? { $_.Name -eq 'OperationsManagerAdministrators' }
  DBGER $MyInvocation.MyCommand.Name $error
  DBGEND
  DBGIF $MyInvocation.MyCommand.Name { (Get-CountSafe $scomAdminsRole) -ne 1 }
  DBGIF $MyInvocation.MyCommand.Name { (Get-CountSafe $scomAdminsRole.Users) -ne 1 }
  DBGIF $MyInvocation.MyCommand.Name { $scomAdminsRole.Users[0] -notlike '*\Administrators' }
  DBG ('Current SCOM administrators: {0} | {1}' -f (Get-CountSafe $scomAdminsRole.Users), ($scomAdminsRole.Users -join ','))

  $newScomAdmins = '{0}@{1}' -f $appConfig.app.aGroup, $appConfig.app.iDomain
  DBG ('Add SCOM Admins group as administrators: {0} | {1} | {2}' -f $appConfig.app.aGroup, $appConfig.app.iDomain, $newScomAdmins)
  DBGSTART
  Set-SCOMUserRole -UserRole $scomAdminsRole -User ($scomAdminsRole.Users + $newScomAdmins)
  DBGER $MyInvocation.MyCommand.Name $error
  DBGEND

  DBG ('Should we adjust hearbeat interval: {0} | {1}' -f (Is-ValidString $appConfig.heartbeat), $appConfig.heartbeat)
  if (Is-ValidString $appConfig.heartbeat) {

    DBGIF $MyInvocation.MyCommand.Name { $appConfig.heartbeat -notmatch $global:rxHHMMSS }
    DBGSTART
    Set-SCOMHeartbeatSetting -HeartbeatInterval $appConfig.heartbeat
    DBGER $MyInvocation.MyCommand.Name $error
    DBGEND
  }

  DBG ('Should we adjust missed hearbeats: {0} | {1}' -f (Is-ValidString $appConfig.missingHB), $appConfig.missingHB)
  if (Is-ValidString $appConfig.missingHB) {

    DBGIF $MyInvocation.MyCommand.Name { -not ([int]::Parse($appConfig.missingHB) -gt 0) }
    DBGSTART
    Set-SCOMHeartbeatSetting -MissingHeartbeatThreshold $appConfig.missingHB
    DBGER $MyInvocation.MyCommand.Name $error
    DBGEND
  }


  DBG ('Update server and console with Update Rollups')

  # Note: this one must install with -qn or it shows FileInUse dialog box (yes, it really shows the old one)
  #       and wants the user to close PowerShell :-)
  #       I tried to laborate with the MSIRESTARTMANAGERCONTROL property, but setting it to =0 has the only effect
  #       of changing the dialog box to that newer RestartManager dialog box.
  #       To definitely get rid of either dialog box, we must probably go for the -qn parameter
  Run-Process 'msiexec' ('-p {0}\scom-2012-r2-update-rollup-4-KB2992020-AMD64-Server.msp -qn -norestart' -f $prereqRoot)
  
  Run-Process 'msiexec' ('-p {0}\scom-2012-r2-update-rollup-4-KB2992020-AMD64-ENU-Console.msp -qn -norestart' -f $prereqRoot)


  DBG ('Setting HealthService to Delayed AutoStart')
  Run-Process 'SC' 'config HealthService start= delayed-auto'

  
<#
  DBG ('Restart the services')
  DBG ('Stop all of them first')
  DBGSTART
  Stop-Service HealthService # Microsoft Monitoring Agent
  Stop-Service cshost # System Center Management Configuration
  Stop-Service OMSDK # System Center Data Access Service
  DBGER $MyInvocation.MyCommand.Name $error
  DBGEND

  DBG ('Start all of them next')
  DBGSTART
  Start-Service OMSDK # System Center Data Access Service
  Start-Sleep -Seconds 23
  Start-Service cshost # System Center Management Configuration
  Start-Sleep -Seconds 23
  Start-Service HealthService # Microsoft Monitoring Agent
  Start-Sleep -Seconds 23
  DBGER $MyInvocation.MyCommand.Name $error
  DBGEND
#>

  DBG ('Open the local SCOM management server and assert some points')
  $scomMgmtSrv = Wait-SCOMManagementServer
 
  DBGIF ('Weird MS version: {0}' -f $scomMgmtSrv.Version) { $scomMgmtSrv.Version -notlike '7.1.*' }
  DBGIF ('Weird MS health state: {0}' -f $scomMgmtSrv.HealthState) { $scomMgmtSrv.HealthState -ne 'Success' }
  DBGIF ('Weird missing HB: {0} | {1}' -f $scomMgmtSrv.MissingHeartbeatThreshold, $appConfig.missingHB) { (Is-ValidString $appConfig.missingHB) -and ($appConfig.missingHB -ne $scomMgmtSrv.MissingHeartbeatThreshold) }
  DBGIF ('Weird MS management group: {0} | {1}' -f $scomMgmtSrv.ManagementGroup.Name, $mgmtGroup) { $scomMgmtSrv.ManagementGroup.Name -ne $mgmtGroup }


  DBG ('Check if any agents need to be installed')
  $agentsRequested = $xmlConfig.SelectNodes('./VMs/MACHINE[vm/@do="true"]/wks/scom[@agent]')
  DBG ("Found {0} scom agent raw nodes" -f (Get-CountSafe $agentsRequested))
  
  if ((Get-CountSafe $agentsRequested) -gt 0) {

    if (Is-NonNull $scomMgmtSrv) {

      DBG ('Check if the SCOM agent install account is defined and valid: {0} | {1}' -f $appConfig.agents.installLogin, $appConfig.agents.installDomain)
      if (Is-ValidString $appConfig.agents.installLogin) {

        $agentInstallSAM = Get-SAMLogin $appConfig.agents.installLogin $appConfig.agents.installDomain
        DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $agentInstallSAM }

        DBG ('Create the pscredential object for the installation action account: {0} | {1}' -f $appConfig.agents.installLogin, $appConfig.agents.installDomain)
        $agentInstallActionAccount = New-Object System.Management.Automation.PSCredential ('{0}@{1}' -f $appConfig.agents.installLogin, $appConfig.agents.installDomain), (ConvertTo-SecureString $appConfig.agents.installPwd -AsPlainText -Force)
        DBGIF $MyInvocation.MyCommand.Name { Is-Null $agentInstallActionAccount }
      }


      [System.Collections.ArrayList] $realAgentList = @()
      foreach ($oneAgentRequested in $agentsRequested) {

        $agentMachine = Get-MachineFromElement $oneAgentRequested

        if (-not (Parse-BoolSafe $agentMachine.vm.do)) {

          DBG ('Machine disabled in config, skipping: {0}' -f $agentMachine.hostName)
          continue
        }


        $agentFQDN = Get-MachineFQDN $oneAgentRequested
        DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $agentFQDN }
        DBGIF $MyInvocation.MyCommand.Name { $agentFQDN -notlike '*.*' }


        DBGIF $MyInvocation.MyCommand.Name { $agentFQDN -eq $global:thisComputerFQDN }
        if ($agentFQDN -eq $global:thisComputerFQDN) {

          DBG ('We do not process SCOM agents locally on SCOM management servers: {0}' -f $agentMachine.hostName)
          continue
        }


        DBG ('Verify agent connectivity first: {0}' -f $agentFQDN)
        DBGIF $MyInvocation.MyCommand.Name { -not (Test-Ping $agentFQDN) }
        DBGIF $MyInvocation.MyCommand.Name { -not (Test-Port $agentFQDN 445) }
        DBGIF $MyInvocation.MyCommand.Name { -not (Test-Port $agentFQDN 135) }


        $oneRealAgent = New-Object PSCustomObject
        Add-Member -Input $oneRealAgent -MemberType NoteProperty -Name fqdn -Value $agentFQDN
        Add-Member -Input $oneRealAgent -MemberType NoteProperty -Name xml -Value $oneAgentRequested
        Add-Member -Input $oneRealAgent -MemberType NoteProperty -Name account -Value $agentInstallActionAccount
        [void] $realAgentList.Add($oneRealAgent)
      }

      

      foreach ($oneRealAgent in $realAgentList) {
        
        DBG ('Should we install the agent: {0} | {1}' -f $oneRealAgent.fqdn, (Parse-BoolSafe $oneRealAgent.xml.agent))
        if (Parse-BoolSafe $oneRealAgent.xml.agent) {

          DBG ('We must wait until the machine gets finished')
          Wait-Machine (Get-MachineWaitParams $oneRealAgent.xml) -doNotRandomWait

          if (Is-NonNull $agentInstallActionAccount) {

            DBG ('Install the SCOM agent on the client computer with a specific user: {0} | {1} | {2}' -f $oneRealAgent.fqdn, $agentInstallSAM, $agentInstallActionAccount.UserName)
            DBGSTART
            Install-SCOMAgent -DnsHostName $oneRealAgent.fqdn -PrimaryManagementServer $scomMgmtSrv -ActionAccount $oneRealAgent.account | Out-Null
            DBGER $MyInvocation.MyCommand.Name $error
            DBGEND
          
          } else {

            DBG ('Install the SCOM agent on the client computer under the default action account: {0} | {1}' -f $oneRealAgent.fqdn, $scomMgmtSrv.ActionAccountIdentity)
            DBGSTART
            Install-SCOMAgent -DnsHostName $oneRealAgent.fqdn -PrimaryManagementServer $scomMgmtSrv | Out-Null
            DBGER $MyInvocation.MyCommand.Name $error
            DBGEND
          }
        }
      }

      
      
      foreach ($oneRealAgent in $realAgentList) {

        DBG ('Get the agent, verify it exists and assert some points: {0}' -f $oneRealAgent.fqdn)
        $agentToModify = Wait-SCOMAgent $oneRealAgent.fqdn -credentials $oneRealAgent.account

        DBGIF ('Weird agent version: {0} | {1}' -f $oneRealAgent.fqdn, $agentToModify.Version) { $agentToModify.Version -notlike '7.1.*' }
        DBGIF ('Weird agent health state: {0} | {1}' -f $oneRealAgent.fqdn, $agentToModify.HealthState) { $agentToModify.HealthState -ne 'Success' }


        DBG ('Should we make the agent trusted as proxy: {0} | {1}' -f $oneRealAgent.fqdn, (Parse-BoolSafe $oneRealAgent.xml.agentProxy))
        if (Parse-BoolSafe $oneRealAgent.xml.agentProxy) {

          if (Is-NonNull $agentToModify) {

            DBG ('Set agent proxy on the agent: {0}' -f $oneRealAgent.fqdn)
            DBGSTART
            Enable-SCOMAgentProxy $agentToModify
            DBGER $MyInvocation.MyCommand.Name $error
            DBGEND
          }
        }
      }
    }
  }
}



DBG ('Throw up any remaining errors')
DBGSTART; DBGEND


# SIG # Begin signature block
# MIIc2AYJKoZIhvcNAQcCoIIcyTCCHMUCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU034raBdAndoR21VkyaCte8Dz
# i+GgghgEMIIE5TCCA82gAwIBAgIQOb1CntKBbrrVvMkDtLpl5zANBgkqhkiG9w0B
# AQsFADB1MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEpMCcG
# A1UECxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIzAhBgNVBAMT
# GlN0YXJ0Q29tIENsYXNzIDIgT2JqZWN0IENBMB4XDTE2MTIwMTE1NTExM1oXDTE4
# MTIwMTE1NTExM1owUTELMAkGA1UEBhMCQ1oxGjAYBgNVBAgMEUppaG9tb3JhdnNr
# eSBLcmFqMQ0wCwYDVQQHDARCcm5vMRcwFQYDVQQDDA5PbmRyZWogU2V2ZWNlazCC
# ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK/RPYTY9Om2rIfSV/e5KbKi
# vWf3IjgQurayOJ75VvQj8ISgU2+cAK4cS2GQRvY1j1q3ctZy/3JuajKgW/5qIGMD
# MLxGFjL7CDjlZ+hw/ZVYTQKLw+jx89M4gQSiLM1048lD0GqCJSBC6L8/eu5u/ByX
# VGSRsaoZbgLEvaPf3xMwO111IVLqkSrHrbmVfwLH4ebDr3nqEbG3luHWk1r7c90y
# blCy9MONyzVWCZHeiy/HHoLyz1WVHtTe7JL4nRL57XZaMELCZahXax90hiiDygOj
# m3GPEmVpBEEm1QRfCrptVE/ozdIJvvOBcDoOVqisflb0ytpY1Vpz6wg9Gc7tqCEC
# AwEAAaOCAZMwggGPMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD
# AzAJBgNVHRMEAjAAMB0GA1UdDgQWBBRtr0qNzYUFiC3lLNKDfV8x03o3HzAfBgNV
# HSMEGDAWgBQ+YpOa18cZ7j6PSRCFVRUg45SEHDBtBggrBgEFBQcBAQRhMF8wJAYI
# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbTA3BggrBgEFBQcwAoYr
# aHR0cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvc2NhLmNvZGUyLmNydDA2BgNV
# HR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9zY2EtY29kZTIu
# Y3JsMCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzBRBgNVHSAE
# SjBIMAgGBmeBDAEEATA8BgsrBgEEAYG1NwECBTAtMCsGCCsGAQUFBwIBFh9odHRw
# czovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5MA0GCSqGSIb3DQEBCwUAA4IBAQCb
# kYhLx7SGEqbJjJD4U8+EDjkoTd6eSlnX/L5u9QN9wkfX3bNdHfA9gdmhPr45hyev
# RmNG234OaGWNi7Ktnri+w2uf4UvPuk9zBLQ+IZ43x1e5sZqEnxbsvyg4qaFersIS
# PpLKnIV2HVB/ubgkDtDDjvCE4wIM1ELJ2eFCARwRnj/nvt5Y8UmEl1nTyK4MXUfe
# 9T/x4VklXyjZZgYBCjEDOSctGgHeI8UpfwM3WLdPuqZYhSdaXhoXRZ4thZvH7uaD
# evGkyKzbXOVmOy84H/rEU1XljkVkt+/tcwA9Jo83fIMnwS8UbmkUn42MZ8tKy13p
# QMH4gN83tg1NgX4Pf633MIIF2DCCA8CgAwIBAgIQbDvSft08lJ6Vjiips8dXoDAN
# BgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20g
# THRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu
# ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN
# MTUxMjE2MDEwMDA1WhcNMzAxMjE2MDEwMDA1WjB1MQswCQYDVQQGEwJJTDEWMBQG
# A1UEChMNU3RhcnRDb20gTHRkLjEpMCcGA1UECxMgU3RhcnRDb20gQ2VydGlmaWNh
# dGlvbiBBdXRob3JpdHkxIzAhBgNVBAMTGlN0YXJ0Q29tIENsYXNzIDIgT2JqZWN0
# IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuRQEWPeyxYYsCDJg
# rQgmwIF3uWgZ2RUrHRhp5NoalgWXLmR5Gqk9UTNa0Hdq9AKTQcOOunAbq9h7dG+Y
# 6Ne5qT5odqSJoCKsF9Yp+Lu4YZ/SB9BmDjBHICtwAh7+cwkccTS14n6prKin8Y46
# QAZ2ksr3eGzvWAVzfX+DUOmiVQLjAK6Wp8bCZHvj+FhAlS5Ne7/dggDeSVWnMyPm
# 2k/5YKOTVXExJJaAlYkmyH1OiC3soTkkGb6aJjGJPHiaiNJ4pjkySX5l2p4DQ7K1
# /J6ft5Vw9PuqwmYrF0ViGnn38kzB2d9UI9Q+dFmHUbV+cnr+FoGl6CiUDd5ZIF1H
# Mrb8hwIDAQABo4IBWjCCAVYwDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsG
# AQUFBwMDMBIGA1UdEwEB/wQIMAYBAf8CAQAwMgYDVR0fBCswKTAnoCWgI4YhaHR0
# cDovL2NybC5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMGYGCCsGAQUFBwEBBFowWDAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3Auc3RhcnRzc2wuY29tMDAGCCsGAQUFBzAC
# hiRodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9jYS5jcnQwHQYDVR0OBBYE
# FD5ik5rXxxnuPo9JEIVVFSDjlIQcMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0
# aEPQQa7yMD8GA1UdIAQ4MDYwNAYEVR0gADAsMCoGCCsGAQUFBwIBFh5odHRwOi8v
# d3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kwDQYJKoZIhvcNAQELBQADggIBAGOlPNWz
# bSco2Ou6U68wC+pKXRLV+ZrKcPpMY4zXTVR+RupS54WhJCManab2P1ncPlHTbRMb
# PjfHnyj0sIdpvwcV49n0nizMF3MBxaKJEnBBEfHs9Krgjc4qKjR2nOywlzxJ0M27
# RthR5XjyjQ1ofHlOisYgMzcyKyMT7YYpxxoC0wTgAh0DNmE5Q/GKFOaDd3S5gTqr
# R9AQzGaC3IxCKBFtcwvk51W98lNRtMbm+oJze5T+dL2wIhyWK58sEIl2paAVfAfW
# GH3umYL46scLn8BXDFchN1Jgrg07DqY6gxCqSdubPhVHZInuVagktWmrnS6N9V/v
# VLz+OaX4Mkas8n1J1RIR+GV8ZQVmTM49l6L+fpv/h95MWLhQOcXanbIY/2cdNEuz
# 5AkhfvDNTQnLxYEMIyMOtW2QIwwZdz92vMTU17G9goxXYjSm09yw+iBniH9G/xGz
# 39BV3bwa8ZtKHzDoZ54HT6JT2AraDhrWTwFXv8Xrvv2cir+k0h5bIWlDtImH7Jm1
# 52edb77f5JI8JrPf6jxcUrhNH4xHxe2kGs8ERA39oYlT0dKQIb0obTN6FOF63hBR
# FFhGB7NuX2FeFjJsZFCkoJkpsEauObb7Rh+C02+fnHfoi6ivKwUC9BOsWlI4xn7G
# Me27niL6k7wpK0L6MTG5/6gxwosqaMA1aukwMIIGajCCBVKgAwIBAgIQAwGaAjr/
# WLFr1tXq5hfwZjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UE
# ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD
# VQQDExhEaWdpQ2VydCBBc3N1cmVkIElEIENBLTEwHhcNMTQxMDIyMDAwMDAwWhcN
# MjQxMDIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNlcnQx
# JTAjBgNVBAMTHERpZ2lDZXJ0IFRpbWVzdGFtcCBSZXNwb25kZXIwggEiMA0GCSqG
# SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjZF38fLPggjXg4PbGKuZJdTvMbuBTqZ8f
# ZFnmfGt/a4ydVfiS457VWmNbAklQ2YPOb2bu3cuF6V+l+dSHdIhEOxnJ5fWRn8YU
# Oawk6qhLLJGJzF4o9GS2ULf1ErNzlgpno75hn67z/RJ4dQ6mWxT9RSOOhkRVfRiG
# BYxVh3lIRvfKDo2n3k5f4qi2LVkCYYhhchhoubh87ubnNC8xd4EwH7s2AY3vJ+P3
# mvBMMWSN4+v6GYeofs/sjAw2W3rBerh4x8kGLkYQyI3oBGDbvHN0+k7Y/qpA8bLO
# cEaD6dpAoVk62RUJV5lWMJPzyWHM0AjMa+xiQpGsAsDvpPCJEY93AgMBAAGjggM1
# MIIDMTAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAK
# BggrBgEFBQcDCDCCAb8GA1UdIASCAbYwggGyMIIBoQYJYIZIAYb9bAcBMIIBkjAo
# BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCCAWQGCCsG
# AQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAgAG8AZgAgAHQAaABpAHMAIABD
# AGUAcgB0AGkAZgBpAGMAYQB0AGUAIABjAG8AbgBzAHQAaQB0AHUAdABlAHMAIABh
# AGMAYwBlAHAAdABhAG4AYwBlACAAbwBmACAAdABoAGUAIABEAGkAZwBpAEMAZQBy
# AHQAIABDAFAALwBDAFAAUwAgAGEAbgBkACAAdABoAGUAIABSAGUAbAB5AGkAbgBn
# ACAAUABhAHIAdAB5ACAAQQBnAHIAZQBlAG0AZQBuAHQAIAB3AGgAaQBjAGgAIABs
# AGkAbQBpAHQAIABsAGkAYQBiAGkAbABpAHQAeQAgAGEAbgBkACAAYQByAGUAIABp
# AG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgAGgAZQByAGUAaQBuACAAYgB5ACAAcgBl
# AGYAZQByAGUAbgBjAGUALjALBglghkgBhv1sAxUwHwYDVR0jBBgwFoAUFQASKxOY
# spkH7R7for5XDStnAs0wHQYDVR0OBBYEFGFaTSS2STKdSip5GoNL9B6Jwcp9MH0G
# A1UdHwR2MHQwOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy
# dEFzc3VyZWRJRENBLTEuY3JsMDigNqA0hjJodHRwOi8vY3JsNC5kaWdpY2VydC5j
# b20vRGlnaUNlcnRBc3N1cmVkSURDQS0xLmNybDB3BggrBgEFBQcBAQRrMGkwJAYI
# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1
# aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0Et
# MS5jcnQwDQYJKoZIhvcNAQEFBQADggEBAJ0lfhszTbImgVybhs4jIA+Ah+WI//+x
# 1GosMe06FxlxF82pG7xaFjkAneNshORaQPveBgGMN/qbsZ0kfv4gpFetW7easGAm
# 6mlXIV00Lx9xsIOUGQVrNZAQoHuXx/Y/5+IRQaa9YtnwJz04HShvOlIJ8OxwYtNi
# S7Dgc6aSwNOOMdgv420XEwbu5AO2FKvzj0OncZ0h3RTKFV2SQdr5D4HRmXQNJsQO
# fxu19aDxxncGKBXp2JPlVRbwuwqrHNtcSCdmyKOLChzlldquxC5ZoGHd2vNtomHp
# igtt7BIYvfdVVEADkitrwlHCCkivsNRu4PQUCjob4489yq9qjXvc2EQwggbNMIIF
# taADAgECAhAG/fkDlgOt6gAK6z8nu7obMA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNV
# BAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp
# Y2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAe
# Fw0wNjExMTAwMDAwMDBaFw0yMTExMTAwMDAwMDBaMGIxCzAJBgNVBAYTAlVTMRUw
# EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
# ITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMTCCASIwDQYJKoZIhvcN
# AQEBBQADggEPADCCAQoCggEBAOiCLZn5ysJClaWAc0Bw0p5WVFypxNJBBo/JM/xN
# RZFcgZ/tLJz4FlnfnrUkFcKYubR3SdyJxArar8tea+2tsHEx6886QAxGTZPsi3o2
# CAOrDDT+GEmC/sfHMUiAfB6iD5IOUMnGh+s2P9gww/+m9/uizW9zI/6sVgWQ8DIh
# FonGcIj5BZd9o8dD3QLoOz3tsUGj7T++25VIxO4es/K8DCuZ0MZdEkKB4YNugnM/
# JksUkK5ZZgrEjb7SzgaurYRvSISbT0C58Uzyr5j79s5AXVz2qPEvr+yJIvJrGGWx
# wXOt1/HYzx4KdFxCuGh+t9V3CidWfA9ipD8yFGCV/QcEogkCAwEAAaOCA3owggN2
# MA4GA1UdDwEB/wQEAwIBhjA7BgNVHSUENDAyBggrBgEFBQcDAQYIKwYBBQUHAwIG
# CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgwggHSBgNVHSAEggHJMIIBxTCC
# AbQGCmCGSAGG/WwAAQQwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3LmRpZ2lj
# ZXJ0LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUHAgIwggFW
# HoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBm
# AGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0
# AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAv
# AEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0
# AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAg
# AGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBw
# AG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBu
# AGMAZQAuMAsGCWCGSAGG/WwDFTASBgNVHRMBAf8ECDAGAQH/AgEAMHkGCCsGAQUF
# BwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMG
# CCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRB
# c3N1cmVkSURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3Js
# My5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2
# hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290
# Q0EuY3JsMB0GA1UdDgQWBBQVABIrE5iymQftHt+ivlcNK2cCzTAfBgNVHSMEGDAW
# gBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEARlA+ybco
# JKc4HbZbKa9Sz1LpMUerVlx71Q0LQbPv7HUfdDjyslxhopyVw1Dkgrkj0bo6hnKt
# OHisdV0XFzRyR4WUVtHruzaEd8wkpfMEGVWp5+Pnq2LN+4stkMLA0rWUvV5PsQXS
# Dj0aqRRbpoYxYqioM+SbOafE9c4deHaUJXPkKqvPnHZL7V/CSxbkS3BMAIke/MV5
# vEwSV/5f4R68Al2o/vsHOE8Nxl2RuQ9nRc3Wg+3nkg2NsWmMT/tZ4CMP0qquAHzu
# nEIOz5HXJ7cW7g/DvXwKoO4sCFWFIrjrGBpN/CohrUkxg0eVd3HcsRtLSxwQnHcU
# wZ1PL1qVCCkQJjGCBD4wggQ6AgEBMIGJMHUxCzAJBgNVBAYTAklMMRYwFAYDVQQK
# Ew1TdGFydENvbSBMdGQuMSkwJwYDVQQLEyBTdGFydENvbSBDZXJ0aWZpY2F0aW9u
# IEF1dGhvcml0eTEjMCEGA1UEAxMaU3RhcnRDb20gQ2xhc3MgMiBPYmplY3QgQ0EC
# EDm9Qp7SgW661bzJA7S6ZecwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAI
# oAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB
# CzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFJgiK8OvN0zLUw/bVnrq
# 2wHK+PAPMA0GCSqGSIb3DQEBAQUABIIBADLAPyNJlqEBBxZjqVxWMolZsteuZEAf
# qtGz0Uh2QU3yR7sabWN+Y2g9JrLpA2sKZ7BJWadPYC5OEC7t9WWji7liIH8OrMq+
# BS1D41lXe+33dSulRpIN3I9Z2Jm9HgWJWtIuiTSowflZOFQxqXFPbRJDoko4xV7/
# ZM34w+dHx0yLeBDi7NMWP10ECMUM6Q3zYwq1cHSBBNyc+Jd/35+fx0TgsLhn3XtM
# GORdgiTeDwNJFOSbJYQ6/twVgQLQulowLyR7fLyAS8IVLY64hqf8ciVC4xgzD5JZ
# uNcf0f0y84w4Foo3Rk0DEJUlJBNIVwXVol6lMf5WU+hIQ+zJnqtmnh2hggIPMIIC
# CwYJKoZIhvcNAQkGMYIB/DCCAfgCAQEwdjBiMQswCQYDVQQGEwJVUzEVMBMGA1UE
# ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD
# VQQDExhEaWdpQ2VydCBBc3N1cmVkIElEIENBLTECEAMBmgI6/1ixa9bV6uYX8GYw
# CQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcN
# AQkFMQ8XDTE3MDMyMzEzNDExMlowIwYJKoZIhvcNAQkEMRYEFIjdz+ENuMZjfj0L
# NT3/pDaBEyAXMA0GCSqGSIb3DQEBAQUABIIBAFo9V1O5hd2cpiXz2v18+VgTjGJw
# aAN5D2B5u9afvkqyMbYjtgQkSaG8/wlljf+ZKBnADzjzZwb9fQUvgkFDQmIrwIvp
# 1BbQvUpj7cTIuIEKuSVkDkH5x4qtYu6SZOYzFeIOiKZXJwBr/0oB+nE7XNJKd7D6
# w/h2A4DFJBtGaDbSFLGhwOSBeJi28F5L+P/y3vCD6/mtRhsCC0D48skHbKyBOMVr
# muIUKnzxTPikBo1Fe8O7gbQdhHM3f2eZq+Ekcmsr2QflyQ9W1wdY8nINa7RvVCnF
# Fzvp1UoqP9mZtjcNIBT475HMO1OQ8uwXWHvuEj25x23PYdcT2WFew0RTuLM=
# SIG # End signature block