ADLAB PowerShell source file: buildup-1.ps1

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



#
# Note: This code may be run without $vmConfig and $vmName because of the obsolette Hyper-V IC (HVIC)
#       so this phase may run twice, first to update basic $commonVM settings and 
#       mainly install newest Hyper-V IC (HVIC)
#
#

#=====================
# Common machine config

DBG ("Build step: {0}" -f $MyInvocation.MyCommand.Definition)
DBG "First stage with Hyper-V IC (HVIC) installation..."


DBGIF ('Weird system drive letter not tested: {0}' -f $env:SystemDrive) { $env:SystemDrive -ne 'C:' }



DBG ('Should we stop on BSOD instead of restarting: {0}' -f (Parse-BoolSafe $vmConfig.bsodStop))

if (Parse-BoolSafe $vmConfig.bsodStop) {

  Set-RegistryValue 'HKLM:\SYSTEM\ControlSet001\Control\CrashControl' AutoReboot 0 DWord
}



if ($global:phaseRetrial -eq 1) {

  #===============
  DBGIF 'SYSPREP myself' { (Is-ValidString $vmConfig.sysprep.unatt) }

  if (Is-ValidString $vmConfig.sysprep.unatt) {

    DBG ('Determine currently running admin account')
    DBGSTART
    $currentRunningAdmin = [Security.Principal.WindowsIdentity]::GetCurrent($false)
    DBGER $MyInvocation.MyCommand.Name $error
    DBGEND
    DBG ('Currently running admin account: {0} | {1}' -f $currentRunningAdmin.Name, $currentRunningAdmin.User.Value)
    DBGIF $MyInvocation.MyCommand.Name { $currentRunningAdmin.User.Value -ne "$($global:thisComputerSID)-500" }
    DBGIF $MyInvocation.MyCommand.Name { $currentRunningAdmin.Name -ne "$global:thisComputerNetBIOS\Administrator" }


    DBG ('Build SYSPREP unattended file with the following params: {0} | {1}' -f $vmConfig.sysprep.pk, $vmConfig.sysprep.org)

    if ($global:thisOSVersionNumber -ge 6) {

      $sysprepPK = Get-SysprepUnattendedXmlPKElement $vmConfig.sysprep.pk

      $sysprepUnattendedSource = Resolve-PathSafe $vmConfig.sysprep.unatt
      $sysprepPath = Join-Path $env:SystemRoot 'System32\sysprep\sysprep.exe'

      $sysprepUnattended = Get-DataFileApp "sysprep-unattended-replaced" $null ([System.IO.Path]::GetExtension($sysprepUnattendedSource)) $true
      Replace-ArgumentsInFile $sysprepUnattendedSource ('defaultAdminPassword${0}|productKey${1}|organization${2}|installFromImage${3}|configId${4}|buildupMainBAT${5}' -f (Escape-ForMultiValue $global:phaseCfg.sevecekBuildup.login.pwd, $sysprepPK, $vmConfig.sysprep.org, '', $global:configScheme, $global:buildupMainBAT)) $sysprepUnattended ASCII

      DBG ('Going to run SYSPREP on Windows 6+: {0} | {1} | {2} | {3}' -f $vmConfig.sysprep.unatt, $sysprepUnattendedSource, $sysprepUnattended, $sysprepPath)

    } else {

      DBGIF ('SYSPREP not implemented for Windows 5.x') { $true }
    }

    
    DBGIF $MyInvocation.MyCommand.Name { -not (Test-Path $sysprepPath) }
    DBGIF $MyInvocation.MyCommand.Name { -not (Test-Path $sysprepUnattended) }

    if ((Test-Path $sysprepPath) -and (Test-Path $sysprepUnattended)) {

      Run-Process $sysprepPath ('/generalize /oobe /quiet /quit /unattend:"{0}"' -f $sysprepUnattended)
    }


    $currentRunningAdminLogin = $currentRunningAdmin.Name.SubString("$global:thisComputerNetBIOS\".Length)
    # Note: I do not like [Environment]::UserName so this goes only to ensure some basics
    DBGIF $MyInvocation.MyCommand.Name { [Environment]::UserName -ne $currentRunningAdminLogin }
    
    if ($global:thisOSRole -like '*workstation') {

      DBG ('Workstation OS built-in Administrator behavior')

      # Note: seems like SYSPREP disables the built-in Administrator account during its pre-restart Generalize phase
      #       and again during some of the post-restart phases (most probably the Specialize phase)
      #       Here we enable the account to let our script finish in a normal manner undisturbed by the fact
      #       it might run under a disabled account.
      #       Later, during the post-restart oobeSystem, we enable the account again using the  element
      #       of the answer file

      DBG ('Verify that the generalize phase of sysprep really disabled the admin account and enable it again: {0}' -f $currentRunningAdminLogin)

      # Note: here we might be running under a different login because, as documentation says
      #       the -500 account will get renamed back to Administrator during oobeSystem
      #       (not verified by me, just as documentation states)

      Enable-LocalUser $currentRunningAdminLogin -assertIfNotDisabled $true

    } else {

      DBG ('Server OS built-in Administrator behavior')

      # Note: the server OS editions do not disable the built-in Administrator account during the Generalize phase
      #       nor later during post-restart phases, so we just make sure it stays that way

      DBGIF $MyInvocation.MyCommand.Name { -not (Is-LocalUserEnabled $currentRunningAdminLogin) }
    }

    
    $global:restartCurrentPhase = $true
    DBG ('Exiting SYSPREP phase to restart')
    exit
  }
}


DBG ('Should we install any root CA certificates: {0} | {1}' -f $vmConfig.wks.rootCAs.search, (Is-ValidString $vmConfig.wks.rootCAs.search))
if (Is-ValidString $vmConfig.wks.rootCAs.search) {

  $rootCaSearches = Split-MultiValue $vmConfig.wks.rootCAs.search
  DBG ('Will import root CAs from the following search locations: {0}' -f (Get-CountSafe $rootCaSearches), ($rootCaSearches -join ','))
  
  foreach ($oneRootCaSearch in $rootCaSearches) {

    $rootCaWildcard = Join-Path (Join-Path $global:libCommonParentDir 'AD-CS') $oneRootCaSearch
    DBG ('Searching in the following root CA location: {0}' -f $rootCaWildcard)
    DBGSTART
    $oneRootCAs = $null
    $oneRootCAs = Get-ChildItem $rootCaWildcard | Select -Expand FullName
    DBGER $MyInvocation.MyCommand.Name $error
    DBGEND
    DBG ('Found the root CA certificates: #{0} | {1}' -f (Get-CountSafe $oneRootCAs), ($oneRootCAs -join ','))
    DBGIF ('Didnt find any root CA certificate as specified: {0}' -f $rootCaWildcard) { (Get-CountSafe $oneRootCAs) -lt 1 }

    if ((Get-CountSafe $oneRootCAs) -gt 0) {

      foreach ($oneRootCaCertificate in $oneRootCAs) {

        DBG ('Install one root CA certificate: {0}' -f $oneRootCaCertificate)
        DBGSTART
        $oneCertLoaded = $true
        $oneCertLoaded = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $oneRootCaCertificate
        $targetCertStore = Get-Item 'Cert:\LocalMachine\Root'
        $targetCertStore.Open('ReadWrite')
        $targetCertStore.Add($oneCertLoaded)
        DBGER $MyInvocation.MyCommand.Name $error
        DBGEND
      }
    }
  }
}


#===============
# Hyper-V IC (HVIC) update if necessary

$wasICUpdated = Update-HyperVIntegration
DBG ('HVIC was updated and restart is needed to update vmConfig? {0} | {1}' -f $wasICUpdated, (Is-EmptyString $global:vmName))
if ($wasICUpdated -and (Is-EmptyString $global:vmName)) {

  DBG ('Will restart current phase to allow for valid $vmConfig next time')
  $global:restartCurrentPhase = $true
  exit
}



#===============
DBG ("All local user passwords except for GUEST")

$users = Get-WMIQueryArray '.' "SELECT * FROM Win32_UserAccount WHERE Domain='$thisComputerNetBIOS' AND SID <> '$thisComputerSID-501'"
DBGIF $MyInvocation.MyCommand.Name { $users.Count -lt 1 }

if (Is-ValidString $vmConfig.commonVM.builtinUserPwd) {

  if ($users.Count -ge 1) {

    DBG ("Resetting passwords for local {0} user accounts." -f $users.Count)
  
    foreach ($wmiUsr in $users) {

      Reset-UserPassword $wmiUsr.Domain $wmiUsr.Name $vmConfig.commonVM.builtinUserPwd -nonExpirePassword (Parse-BoolSafe($vmConfig.commonVM.nonExpirePwd))
    }
  }
}


#===============
# Note: we MUST disable UAC for the duration of the buildup process as it was designed in such a way
#       from the very start. So this code has been moved to DTR as the very final task and changed to
#       actually re-enable UAC if requested
#DBG ("Disable UAC: {0}" -f (Parse-BoolSafe $vmConfig.commonVM.uacOff))
#
#if (Parse-BoolSafe($vmConfig.commonVM.uacOff))
#{
DBG ('We must disable UAC for the duration of the buildup process on Windows 6.0+: {0}' -f ($global:thisOSVersionNumber -ge 6))
if ($global:thisOSVersionNumber -ge 6) {

  [string] $luaRegKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'

  DBG ('Verify the value existance: {0}' -f $luaRegKey)
  DBGIF $MyInvocation.MyCommand.Name { -not (Test-Path -Literal $luaRegKey) }
  DBGSTART
  $luaRegValues = Get-ItemProperty $luaRegKey
  DBGER $MyInvocation.MyCommand.Name $error
  DBGEND
  DBG ('LUA settings: {0} | {1} | {2}' -f $luaRegValues.EnableLUA, $luaRegValues.PromptOnSecureDesktop, $luaRegValues.ConsentPromptBehaviorAdmin)
  DBGIF ('Weird LUA settings: {0},{1},{2} should be either 0,0,0 or 1,1,5' -f $luaRegValues.EnableLUA, $luaRegValues.PromptOnSecureDesktop, $luaRegValues.ConsentPromptBehaviorAdmin) { (-not (($luaRegValues.EnableLUA -eq 0) -and ($luaRegValues.PromptOnSecureDesktop -eq 0) -and ($luaRegValues.ConsentPromptBehaviorAdmin -eq 0))) -and (-not (($luaRegValues.EnableLUA -eq 1) -and ($luaRegValues.PromptOnSecureDesktop -eq 1) -and ($luaRegValues.ConsentPromptBehaviorAdmin -eq 5))) }

  Set-RegistryValue 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' EnableLUA 0 DWord
  Set-RegistryValue 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' PromptOnSecureDesktop 0 DWord
  Set-RegistryValue 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' ConsentPromptBehaviorAdmin 0 DWord
}
#}


#===============
DBG ("Disable System Restore (System Protection): {0}" -f (Parse-BoolSafe($vmConfig.commonVM.systemRestoreOff)))

if (Parse-BoolSafe($vmConfig.commonVM.systemRestoreOff))
{
  Disable-SystemRestore
}


ReDisable-Updates


#===============
DBG ('Disable "Take a tour" on Windows XP: {0}' -f (Parse-BoolSafe($vmConfig.commonVM.tourOff)))

if ((Parse-BoolSafe($vmConfig.commonVM.tourOff)) -and ($thisOSVersionNumber -eq 5.1)) 
{
  Set-RegistryValue 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Applets\Tour' RunCount 0 DWord
}


#===============
DBG ("Disable security center notifications: {0}" -f (Parse-BoolSafe($vmConfig.commonVM.scNotifyOff)))

if (Parse-BoolSafe($vmConfig.commonVM.scNotifyOff)) 
{
  if ($thisOSVersion -like '5.*') {
  
    Set-RegistryValue 'HKLM:\SOFTWARE\Microsoft\Security Center' AntiVirusDisableNotify 1 DWord
    Set-RegistryValue 'HKLM:\SOFTWARE\Microsoft\Security Center' FirewallDisableNotify 1 DWord
    Set-RegistryValue 'HKLM:\SOFTWARE\Microsoft\Security Center' UpdatesDisableNotify 1 DWord
  }
}


#===============
DBG ("Configure firewall to Allow/Allow: {0}" -f (Parse-BoolSafe($vmConfig.commonVM.firewallAllow)))

if (Parse-BoolSafe($vmConfig.commonVM.firewallAllow))
{
  if ($thisOSVersion -like '5.*') {

    DBG ("Firewall config on Windows 5.x: Disable")

    $fwBackupFile = Get-DataFileApp 'firewall-backup-win50' $null '.ini' -doNotPrefixWithOutFile $true

    if ($global:thisOSRole -like '*workstation*') {

      DBG ('Configure Windows Firewall on Windows XP')
      Set-AdvFirewallWithBackup $fwBackupFile -state5x 'disable' -state5xSvc 'Disabled' -expectedState5x 'enable' -expectedState5xSvc 'auto'

    } else {

      if ($global:phaseCfg.sevecekBuildup.media.source -eq 'iso') {

        # Note: on 5.x we must ensure the Windows Firewall/Internet Connection Sharing service
        #       (SharedAccess) is disabled. When installing from ISO, the service is not
        #       disabled by default not even on Windows 2003.
        #       On Windows 5.x, after disabling it with NETSH, the service is left in Automatic
        #       start mode and just stops immediatelly after started automatically. This prevents
        #       later installation of IP NAT and also displays GUI error of a service not started.

        DBG ('Configure Windows Firewall on Windows 2003 when built from ISO')
        Set-AdvFirewallWithBackup $fwBackupFile -state5x 'disable' -state5xSvc 'Disabled' -expectedState5x 'enable' -expectedState5xSvc 'auto'

      } else {

        DBG ('Configure Windows Firewall on Windows 2003 when built from VHD')
        Set-AdvFirewallWithBackup $fwBackupFile -state5x 'disable' -state5xSvc 'Disabled' -expectedState5x 'disable' -expectedState5xSvc 'disabled'
      }
    }
  }
  
  else {

    DBG ("Firewall config on Windows 6.0+: Allow/Allow")

    
    $fwBackupFile = Get-DataFileApp 'firewall-backup-win60' $null '.ini' -doNotPrefixWithOutFile $true

    Set-AdvFirewallWithBackup $fwBackupFile -group domainprofile -what state -value on -expectedWhat State -expectedCurrentValue on
    Set-AdvFirewallWithBackup $fwBackupFile -group privateprofile -what state -value on -expectedWhat State -expectedCurrentValue on
    Set-AdvFirewallWithBackup $fwBackupFile -group publicprofile -what state -value on -expectedWhat State -expectedCurrentValue on

    Set-AdvFirewallWithBackup $fwBackupFile -group domainprofile -what firewallpolicy -value 'allowinbound,allowoutbound' -expectedWhat 'Firewall Policy' -expectedCurrentValue 'BlockInbound,AllowOutbound'
    Set-AdvFirewallWithBackup $fwBackupFile -group privateprofile -what firewallpolicy -value 'allowinbound,allowoutbound' -expectedWhat 'Firewall Policy' -expectedCurrentValue 'BlockInbound,AllowOutbound'
    Set-AdvFirewallWithBackup $fwBackupFile -group publicprofile -what firewallpolicy -value 'allowinbound,allowoutbound' -expectedWhat 'Firewall Policy' -expectedCurrentValue 'BlockInbound,AllowOutbound'

    if ($global:thisOSRole -like '*workstation*') {

      Set-AdvFirewallWithBackup $fwBackupFile -group global -what statefulftp -value enable -expectedWhat 'StatefulFTP' -expectedCurrentValue 'Enable'
      Set-AdvFirewallWithBackup $fwBackupFile -group global -what statefulpptp -value enable -expectedWhat 'StatefulPPTP' -expectedCurrentValue 'Enable'

    } else {

      Set-AdvFirewallWithBackup $fwBackupFile -group global -what statefulftp -value enable -expectedWhat 'StatefulFTP' -expectedCurrentValue 'Disable'
      Set-AdvFirewallWithBackup $fwBackupFile -group global -what statefulpptp -value enable -expectedWhat 'StatefulPPTP' -expectedCurrentValue 'Disable'
    }

    # other firewall states are: blockinboundalways, blockinbound, blockoutbound

    <#$cmdRs = & {
    
      netsh advfirewall set allprofiles state on
      netsh advfirewall set allprofiles firewallpolicy "allowinbound,allowoutbound"
      netsh advfirewall set global statefulftp enable
      netsh advfirewall set global statefulpptp enable
    
    } | Out-String
    
    DBG ("CMD output: {0}" -f $cmdRs)#>
  }
}


#===============
DBG ("Should disable WinRE: {0}" -f (($thisOSVersionNumber -ge 6.1) -and (Parse-BoolSafe($vmConfig.commonVM.winreOff))))

if (($thisOSVersionNumber -ge 6.1) -and (Parse-BoolSafe($vmConfig.commonVM.winreOff)))
{
  Run-Process 'ReAgentC' '/disable'
}


#================
DBG ('Should we change time zone: {0} | {1}' -f (Is-ValidString $vmConfig.commonVM.timeZone), $vmConfig.commonVM.timeZone)

if (Is-ValidString $vmConfig.commonVM.timeZone) {

  Set-TimeZone $vmConfig.commonVM.timeZone
}


#================
DBG ("Fixing WMI Error 10 on Windows 6.0/6.1")

if (($thisOSVersion -like '6.0.*') -or ($thisOSVersion -like '6.1.*')) {

  DBG ("Going to obtain the BVTFilter and its associates.")
  $evFilter = Get-WMIQueryArray '.' "SELECT * FROM __EventFilter WHERE Name='BVTFilter'" 'root\subscription'

  DBG ('Must delete the EventFilter = BVTFilter? Exists = {0}' -f ((Get-CountSafe $evFilter) -gt 0))
  if ((Get-CountSafe $evFilter) -gt 0) {

    # this is the list of real objects the are associated with the filter
    $assocs = Get-WMIQueryArray '.' "Associators Of {__EventFilter.Name='BVTFilter'} WHERE AssocClass=__FilterToConsumerBinding" 'root\subscription'

    # this is the list of binding classes that connect the two real objects
    $refers = Get-WMIQueryArray '.' "References Of {__EventFilter.Name='BVTFilter'} WHERE ResultClass=__FilterToConsumerBinding" 'root\subscription'
  
    DBG ("Going to delete the objects...")
    DBGSTART
    $assocs | Remove-WmiObject
    $refers | Remove-WmiObject
    $evFilter | Remove-WmiObject
    DBGER $MyInvocation.MyCommand.Name $error
    DBGEND
  }
}


#===============
DBG ('Should we configure static w32time/w32tm settings: {0}' -f (Is-NonNull $vmConfig.w32time))
if (Is-NonNull $vmConfig.w32time) {

  Set-W32timeConfig -maxPosCorrection $vmConfig.w32time.maxPosCorrection -maxNegCorrection $vmConfig.w32time.maxNegCorrection -specialPoll $vmConfig.w32time.specialPoll -manualPeers $vmConfig.w32time.manualPeers -clientType $vmConfig.w32time.clientType -triggerW32TimeOnNetwork (Parse-BoolSafe $vmConfig.w32time.triggerOnNetwork)
}


#===============
DBG ('Local/builtin admin (-500) rename: {0}' -f $vmConfig.commonVM.builtinAdmin)

if (Is-ValidString $vmConfig.commonVM.builtinAdmin) {

  $currentAutoLogin = $global:phaseCfg.sevecekBuildup.login
  DBG ('Current autologon parameters: {0}\{1}' -f $currentAutoLogin.domain, $currentAutoLogin.autoLogin)

  DBG ('Get the current -500 builtin Administrator account name')
  [string] $builtinAdminSAM = Get-SAMLogin ('{0}{1}' -f $global:thisComputerSID, $global:wellKnownSIDs['Administrator'])
  [string] $builtinAdminLogin = $builtinAdminSAM.SubString(($builtinAdminSAM.IndexOf('\') + 1))
  DBG ('Current builtin Administrator (-500) account login name: {0}' -f $builtinAdminLogin)
  DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $builtinAdminLogin }
  DBGIF ('We are not adapting and the current autologon identity is not the same as builtin admin: auto = {0} | builtin = {1}' -f $currentAutoLogin.autoLogin, $builtinAdminLogin) { (-not $global:adaptingExistingEnv) -and (($builtinAdminLogin -ne $currentAutoLogin.autoLogin) -or ($currentAutoLogin.domain -ne '.')) }

  #
  #

  DBG ('Should we rename the builtin admin to a new value: currentBuiltin = {0} | newBuiltin = {1}' -f $builtinAdminLogin, $vmConfig.commonVM.builtinAdmin)
  if ($builtinAdminLogin -ne $vmConfig.commonVM.builtinAdmin) {

    Rename-LocalObj 'user' $builtinAdminLogin $vmConfig.commonVM.builtinAdmin
  }

  # Note: we are changing to ensure some control over the input/state parameters but when adapting
  #       the password change may not succeed as there might alread be some domain/local policies in place such as 
  #       MinimumPasswordAge or PasswordHistory which require SetPassword() to work
  #       If we are adapting, we may also hit the problem with current password being unknown
  Change-LocalUserPassword $vmConfig.commonVM.builtinAdmin $currentAutoLogin.pwd $vmConfig.commonVM.builtinAdminPwd -resetIfComplexityOrCurrentFails $true

  $newAutoLogonLogin = $vmConfig.commonVM.builtinAdmin
  $newAutoLogonDomain = '.'
  $newAutoLogonPwd = $vmConfig.commonVM.builtinAdminPwd

  DBG ('Changing autologon identity to the renamed local admin: current = {0}\{1} | new = {2}\{3}' -f $currentAutoLogin.domain, $currentAutoLogin.autoLogin, $newAutoLogonDomain, $newAutoLogonLogin)

  $global:phaseCfg.sevecekBuildup.login.autoLogin = $newAutoLogonLogin
  $global:phaseCfg.sevecekBuildup.login.pwd = $newAutoLogonPwd
  $global:phaseCfg.sevecekBuildup.login.domain = $newAutoLogonDomain
  $global:phaseCfg.sevecekBuildup.originalAdmin.login = $vmConfig.commonVM.builtinAdmin

} else {

  DBGIF ('Inconsistent autologin and current user: autologin = {0} | current = {1}' -f $global:phaseCfg.sevecekBuildup.login.autoLogin, ([Environment]::UserName)) { $global:phaseCfg.sevecekBuildup.login.autoLogin -ne ([Environment]::UserName) }
  DBGIF ('Current user is not -500 admin: {0}' -f ([Environment]::UserName)) { (New-Object Security.Principal.NTAccount ([Environment]::UserName)).Translate([Security.Principal.SecurityIdentifier]).Value -notlike 'S-1-5-21-?*-500' }

  $global:phaseCfg.sevecekBuildup.login.autoLogin = [Environment]::UserName
  $global:phaseCfg.sevecekBuildup.login.domain = '.'
  $global:phaseCfg.sevecekBuildup.originalAdmin.login = [Environment]::UserName

  DBG ('We are not renaming the admin-500 so we just keep the original admin name: {0}' -f $global:phaseCfg.sevecekBuildup.originalAdmin.login)
}





# SIG # Begin signature block
# MIIYMAYJKoZIhvcNAQcCoIIYITCCGB0CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCjzjO4XAlopVeo
# gaMfcZqNMxYuyjxSyNscbcV81qALu6CCE0cwggYEMIID7KADAgECAgoqHIRwAAEA
# AAB/MA0GCSqGSIb3DQEBCwUAMGwxCzAJBgNVBAYTAkNaMRcwFQYDVQQIEw5DemVj
# aCBSZXB1YmxpYzENMAsGA1UEBxMEQnJubzEQMA4GA1UEChMHU2V2ZWNlazEjMCEG
# A1UEAxMaU2V2ZWNlayBFbnRlcnByaXNlIFJvb3QgQ0EwHhcNMTkwNjExMTkyMzMy
# WhcNMjQwNjA5MTkyMzMyWjCBjzELMAkGA1UEBhMCQ1oxFzAVBgNVBAgTDkN6ZWNo
# IFJlcHVibGljMQ0wCwYDVQQHEwRCcm5vMRwwGgYDVQQKExNJbmcuIE9uZHJlaiBT
# ZXZlY2VrMRcwFQYDVQQDEw5PbmRyZWogU2V2ZWNlazEhMB8GCSqGSIb3DQEJARYS
# b25kcmVqQHNldmVjZWsuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
# AQEAnkjWNkK4FfUUN8iAN91ry+wsSn8cFKJbMnROAqTrx8t3H315p2/bUG2DosCF
# Odu0WcaTOLdm5obhT+/3O7BqpdcnlWKlSEz4AL9zQeCbe4++NObBVPBbPE16j9C4
# xELoXW/Ti86C2PEkN5azGUvxGxzQQ45g32OsEI+Bh05qHMkk3oQ6L8O0Fpd5W4e+
# L4HuKS3JOikNhhryTNPD9grF/0wXTzn94TrL1GohuaCPh8g9HOtMoDCd+ExnqV8q
# 4k60D37BOK1I81hYFIBn8MvCsjMRC5TK87MtI7aUUIeve5kopc8ZpxNti3F/+Puh
# 4UUxL3nKjfAM6HE0b7FqkfkRpwIDAQABo4IBgjCCAX4wEwYDVR0lBAwwCgYIKwYB
# BQUHAwMwDgYDVR0PAQH/BAQDAgbAMBsGCSsGAQQBgjcVCgQOMAwwCgYIKwYBBQUH
# AwMwHQYDVR0OBBYEFOKbNkkiAht2GxCISJMJxLg4gOC9MB0GA1UdEQQWMBSBEm9u
# ZHJlakBzZXZlY2VrLmNvbTAfBgNVHSMEGDAWgBQNnMgyfdUi8l9UfithS4FQ88Vs
# wDBSBgNVHR8ESzBJMEegRaBDhkFodHRwOi8vcGtpLnNldmVjZWsuY29tL0NBL1Nl
# dmVjZWslMjBFbnRlcnByaXNlJTIwUm9vdCUyMENBKDEpLmNybDCBhgYIKwYBBQUH
# AQEEejB4ME0GCCsGAQUFBzAChkFodHRwOi8vcGtpLnNldmVjZWsuY29tL0NBL1Nl
# dmVjZWslMjBFbnRlcnByaXNlJTIwUm9vdCUyMENBKDEpLmNydDAnBggrBgEFBQcw
# AYYbaHR0cDovL3BraS5zZXZlY2VrLmNvbS9vY3NwMA0GCSqGSIb3DQEBCwUAA4IC
# AQCfr6XDtt/O8OBr+X5l49UBLaJrjUXHkAHofdC7p7BLCXIs4GYIti1lf6pas5yB
# Q428aKITITq/vEHUTyiiyKtzVkafILWXXKPxy+zmmuw9odB3Hea4ECNpcaG8UNtz
# vMm1Dr0ZrkENhcv6I3tNhRr2AOE9AKOfnVEullFD/mZqfmaNkhpnl31jk7OMSUQc
# oY8qD6BDQP9371C10gJOmp57sHfPa4Vn5E4aNzn8+o9C9HI7nNagZF5BamKOFdR2
# ui7K3krMbTuDHo+ZcA9nHnzZqiVKpEBFu8lGv9Mf+GDb9yxz6EjV3xS2RcnywX2v
# z0VUt2NGno8LudrnWpgrRy4Sl7x6FwVVKtS/o7zFSIiHgntIKFv8urSKSTukCLFK
# Y9fBIDDlWFV1ZV1DNpNWxnexWIRv2AH7YlzKQCA4Rysn01hVeBGsWFkCr9J33LmV
# enQYpk9eoYMPRwAYg48r65wOOOzLvmyLSGllH88BMvmTQ9myXqwp6NDH1psljXTl
# PUbpf7w6IZwsY0dhGhP9iyqbcrGdK0Bnf8Za6Qdj3iXtwd1VgpatFZrxOM5KawCL
# pkYl1ABupbzNpWzmC+nfymqwbYiCogPt1vHOyF4EJ73ExVDCqXkpiNvFRqmu1eaZ
# IOdbPCdl00a9rk52NKqo/BUsw16TKsDEYTA/7ACbEsnERzCCBmowggVSoAMCAQIC
# EAMBmgI6/1ixa9bV6uYX8GYwDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UEBhMCVVMx
# FTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv
# bTEhMB8GA1UEAxMYRGlnaUNlcnQgQXNzdXJlZCBJRCBDQS0xMB4XDTE0MTAyMjAw
# MDAwMFoXDTI0MTAyMjAwMDAwMFowRzELMAkGA1UEBhMCVVMxETAPBgNVBAoTCERp
# Z2lDZXJ0MSUwIwYDVQQDExxEaWdpQ2VydCBUaW1lc3RhbXAgUmVzcG9uZGVyMIIB
# IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo2Rd/Hyz4II14OD2xirmSXU7
# zG7gU6mfH2RZ5nxrf2uMnVX4kuOe1VpjWwJJUNmDzm9m7t3LhelfpfnUh3SIRDsZ
# yeX1kZ/GFDmsJOqoSyyRicxeKPRktlC39RKzc5YKZ6O+YZ+u8/0SeHUOplsU/UUj
# joZEVX0YhgWMVYd5SEb3yg6Np95OX+Koti1ZAmGIYXIYaLm4fO7m5zQvMXeBMB+7
# NgGN7yfj95rwTDFkjePr+hmHqH7P7IwMNlt6wXq4eMfJBi5GEMiN6ARg27xzdPpO
# 2P6qQPGyznBGg+naQKFZOtkVCVeZVjCT88lhzNAIzGvsYkKRrALA76TwiRGPdwID
# AQABo4IDNTCCAzEwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0l
# AQH/BAwwCgYIKwYBBQUHAwgwggG/BgNVHSAEggG2MIIBsjCCAaEGCWCGSAGG/WwH
# ATCCAZIwKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMw
# ggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgA
# aQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQA
# ZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcA
# aQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBlAGwA
# eQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkA
# YwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAgAGEA
# cgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIA
# eQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wCwYJYIZIAYb9bAMVMB8GA1UdIwQYMBaA
# FBUAEisTmLKZB+0e36K+Vw0rZwLNMB0GA1UdDgQWBBRhWk0ktkkynUoqeRqDS/Qe
# icHKfTB9BgNVHR8EdjB0MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v
# RGlnaUNlcnRBc3N1cmVkSURDQS0xLmNybDA4oDagNIYyaHR0cDovL2NybDQuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0EtMS5jcmwwdwYIKwYBBQUHAQEE
# azBpMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYB
# BQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy
# ZWRJRENBLTEuY3J0MA0GCSqGSIb3DQEBBQUAA4IBAQCdJX4bM02yJoFcm4bOIyAP
# gIfliP//sdRqLDHtOhcZcRfNqRu8WhY5AJ3jbITkWkD73gYBjDf6m7GdJH7+IKRX
# rVu3mrBgJuppVyFdNC8fcbCDlBkFazWQEKB7l8f2P+fiEUGmvWLZ8Cc9OB0obzpS
# CfDscGLTYkuw4HOmksDTjjHYL+NtFxMG7uQDthSr849Dp3GdId0UyhVdkkHa+Q+B
# 0Zl0DSbEDn8btfWg8cZ3BigV6diT5VUW8LsKqxzbXEgnZsijiwoc5ZXarsQuWaBh
# 3drzbaJh6YoLbewSGL33VVRAA5Ira8JRwgpIr7DUbuD0FAo6G+OPPcqvao173NhE
# MIIGzTCCBbWgAwIBAgIQBv35A5YDreoACus/J7u6GzANBgkqhkiG9w0BAQUFADBl
# MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
# d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
# b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMjExMTEwMDAwMDAwWjBiMQswCQYDVQQG
# EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
# cnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBBc3N1cmVkIElEIENBLTEwggEiMA0G
# CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDogi2Z+crCQpWlgHNAcNKeVlRcqcTS
# QQaPyTP8TUWRXIGf7Syc+BZZ3561JBXCmLm0d0ncicQK2q/LXmvtrbBxMevPOkAM
# Rk2T7It6NggDqww0/hhJgv7HxzFIgHweog+SDlDJxofrNj/YMMP/pvf7os1vcyP+
# rFYFkPAyIRaJxnCI+QWXfaPHQ90C6Ds97bFBo+0/vtuVSMTuHrPyvAwrmdDGXRJC
# geGDboJzPyZLFJCuWWYKxI2+0s4Grq2Eb0iEm09AufFM8q+Y+/bOQF1c9qjxL6/s
# iSLyaxhlscFzrdfx2M8eCnRcQrhofrfVdwonVnwPYqQ/MhRglf0HBKIJAgMBAAGj
# ggN6MIIDdjAOBgNVHQ8BAf8EBAMCAYYwOwYDVR0lBDQwMgYIKwYBBQUHAwEGCCsG
# AQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIMIIB0gYDVR0gBIIB
# yTCCAcUwggG0BgpghkgBhv1sAAEEMIIBpDA6BggrBgEFBQcCARYuaHR0cDovL3d3
# dy5kaWdpY2VydC5jb20vc3NsLWNwcy1yZXBvc2l0b3J5Lmh0bTCCAWQGCCsGAQUF
# BwICMIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAgAG8AZgAgAHQAaABpAHMAIABDAGUA
# cgB0AGkAZgBpAGMAYQB0AGUAIABjAG8AbgBzAHQAaQB0AHUAdABlAHMAIABhAGMA
# YwBlAHAAdABhAG4AYwBlACAAbwBmACAAdABoAGUAIABEAGkAZwBpAEMAZQByAHQA
# IABDAFAALwBDAFAAUwAgAGEAbgBkACAAdABoAGUAIABSAGUAbAB5AGkAbgBnACAA
# UABhAHIAdAB5ACAAQQBnAHIAZQBlAG0AZQBuAHQAIAB3AGgAaQBjAGgAIABsAGkA
# bQBpAHQAIABsAGkAYQBiAGkAbABpAHQAeQAgAGEAbgBkACAAYQByAGUAIABpAG4A
# YwBvAHIAcABvAHIAYQB0AGUAZAAgAGgAZQByAGUAaQBuACAAYgB5ACAAcgBlAGYA
# ZQByAGUAbgBjAGUALjALBglghkgBhv1sAxUwEgYDVR0TAQH/BAgwBgEB/wIBADB5
# BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0
# LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0Rp
# Z2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0
# cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNy
# bDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl
# ZElEUm9vdENBLmNybDAdBgNVHQ4EFgQUFQASKxOYspkH7R7for5XDStnAs0wHwYD
# VR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQEFBQADggEB
# AEZQPsm3KCSnOB22WymvUs9S6TFHq1Zce9UNC0Gz7+x1H3Q48rJcYaKclcNQ5IK5
# I9G6OoZyrTh4rHVdFxc0ckeFlFbR67s2hHfMJKXzBBlVqefj56tizfuLLZDCwNK1
# lL1eT7EF0g49GqkUW6aGMWKoqDPkmzmnxPXOHXh2lCVz5Cqrz5x2S+1fwksW5Etw
# TACJHvzFebxMElf+X+EevAJdqP77BzhPDcZdkbkPZ0XN1oPt55INjbFpjE/7WeAj
# D9KqrgB87pxCDs+R1ye3Fu4Pw718CqDuLAhVhSK46xgaTfwqIa1JMYNHlXdx3LEb
# S0scEJx3FMGdTy9alQgpECYxggQ/MIIEOwIBATB6MGwxCzAJBgNVBAYTAkNaMRcw
# FQYDVQQIEw5DemVjaCBSZXB1YmxpYzENMAsGA1UEBxMEQnJubzEQMA4GA1UEChMH
# U2V2ZWNlazEjMCEGA1UEAxMaU2V2ZWNlayBFbnRlcnByaXNlIFJvb3QgQ0ECCioc
# hHAAAQAAAH8wDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAA
# oQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4w
# DAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgK2n96QiNoFvCFBC58grIKtKq
# ysUF9oRjFFzYV0Ffwu0wDQYJKoZIhvcNAQEBBQAEggEAaCQK1Bg5jB+TgyfOeauR
# 4pSXfbOnoNWuWvMp+nAARhWglN0/0414KHK+lEpfaB4TZJpMqBrSwnyp6AG93cdX
# 9ljdWzE1cqIP3SFnf0h9GiVnJq5ZBbBxBqlj8PfbZzF24fBB1pTg/WXI/wlT8cKY
# mFFb4TnbMTmfjlyIPNxbcPaVPcFBJ6vJ1paj+aTkU+PLYLC0dSVg04GsZ2IIF53X
# 2N6NkoEVW4/lghh56G6FdijfC/0FvGTIWVlOnVwxR67W73Fhm5Q+n31EuA2J6Tlr
# owlUOOYTIpd5oxTXSj2mywRJH9y2c9GArQFFxtZQx4kxqGbgto2SuU3szRBcSGsU
# YKGCAg8wggILBgkqhkiG9w0BCQYxggH8MIIB+AIBATB2MGIxCzAJBgNVBAYTAlVT
# MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
# b20xITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMQIQAwGaAjr/WLFr
# 1tXq5hfwZjAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAc
# BgkqhkiG9w0BCQUxDxcNMTkwNjEyMTYxOTM1WjAjBgkqhkiG9w0BCQQxFgQUVFut
# hvA/djLzl7ubhWZstUxQ9I0wDQYJKoZIhvcNAQEBBQAEggEAR165mv0z2c4WJe4y
# kkUexgOfHfF3aY0V1TXbBils/BzJ76P9Z0YyIMjhs8UoxnNpUlYycT2j74QdhTcN
# FhX1ZGcOJtJO6nAAFC5V8HHT6B3zWHTt7MINJhmr6n/yp7rvoe+sRMKJ7/NQfd7L
# qIEFEY4QlWwobzVlhDsDkq9nD0izE2ETRvdIY+FslrdS/ekBkCYkHNf9GpCgiQD6
# Li9RU+JIJtb6oM8yA+Lm5Sp1Rt578xaYa5NR/KP6P7bQsq6OdEkvY/xAD5YmKVtJ
# FGVC69+kx/DxZMIFuid/glS6A5f4L4d4zV445boGtAXpd3BoW6wkD89gDvGiRpBR
# UNyteA==
# SIG # End signature block