ADLAB PowerShell source file: buildup-caweb.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 cawebLib
& "$libDir\lib-modifyActions.ps1"
& "$libDir\lib-buildup.ps1"

$vmName = $args[0]

DBG ('CA web services installation library.')
Redirect-TempToOutput
Load-VMConfig

Find-MarkedVolumes


$instanceName = $args[1]
DBG ('CA web instance to be installed: {0}' -f $instanceName)

$appTag = 'caweb'
$appConfig = $vmConfig.SelectSingleNode(('./{0}[@instance="{1}"]' -f $appTag, $instanceName))
$firstAppHost = Get-FirstAppHostInInstance $appTag $appConfig.instance 'waitParams'
$firstAppHostInInstance = Check-FirstAppHostInInstance $appTag $appConfig.instance

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


DBGIF $MyInvocation.MyCommand.Name { $global:thisOSVersionNumber -lt 6.2 }
if ($global:thisOSVersionNumber -lt 6.2) {

  DBG ('Incompatible OS version, exiting')
  exit
}

$websvcKind = $appConfig.kind
$websvcCACN = $appConfig.cn
DBG ('CA web service kind requested: {0} | ca = {1}' -f $websvcKind, $websvcCACN)
DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $websvcKind }

[string] $caFQDN = Get-FirstAppHostInInstance 'ca' $websvcCACN 'fqdn'
[System.Xml.XmlElement] $caNode = (Get-FirstAppHostInInstance 'ca' $websvcCACN 'vmConfig').ca
[string] $caReference = '{0}\{1}' -f $caFQDN, $websvcCACN

[System.Collections.ArrayList] $deList = @()
$rootDSE = Get-DE 'RootDSE' ([ref] $deList)
$configDN = GDES $rootDSE configurationNamingContext
$caEnrollmentDN = 'CN={0},CN=Enrollment Services,CN=Public Key Services,CN=Services,{1}' -f $websvcCACN, $configDN

DBG ('Will use CA reference: {0}' -f $caReference)
DBG ('CA configuration DN: {0}' -f $caEnrollmentDN)


Assert-Assembly 'System.Web'


if ($websvcKind -eq 'CWE') {

  DBG ('Going to provision Certificate Web Enrollment (CWE)')
  Install-WindowsFeaturesUniversal @('ADCS-Web-Enrollment', 'Web-Mgmt-Console', 'Web-Basic-Auth') $false $installMediaVolume $global:installISOVolume

  $webCert = Enroll-AppCertificate $appConfig.SelectSingleNode('./cert[@appTag="web"]/one') -reuseExisting $true

  $isCALocal = Contains-Safe $global:thisComputerLocalMachineNames $caFQDN

  DBG ('Going to configure the web service kind: {0} | {1} | local = {2}' -f $websvcKind, $caReference, $isCALocal)
  DBGSTART 

  if ($isCALocal) {

    $installRes = Install-AdcsWebEnrollment -Force -Verbose

  } else {

    $installRes = Install-AdcsWebEnrollment -CAConfig $caReference -Force -Verbos
  }

  DBGER $MyInvocation.MyCommand.Name $error
  DBGIF ('Invalid CWE configuration result: {0}' -f $installRes.ErrorId) { $installRes.ErrorId -ne 0 }

  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv" -section:system.webServer/security/authentication/basicAuthentication /enabled:"true" /commit:appHost'
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv" -section:system.webServer/security/authentication/basicAuthentication /logonMethod:"ClearText" /commit:appHost'
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv" -section:system.webServer/security/authentication/windowsAuthentication /enabled:"false" /commit:appHost'

  DBG ('Must bind the SSL certificate manually: {0}' -f $webCert)
  Ensure-HttpsCertificateBound -ip '0.0.0.0' -port 443 -webCert $webCert
}


if ($websvcKind -eq 'CEWS') {

  DBG ('Going to provision Certificate Enrollment Web Service (CEWS)')
  Install-WindowsFeaturesUniversal @('ADCS-Enroll-Web-Svc', 'Web-Mgmt-Console') $false $installMediaVolume $global:installISOVolume

  $webCert = Enroll-AppCertificate $appConfig.SelectSingleNode('./cert[@appTag="web"]/one') -reuseExisting $true

  DBG ('Going to configure the web service kind: {0}' -f $websvcKind)
  DBGSTART 
  $installRes = Install-AdcsEnrollmentWebService -ApplicationPoolIdentity -CAConfig $caReference -SSLCertThumbprint $webCert -AuthenticationType UserName -Force -Verbose
  DBGER $MyInvocation.MyCommand.Name $error
  DBGIF ('Invalid CEWS configuration result: {0}' -f $installRes.ErrorString) { Is-ValidString $installRes.ErrorString }

  $siteName = '{0}_CES_UsernamePassword' -f $websvcCACN
  $publicFQDN = $appConfig.publicFQDN
  $urlMuster = 'https://{0}/{1}/service.svc/CES'
  $oldUrl = $urlMuster -f $global:thisComputerFQDN, ([Uri]::EscapeDataString($siteName))
  $newUrl = $urlMuster -f $publicFQDN, ([Uri]::EscapeDataString($siteName))
  DBG ('Some parameters determined: site = {0} | publicFQDN = {1} | old = {2} | new = {3}' -f $siteName, $publicFQDN, $oldUrl, $newUrl)

  $installDir = Join-Path $env:WINDIR ('SystemData\CES\{0}' -f $siteName)
  $webConfig = Join-Path $installDir 'web.config'
  DBGIF ('Installation directory does not exist: {0} | {1}' -f $websvcKind, $installDir) { -not (Test-Path $installDir) }
  DBGIF ('Web.config does not exist: {0} | {1}' -f $websvcKind, $webConfig) { -not (Test-Path $webConfig) }

  DBG ('Going to reconfigure CEWS web.config file URI: {0}' -f $newUrl)

  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe ('set config "Default Web Site/{0}" -section:appSettings "/-[key=''URI'']"' -f $siteName)
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe ('set config "Default Web Site/{0}" -section:appSettings "/+[key=''URI'',value=''{1}'']"' -f $siteName, $newUrl)

  DBG ('Going to correct the AD URL value: {0}' -f $caEnrollmentDN)
  $caEnrollmentDE = Get-DE $caEnrollmentDN ([ref] $deList)

  [string[]] $existingReferences = $caEnrollmentDE.Properties['msPKI-Enrollment-Servers'].Value
  DBG ('Existing URL references for the CA CEWS: #{0} | {1}' -f $existingReferences.Length, ($existingReferences -join ' ; '))
  DBGIF $MyInvocation.MyCommand.Name { $existingReferences.Length -lt 1 }

  # Note: the msPKI-Enrollment-Servers format is actually priority-authentication-renewal-URL-unknown
  [string] $newUrlMuster = "1`n4`n0`n{0}`n0"
  [Collections.ArrayList] $newReferences = @()
  [void] $newReferences.Add(($newUrlMuster -f $newUrl))

  if ($existingReferences.Length -ge 1) {

    [bool] $oldUrlHit = $false
    [string] $oldUrlEntryToCheck = $newUrlMuster -f $oldUrl

    foreach ($oneExistingReference in $existingReferences) {

      DBG ('Checking one existing URL CEWS reference: {0} | {1}' -f $oneExistingReference, $oldUrlEntryToCheck)
      if (($oneExistingReference -eq $oldUrlEntryToCheck) -or (([Uri]::UnescapeDataString($oneExistingReference)) -eq $oldUrlEntryToCheck) -or ($oneExistingReference -eq ([Uri]::UnescapeDataString($oldUrlEntryToCheck)))) {

        DBG ('This one is the original URL CEWS reference: {0}' -f $oneExistingReference)
        DBGIF $MyInvocation.MyCommand.Name { $oldUrlHit }
        $oldUrlHit = $true
       
      } else {

        if ($newReferences -notcontains $oneExistingReference) {

          [void] $newReferences.Add($oneExistingReference)
        }
      }
    }

    DBGIF ('The current URL is not present in the CEWS reference list: {0} | seeked = {1}' -f $oldUrl, $oldUrlEntryToCheck) { -not $oldUrlHit }
  }

  DBG ('Put the CEWS reference list back into the AD: #{0} | {1}' -f $newReferences.Count, ($newReferences -join ' ; '))
  DBGSTART
  $caEnrollmentDE.PutEx($global:PutExUpdate, 'msPKI-Enrollment-Servers', @($newReferences))
  $caEnrollmentDE.SetInfo()
  DBGER $MyInvocation.MyCommand.Name $error
  DBGEND
}


if ($websvcKind -eq 'CEPWS') {

  DBG ('Going to provision Certificate Enrollment Policy Web Service (CEPWS)')
  Install-WindowsFeaturesUniversal @('ADCS-Enroll-Web-Pol', 'Web-Mgmt-Console') $false $installMediaVolume $global:installISOVolume

  $webCert = Enroll-AppCertificate $appConfig.SelectSingleNode('./cert[@appTag="web"]/one') -reuseExisting $true

  DBG ('CEPWS authentication URL token: {0}' -f $appConfig.auth)
  DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $appConfig.auth }

  switch ($appConfig.auth) {

    'UsernamePassword' { $authType = 'Username' }
    default { $authType = 'Username'; DBGIF ('Weird authentication type specified: {0}' -f $appConfig.auth) { $true } }
  }

  DBG ('Going to configure the web service kind: {0} | auth = {1}/{2}' -f $websvcKind, $appConfig.auth, $authType)
  DBGSTART 
  $installRes = Install-AdcsEnrollmentPolicyWebService -AuthenticationType $authType -SSLCertThumbprint $webCert -Confirm:$false -Force -Verbose
  DBGER $MyInvocation.MyCommand.Name $error
  DBGIF ('Invalid CEPWS configuration result: {0}' -f $installRes.ErrorString) { Is-ValidString $installRes.ErrorString }

  $siteName = 'ADPolicyProvider_CEP_{0}' -f $appConfig.auth
  $publicFQDN = $appConfig.publicFQDN
  $urlMuster = 'https://{0}/{1}/service.svc/CEP'
  $oldUrl = $urlMuster -f $global:thisComputerFQDN, $siteName #([Uri]::EscapeDataString($siteName))
  $newUrl = $urlMuster -f $publicFQDN, $siteName #([Uri]::EscapeDataString($siteName))
  DBG ('Some parameters determined: site = {0} | publicFQDN = {1} | old = {2} | new = {3}' -f $siteName, $publicFQDN, $oldUrl, $newUrl)

  $installDir = Join-Path $env:WINDIR ('SystemData\CEP\{0}' -f $siteName)
  $webConfig = Join-Path $installDir 'web.config'
  DBGIF ('Installation directory does not exist: {0} | {1}' -f $websvcKind, $installDir) { -not (Test-Path $installDir) }
  DBGIF ('Web.config does not exist: {0} | {1}' -f $websvcKind, $webConfig) { -not (Test-Path $webConfig) }

  DBG ('Going to reconfigure CEPWS web.config file URI: {0}' -f $newUrl)
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe ('set config "Default Web Site/{0}" -section:appSettings "/-[key=''URI'']"' -f $siteName)
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe ('set config "Default Web Site/{0}" -section:appSettings "/+[key=''URI'',value=''{1}'']"' -f $siteName, $newUrl)

  if (Is-EmptyString $appConfig.guid) {

    $cepwsGuid = ([guid]::NewGuid()).ToString('B')

  } else {

    DBG ('Will use the configured GUID for the CEPWS application: {0}' -f $appConfig.guid)
    DBGSTART
    $cepwsGuid = ([guid]::Parse($appConfig.guid)).ToString('B')
    DBGER $MyInvocation.MyCommand.Name $error
    DBGEND
  }

  DBG ('Going to reconfigure CEPWS web.config file ID: {0}' -f $cepwsGuid)
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe ('set config "Default Web Site/{0}" -section:appSettings "/-[key=''ID'']"' -f $siteName)
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe ('set config "Default Web Site/{0}" -section:appSettings "/+[key=''ID'',value=''{1}'']"' -f $siteName, $cepwsGuid)

  DBG ('Going to reconfigure CEPWS web.config file FriendlyName: {0}' -f $appConfig.display)
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe ('set config "Default Web Site/{0}" -section:appSettings "/-[key=''FriendlyName'']"' -f $siteName)
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe ('set config "Default Web Site/{0}" -section:appSettings "/+[key=''FriendlyName'',value=''{1}'']"' -f $siteName, $appConfig.display)
}



if ($websvcKind -eq 'NDES') {

  DBG ('Going to provision Network Device Enrollment Service (NDES)')
  Install-WindowsFeaturesUniversal @('ADCS-Device-Enrollment', 'Web-Mgmt-Console') $false $installMediaVolume $global:installISOVolume

  #
  #

  DBG ('Going to configure the web service kind: {0}' -f $websvcKind)

  #
  #

  $webCert = Enroll-AppCertificate $appConfig.SelectSingleNode('./cert[@appTag="web"]/one') -reuseExisting $true

  $raSubject = $appConfig.SelectSingleNode('./cert/one[@appTag="scepEnc"]').subject
  DBG ('RA certificate subject: {0}' -f $raSubject)
  DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $raSubject }

  $raSubjectElements = Split-Dn $raSubject
  $raSubjectName = $raSubjectElements | ? { $_.prefix -eq 'CN' } | select -First 1 | select -Expand value
  DBG ('RA subject name extracted: {0}' -f $raSubjectName)
  DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $raSubjectName }

  #
  #

  DBG ('First obtain the list of cert templates that the CA already publishes: {0}' -f $caEnrollmentDN)
  $caEnrollmentDE = Get-DE $caEnrollmentDN ([ref] $deList)
  [string[]] $originalCertTemplates = $caEnrollmentDE.Properties['certificateTemplates'].Value
  DBG ('The CA currenlty publishes certificate templates: #{0} | {1}' -f $originalCertTemplates.Count, ($originalCertTemplates -join ','))

  #
  #

  [hashtable] $raSubjectParameters = @{
      RAName = $raSubjectName
    }

  [string] $raSubjectEmail = $raSubjectElements | ? { $_.prefix -eq 'E' } | select -First 1 | select -Expand value
  [string] $raSubjectCompany = $raSubjectElements | ? { $_.prefix -eq 'O' } | select -First 1 | select -Expand value
  [string] $raSubjectDepartment = $raSubjectElements | ? { $_.prefix -eq 'OU' } | select -First 1 | select -Expand value
  [string] $raSubjectCity = $raSubjectElements | ? { $_.prefix -eq 'L' } | select -First 1 | select -Expand value
  [string] $raSubjectState = $raSubjectElements | ? { $_.prefix -eq 'S' } | select -First 1 | select -Expand value
  [string] $raSubjectCountry = $raSubjectElements | ? { $_.prefix -eq 'C' } | select -First 1 | select -Expand value
  
  if (Is-ValidString $raSubjectEmail) { [void] $raSubjectParameters.Add('RAEmail', $raSubjectEmail) }
  if (Is-ValidString $raSubjectCompany) { [void] $raSubjectParameters.Add('RACompany', $raSubjectCompany) }
  if (Is-ValidString $raSubjectDepartment) { [void] $raSubjectParameters.Add('RADepartment', $raSubjectDepartment) }
  if (Is-ValidString $raSubjectCity) { [void] $raSubjectParameters.Add('RACity', $raSubjectCity) }
  if (Is-ValidString $raSubjectState) { [void] $raSubjectParameters.Add('RAState', $raSubjectState) }
  if (Is-ValidString $raSubjectCountry) { [void] $raSubjectParameters.Add('RACountry', $raSubjectCountry) }

  [hashtable] $svcLogin = @{ }

  if (Is-EmptyString $appConfig.svc.login) {

    [void] $svcLogin.Add('ApplicationPoolIdentity', $true)

  } else {

    [void] $svcLogin.Add('ServiceAccountName', (Get-SAMLogin $appConfig.svc.login $appConfig.svc.domain))
    [void] $svcLogin.Add('ServiceAccountPassword', (ConvertTo-SecureString $appConfig.svc.pwd -AsPlainText -Force))

    DBG ('Make the account member of local IIS_IUSRS group as required though unnecessarily')
    Add-MemberLocalGroup -localGroup IIS_IUSRS -memberLogin $appConfig.svc.login -memberDomain $appConfig.svc.domain
  }

  $isCALocal = Contains-Safe $global:thisComputerLocalMachineNames $caFQDN
  DBG ('The CA is local: {0}' -f $isCALocal)

  if (-not $isCALocal) {

    $caReferenceOrNothing = @{ CAConfig = $caReference }
  
  } else {

    $caReferenceOrNothing = @{}
  }

  DBG ("Do the actual NDES service configuration: ca = {0} | local = {1} | raName = {2}`r`n{3}`r`n{4}" -f $caReference, $isCALocal, $raSubjectName, ($raSubjectParameters | Out-String), ($svcLogin | Out-String))
  DBGSTART 
  $installRes = Install-AdcsNetworkDeviceEnrollmentService -EncryptionProviderName 'Microsoft Enhanced RSA and AES Cryptographic Provider' -EncryptionKeyLength 2048 -SigningProviderName 'Microsoft Enhanced RSA and AES Cryptographic Provider' -SigningKeyLength 2048 -Confirm:$false -Force -Verbose @raSubjectParameters @svcLogin @caReferenceOrNothing
  DBGER $MyInvocation.MyCommand.Name $error
  DBGIF ('Invalid NDES configuration result: {0} | {1}' -f $installRes.ErrorId, $installRes.ErrorString) { ($installRes.ErrorId -ne 0) -or (Is-ValidString $installRes.ErrorString) }

  #
  #

  DBG ('Remove the automatically enrolled certificates before replacing them')
  [object[]] $autoEnrolledCerts = dir Cert:\LocalMachine\My | ? { $_.Subject -eq (($raSubjectElements | select -Expand rdn) -join ', ') }
  DBG ('Found autoenrolled certificates: #{0} | {1}' -f (Get-CountSafe $autoEnrolledCerts), (($autoEnrolledCerts | select -Expand Thumbprint) -join ', '))
  DBGIF $MyInvocation.MyCommand.Name { (Get-CountSafe $autoEnrolledCerts) -ne 2 }

  foreach ($oneAutoEnrolledCert in $autoEnrolledCerts) {

    [string] $oneKeyContainer = $oneAutoEnrolledCert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
    DBG ('One autoenrolled certificate key container: {0}' -f $oneKeyContainer)
    DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $oneKeyContainer }

    DBG ('Deleting the one autoenrolled certificate: {0} | {1}' -f $oneAutoEnrolledCert.Thumbprint, $oneKeyContainer)
    Run-Process certutil ('-delkey {0}' -f $oneKeyContainer)
    Run-Process certutil ('-delstore my {0}' -f $oneAutoEnrolledCert.Thumbprint)
  }

  #
  #

  $raEncryptionCert = Enroll-AppCertificate $appConfig.SelectSingleNode('./cert/one[@appTag="scepEnc"]')
  $raSigningCert = Enroll-AppCertificate $appConfig.SelectSingleNode('./cert/one[@appTag="scepSig"]')

  DBG ('RA encryption certificate enrolled: {0}' -f $raEncryptionCert)
  DBG ('RA signature certificate enrolled: {0}' -f $raSigningCert)

  DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $raEncryptionCert }
  DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $raSigningCert }

  DBG ('Get the IIS APPPOOL\SCEP SID')
  DBGSTART
  $iisPoolScepSID = (New-Object Security.Principal.NTAccount 'IIS APPPOOL\SCEP').Translate([Security.Principal.SecurityIdentifier]).Value
  DBGER $MyInvocation.MyCommand.Name $error
  DBGEND
  DBG ('Update the RA encryption certificate permissions for IIS APPPOOL\SCEP: {0}' -f $iisPoolScepSID)
  DBGIF $MyInvocation.MyCommand.Name { (Is-EmptyString $iisPoolScepSID) -or ($iisPoolScepSID -ne 'S-1-5-82-298598261-2050821656-3206418497-3728514927-3871840613') }

  Set-CertificatePrivateKeyPermissions -storePath Cert:\LocalMachine\My -thumbprint $raEncryptionCert -who 'IIS APPPOOL\SCEP' -access 'GR'
  Set-CertificatePrivateKeyPermissions -storePath Cert:\LocalMachine\My -thumbprint $raSigningCert -who 'IIS APPPOOL\SCEP' -access 'GR'

  #
  #

  DBG ('Verify the list of cert templates that the CA publishes after NDES configuration: {0}' -f $caEnrollmentDN)
  $caEnrollmentDE = Get-DE $caEnrollmentDN ([ref] $deList)
  [string[]] $afterNdesCertTemplates = $caEnrollmentDE.Properties['certificateTemplates'].Value
  DBG ('After NDES installation the CA publishes certificate templates: #{0} | {1}' -f $afterNdesCertTemplates.Count, ($afterNdesCertTemplates -join ','))
  DBGIF $MyInvocation.MyCommand.Name { (-not (Contains-Safe $afterNdesCertTemplates CEPEncryption)) -or (-not (Contains-Safe $afterNdesCertTemplates EnrollmentAgentOffline)) -or (-not (Contains-Safe $afterNdesCertTemplates IPSecIntermediateOffline)) }

  DBG ('Return the CA configuration of the original certificate template list')
  DBGSTART
  $caEnrollmentDE.PutEx($global:PutExUpdate, 'certificateTemplates', @($originalCertTemplates))
  $caEnrollmentDE.SetInfo()
  DBGER $MyInvocation.MyCommand.Name $error
  DBGEND

  #
  #

  DBG ('Verify existance of the template regitry values first')
  DBGSTART
  [string] $assertSigTemplate = (Get-ItemProperty -Path HKLM:\Software\Microsoft\Cryptography\MSCEP -Name SignatureTemplate).SignatureTemplate
  [string] $assertEncTemplate = (Get-ItemProperty -Path HKLM:\Software\Microsoft\Cryptography\MSCEP -Name EncryptionTemplate).EncryptionTemplate
  [string] $assertBothTemplate = (Get-ItemProperty -Path HKLM:\Software\Microsoft\Cryptography\MSCEP -Name GeneralPurposeTemplate).GeneralPurposeTemplate
  DBGER $MyInvocation.MyCommand.Name $error
  DBGEND
  DBGIF $MyInvocation.MyCommand.Name { $assertSigTemplate -ne 'IPSECIntermediateOffline' }
  DBGIF $MyInvocation.MyCommand.Name { $assertEncTemplate -ne 'IPSECIntermediateOffline' }
  DBGIF $MyInvocation.MyCommand.Name { $assertBothTemplate -ne 'IPSECIntermediateOffline' }

  DBG ('Template name prefix of the CA: prefix = {0}' -f $caNode.templateNamePrefix)
  [string] $templateSig = $appConfig.SelectSingleNode('./cert[@appTag="sig"]').template.Replace('$namePrefix$', $caNode.templateNamePrefix)
  [string] $templateEnc = $appConfig.SelectSingleNode('./cert[@appTag="enc"]').template.Replace('$namePrefix$', $caNode.templateNamePrefix)
  [string] $templateBoth = $appConfig.SelectSingleNode('./cert[@appTag="both"]').template.Replace('$namePrefix$', $caNode.templateNamePrefix)

  DBG ('Certificate templates required: sig = {0} | enc = {1} | both = {2}' -f $templateSig, $templateEnc, $templateBoth)
  DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $templateSig }
  DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $templateEnc }
  DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $templateBoth }
 
  if ((Is-ValidString $templateSig) -and (Is-ValidString $templateEnc) -and (Is-ValidString $templateBoth)) {

    DBG ('Configure the templates')
    DBGSTART
    Set-ItemProperty -Path HKLM:\Software\Microsoft\Cryptography\MSCEP -Name SignatureTemplate -Value $templateSig
    Set-ItemProperty -Path HKLM:\Software\Microsoft\Cryptography\MSCEP -Name EncryptionTemplate -Value $templateEnc
    Set-ItemProperty -Path HKLM:\Software\Microsoft\Cryptography\MSCEP -Name GeneralPurposeTemplate -Value $templateBoth
    DBGER $MyInvocation.MyCommand.Name $error
    DBGEND
  }

  #
  #

  DBG ('Fix some reasons why the NDES Admin does not have sufficient permissions and other issues')
  Set-RegPermissions 'SOFTWARE\Microsoft\Cryptography\CertificateTemplateCache' 'IIS APPPOOL\SCEP'

  #Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv/mscep_admin" -section:system.webServer/security/authentication/basicAuthentication /enabled:"true" /commit:appHost'
  #Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv/mscep_admin" -section:system.webServer/security/authentication/basicAuthentication /logonMethod:"ClearText" /commit:appHost'
  #Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv/mscep" -section:system.webServer/security/authentication/basicAuthentication /enabled:"true" /commit:appHost'
  #Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv/mscep" -section:system.webServer/security/authentication/basicAuthentication /logonMethod:"ClearText" /commit:appHost'
  #Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv/mscep" -section:system.webServer/security/authentication/windowsAuthentication /enabled:"false" /commit:appHost'

  # Note: the CERTREQ tool requires Windows Authentication or NTLM to connect to the mscep_admin site
  #       because it maintains the authenticated state on a TCP connection while with the Basic authentication it
  #       succeeds in authenticating once, but after a simple redirect to /mscep_admin/ it cannot authenticate again and
  #       returns 401 unauthorized
  #       Moreover the CERTREQ tool cannot generate requests over anything else than clean HTTP, you cannot provide it with https:// URI with -new parameter
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv/mscep_admin" -section:system.webServer/security/authentication/windowsAuthentication /~providers /commit:appHost'
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv/mscep_admin" -section:system.webServer/security/authentication/windowsAuthentication "/+providers.[value=''NTLM'']" /commit:appHost'

  # Note: /mscep does not need any authentication
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv/mscep" -section:system.webServer/security/authentication/windowsAuthentication /enabled:"false" /commit:appHost'

  # Note: this one is needed in order to work with a single admin password which gets encrypted with DPAPI into registry
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set apppool SCEP /processModel.loadUserProfile:"true"'

  #
  #
     
  Run-Process $env:WINDIR\system32\inetsrv\appcmd.exe 'set config "Default Web Site/certsrv/mscep" /section:system.webServer/security/requestFiltering /requestLimits.maxUrl:65534 /requestLimits.maxQueryString:65534 /commit:appHost'

  DBG ('Verify HTTP.SYS registry limits')
  DBGSTART
  [int] $httpsMaxField = 0
  $httpsMaxField = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\HTTP\Parameters -Name MaxFieldLength).MaxFieldLength
  [int] $httpsMaxRequest = 0
  $httpsMaxRequest = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\HTTP\Parameters -Name MaxRequestBytes).MaxRequestBytes
  #DBGER $MyInvocation.MyCommand.Name $error
  DBGEND
  DBGIF ('Non-default HTTP.SYS registry limits: maxField = {0} | maxRequest = {1}' -f $httpsMaxField, $httpsMaxRequest) { ($httpsMaxField -ne 0) -or ($httpsMaxRequest -ne 0) }

  DBG ('Set the new HTTP.SYS limits')
  DBGSTART
  Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\HTTP\Parameters -Name MaxFieldLength -Value 65534
  Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\HTTP\Parameters -Name MaxRequestBytes -Value 65534
  DBGER $MyInvocation.MyCommand.Name $error
  DBGEND

  DBG ('Must bind the SSL certificate manually: {0}' -f $webCert)
  Ensure-HttpsCertificateBound -ip '0.0.0.0' -port 443 -webCert $webCert
}


Dispose-List ([ref] $deList)


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


# SIG # Begin signature block
# MIIc/QYJKoZIhvcNAQcCoIIc7jCCHOoCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBiewu8xUqtYnXz
# uZxxY8pHN9ExGfftVGz0zd51yjnbbKCCGAQwggTlMIIDzaADAgECAhA5vUKe0oFu
# utW8yQO0umXnMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNVBAYTAklMMRYwFAYDVQQK
# Ew1TdGFydENvbSBMdGQuMSkwJwYDVQQLEyBTdGFydENvbSBDZXJ0aWZpY2F0aW9u
# IEF1dGhvcml0eTEjMCEGA1UEAxMaU3RhcnRDb20gQ2xhc3MgMiBPYmplY3QgQ0Ew
# HhcNMTYxMjAxMTU1MTEzWhcNMTgxMjAxMTU1MTEzWjBRMQswCQYDVQQGEwJDWjEa
# MBgGA1UECAwRSmlob21vcmF2c2t5IEtyYWoxDTALBgNVBAcMBEJybm8xFzAVBgNV
# BAMMDk9uZHJlaiBTZXZlY2VrMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
# AQEAr9E9hNj06bash9JX97kpsqK9Z/ciOBC6trI4nvlW9CPwhKBTb5wArhxLYZBG
# 9jWPWrdy1nL/cm5qMqBb/mogYwMwvEYWMvsIOOVn6HD9lVhNAovD6PHz0ziBBKIs
# zXTjyUPQaoIlIELovz967m78HJdUZJGxqhluAsS9o9/fEzA7XXUhUuqRKsetuZV/
# Asfh5sOveeoRsbeW4daTWvtz3TJuULL0w43LNVYJkd6LL8cegvLPVZUe1N7skvid
# EvntdlowQsJlqFdrH3SGKIPKA6ObcY8SZWkEQSbVBF8Kum1UT+jN0gm+84FwOg5W
# qKx+VvTK2ljVWnPrCD0Zzu2oIQIDAQABo4IBkzCCAY8wDgYDVR0PAQH/BAQDAgeA
# MBMGA1UdJQQMMAoGCCsGAQUFBwMDMAkGA1UdEwQCMAAwHQYDVR0OBBYEFG2vSo3N
# hQWILeUs0oN9XzHTejcfMB8GA1UdIwQYMBaAFD5ik5rXxxnuPo9JEIVVFSDjlIQc
# MG0GCCsGAQUFBwEBBGEwXzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Auc3RhcnRz
# c2wuY29tMDcGCCsGAQUFBzAChitodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0
# cy9zY2EuY29kZTIuY3J0MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuc3Rh
# cnRzc2wuY29tL3NjYS1jb2RlMi5jcmwwIwYDVR0SBBwwGoYYaHR0cDovL3d3dy5z
# dGFydHNzbC5jb20vMFEGA1UdIARKMEgwCAYGZ4EMAQQBMDwGCysGAQQBgbU3AQIF
# MC0wKwYIKwYBBQUHAgEWH2h0dHBzOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kw
# DQYJKoZIhvcNAQELBQADggEBAJuRiEvHtIYSpsmMkPhTz4QOOShN3p5KWdf8vm71
# A33CR9fds10d8D2B2aE+vjmHJ69GY0bbfg5oZY2Lsq2euL7Da5/hS8+6T3MEtD4h
# njfHV7mxmoSfFuy/KDipoV6uwhI+ksqchXYdUH+5uCQO0MOO8ITjAgzUQsnZ4UIB
# HBGeP+e+3ljxSYSXWdPIrgxdR971P/HhWSVfKNlmBgEKMQM5Jy0aAd4jxSl/AzdY
# t0+6pliFJ1peGhdFni2Fm8fu5oN68aTIrNtc5WY7Lzgf+sRTVeWORWS37+1zAD0m
# jzd8gyfBLxRuaRSfjYxny0rLXelAwfiA3ze2DU2Bfg9/rfcwggXYMIIDwKADAgEC
# AhBsO9J+3TyUnpWOKKmzx1egMA0GCSqGSIb3DQEBCwUAMH0xCzAJBgNVBAYTAklM
# MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUgRGlnaXRh
# bCBDZXJ0aWZpY2F0ZSBTaWduaW5nMSkwJwYDVQQDEyBTdGFydENvbSBDZXJ0aWZp
# Y2F0aW9uIEF1dGhvcml0eTAeFw0xNTEyMTYwMTAwMDVaFw0zMDEyMTYwMTAwMDVa
# MHUxCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSkwJwYDVQQL
# EyBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEjMCEGA1UEAxMaU3Rh
# cnRDb20gQ2xhc3MgMiBPYmplY3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
# ggEKAoIBAQC5FARY97LFhiwIMmCtCCbAgXe5aBnZFSsdGGnk2hqWBZcuZHkaqT1R
# M1rQd2r0ApNBw466cBur2Ht0b5jo17mpPmh2pImgIqwX1in4u7hhn9IH0GYOMEcg
# K3ACHv5zCRxxNLXifqmsqKfxjjpABnaSyvd4bO9YBXN9f4NQ6aJVAuMArpanxsJk
# e+P4WECVLk17v92CAN5JVaczI+baT/lgo5NVcTEkloCViSbIfU6ILeyhOSQZvpom
# MYk8eJqI0nimOTJJfmXangNDsrX8np+3lXD0+6rCZisXRWIaeffyTMHZ31Qj1D50
# WYdRtX5yev4WgaXoKJQN3lkgXUcytvyHAgMBAAGjggFaMIIBVjAOBgNVHQ8BAf8E
# BAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAy
# BgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9zZnNjYS5j
# cmwwZgYIKwYBBQUHAQEEWjBYMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5zdGFy
# dHNzbC5jb20wMAYIKwYBBQUHMAKGJGh0dHA6Ly9haWEuc3RhcnRzc2wuY29tL2Nl
# cnRzL2NhLmNydDAdBgNVHQ4EFgQUPmKTmtfHGe4+j0kQhVUVIOOUhBwwHwYDVR0j
# BBgwFoAUTgvvGqRAW6UXaYcwyjRoQ9BBrvIwPwYDVR0gBDgwNjA0BgRVHSAAMCww
# KgYIKwYBBQUHAgEWHmh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeTANBgkq
# hkiG9w0BAQsFAAOCAgEAY6U81bNtJyjY67pTrzAL6kpdEtX5mspw+kxjjNdNVH5G
# 6lLnhaEkIxqdpvY/Wdw+UdNtExs+N8efKPSwh2m/BxXj2fSeLMwXcwHFookScEER
# 8ez0quCNzioqNHac7LCXPEnQzbtG2FHlePKNDWh8eU6KxiAzNzIrIxPthinHGgLT
# BOACHQM2YTlD8YoU5oN3dLmBOqtH0BDMZoLcjEIoEW1zC+TnVb3yU1G0xub6gnN7
# lP50vbAiHJYrnywQiXaloBV8B9YYfe6ZgvjqxwufwFcMVyE3UmCuDTsOpjqDEKpJ
# 25s+FUdkie5VqCS1aaudLo31X+9UvP45pfgyRqzyfUnVEhH4ZXxlBWZMzj2Xov5+
# m/+H3kxYuFA5xdqdshj/Zx00S7PkCSF+8M1NCcvFgQwjIw61bZAjDBl3P3a8xNTX
# sb2CjFdiNKbT3LD6IGeIf0b/EbPf0FXdvBrxm0ofMOhnngdPolPYCtoOGtZPAVe/
# xeu+/ZyKv6TSHlshaUO0iYfsmbXnZ51vvt/kkjwms9/qPFxSuE0fjEfF7aQazwRE
# Df2hiVPR0pAhvShtM3oU4XreEFEUWEYHs25fYV4WMmxkUKSgmSmwRq45tvtGH4LT
# b5+cd+iLqK8rBQL0E6xaUjjGfsYx7bueIvqTvCkrQvoxMbn/qDHCiypowDVq6TAw
# ggZqMIIFUqADAgECAhADAZoCOv9YsWvW1ermF/BmMA0GCSqGSIb3DQEBBQUAMGIx
# CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
# dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0Et
# MTAeFw0xNDEwMjIwMDAwMDBaFw0yNDEwMjIwMDAwMDBaMEcxCzAJBgNVBAYTAlVT
# MREwDwYDVQQKEwhEaWdpQ2VydDElMCMGA1UEAxMcRGlnaUNlcnQgVGltZXN0YW1w
# IFJlc3BvbmRlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNkXfx8
# s+CCNeDg9sYq5kl1O8xu4FOpnx9kWeZ8a39rjJ1V+JLjntVaY1sCSVDZg85vZu7d
# y4XpX6X51Id0iEQ7Gcnl9ZGfxhQ5rCTqqEsskYnMXij0ZLZQt/USs3OWCmejvmGf
# rvP9Enh1DqZbFP1FI46GRFV9GIYFjFWHeUhG98oOjafeTl/iqLYtWQJhiGFyGGi5
# uHzu5uc0LzF3gTAfuzYBje8n4/ea8EwxZI3j6/oZh6h+z+yMDDZbesF6uHjHyQYu
# RhDIjegEYNu8c3T6Ttj+qkDxss5wRoPp2kChWTrZFQlXmVYwk/PJYczQCMxr7GJC
# kawCwO+k8IkRj3cCAwEAAaOCAzUwggMxMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMB
# Af8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMIIBvwYDVR0gBIIBtjCCAbIw
# ggGhBglghkgBhv1sBwEwggGSMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdp
# Y2VydC5jb20vQ1BTMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUAcwBl
# ACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBu
# AHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0
# AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQAIAB0
# AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUAbQBl
# AG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5
# ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAAaABl
# AHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMAsGCWCGSAGG/WwD
# FTAfBgNVHSMEGDAWgBQVABIrE5iymQftHt+ivlcNK2cCzTAdBgNVHQ4EFgQUYVpN
# JLZJMp1KKnkag0v0HonByn0wfQYDVR0fBHYwdDA4oDagNIYyaHR0cDovL2NybDMu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0EtMS5jcmwwOKA2oDSGMmh0
# dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRENBLTEuY3Js
# MHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl
# cnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v
# RGlnaUNlcnRBc3N1cmVkSURDQS0xLmNydDANBgkqhkiG9w0BAQUFAAOCAQEAnSV+
# GzNNsiaBXJuGziMgD4CH5Yj//7HUaiwx7ToXGXEXzakbvFoWOQCd42yE5FpA+94G
# AYw3+puxnSR+/iCkV61bt5qwYCbqaVchXTQvH3Gwg5QZBWs1kBCge5fH9j/n4hFB
# pr1i2fAnPTgdKG86Ugnw7HBi02JLsOBzppLA044x2C/jbRcTBu7kA7YUq/OPQ6dx
# nSHdFMoVXZJB2vkPgdGZdA0mxA5/G7X1oPHGdwYoFenYk+VVFvC7Cqsc21xIJ2bI
# o4sKHOWV2q7ELlmgYd3a822iYemKC23sEhi991VUQAOSK2vCUcIKSK+w1G7g9BQK
# Ohvjjz3Kr2qNe9zYRDCCBs0wggW1oAMCAQICEAb9+QOWA63qAArrPye7uhswDQYJ
# KoZIhvcNAQEFBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu
# YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQg
# QXNzdXJlZCBJRCBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTIxMTExMDAwMDAw
# MFowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UE
# CxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgQXNzdXJlZCBJ
# RCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6IItmfnKwkKV
# pYBzQHDSnlZUXKnE0kEGj8kz/E1FkVyBn+0snPgWWd+etSQVwpi5tHdJ3InECtqv
# y15r7a2wcTHrzzpADEZNk+yLejYIA6sMNP4YSYL+x8cxSIB8HqIPkg5QycaH6zY/
# 2DDD/6b3+6LNb3Mj/qxWBZDwMiEWicZwiPkFl32jx0PdAug7Pe2xQaPtP77blUjE
# 7h6z8rwMK5nQxl0SQoHhg26Ccz8mSxSQrllmCsSNvtLOBq6thG9IhJtPQLnxTPKv
# mPv2zkBdXPao8S+v7Iki8msYZbHBc63X8djPHgp0XEK4aH631XcKJ1Z8D2KkPzIU
# YJX9BwSiCQIDAQABo4IDejCCA3YwDgYDVR0PAQH/BAQDAgGGMDsGA1UdJQQ0MDIG
# CCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcD
# CDCCAdIGA1UdIASCAckwggHFMIIBtAYKYIZIAYb9bAABBDCCAaQwOgYIKwYBBQUH
# AgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5o
# dG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0
# AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1
# AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABp
# AGcAaQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBl
# AGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBo
# AGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAg
# AGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAg
# AGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wCwYJYIZIAYb9bAMVMBIGA1UdEwEB
# /wQIMAYBAf8CAQAweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8v
# b2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRp
# Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6
# MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy
# ZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9E
# aWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwHQYDVR0OBBYEFBUAEisTmLKZB+0e
# 36K+Vw0rZwLNMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqG
# SIb3DQEBBQUAA4IBAQBGUD7Jtygkpzgdtlspr1LPUukxR6tWXHvVDQtBs+/sdR90
# OPKyXGGinJXDUOSCuSPRujqGcq04eKx1XRcXNHJHhZRW0eu7NoR3zCSl8wQZVann
# 4+erYs37iy2QwsDStZS9Xk+xBdIOPRqpFFumhjFiqKgz5Js5p8T1zh14dpQlc+Qq
# q8+cdkvtX8JLFuRLcEwAiR78xXm8TBJX/l/hHrwCXaj++wc4Tw3GXZG5D2dFzdaD
# 7eeSDY2xaYxP+1ngIw/Sqq4AfO6cQg7PkdcntxbuD8O9fAqg7iwIVYUiuOsYGk38
# KiGtSTGDR5V3cdyxG0tLHBCcdxTBnU8vWpUIKRAmMYIETzCCBEsCAQEwgYkwdTEL
# MAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKTAnBgNVBAsTIFN0
# YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSMwIQYDVQQDExpTdGFydENv
# bSBDbGFzcyAyIE9iamVjdCBDQQIQOb1CntKBbrrVvMkDtLpl5zANBglghkgBZQME
# AgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEM
# BgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqG
# SIb3DQEJBDEiBCCaO+YtILOD7tGKGOmR4dCfSl+t/ijihj7bfCFDROkxUTANBgkq
# hkiG9w0BAQEFAASCAQCD209FqxxRjovuEpVgDgyKH7bXkHSgB02g6abS7WPMYIHf
# 4w26WJyGrxezCEcwSOohX/WWvoFciMBNWZFxtMcQIZouXygN/YOH3i9EUxmLl3hU
# uoGcNwrzwvHOYIAFIHkBtP8KseokcftVXmu28zXsov4LaaAOj0BbbesRGm6Wq37q
# oscrfmerxmlt0hsklyphQrC89Nc8lLGydPu69Q+vE/UpbtuwhEbrJSAXfJkWAOKb
# C5whfp4heZtmWRJvrnvcWoBiwBoqtIqcBwRHoKTRtuXblQ9/wCAVtHZrPRSg4pR6
# 3JgencXcXfnD4w57ftwJWep7wfRCMy4uqcke+rbcoYICDzCCAgsGCSqGSIb3DQEJ
# BjGCAfwwggH4AgEBMHYwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0
# IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNl
# cnQgQXNzdXJlZCBJRCBDQS0xAhADAZoCOv9YsWvW1ermF/BmMAkGBSsOAwIaBQCg
# XTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xODA4
# MjMwNTQ2MzNaMCMGCSqGSIb3DQEJBDEWBBR7Vmqxo32Q3JdYvJ+JmQSnqQ1j9zAN
# BgkqhkiG9w0BAQEFAASCAQAwMqvx6HHhzsE0/sBnKlRfuTgBceyI5O6DmyZvjGfe
# 1MmnQJgJkjGWvIBK9ZFpIBpnfWVAJckcXDpn8XUHXuwK4FC/rB6J9J2uG3Tuj5YH
# Syp4jonOcmPygNEHuuQZ1QL7QRGlZfeEzfCB4Fega49GyYoC2FhNgiXYxrQTlRwz
# k/2zRqMTRYTO5yFESHuXFSRq2uwhKEuibsHgzbO7ll/omPW5b27og6OYi066gg4y
# VeS5+EvCOliAXmw8wLie074C8NnT8tavW1UTeNw0fmk0iwr0bybulvwJsPv1B5Ho
# L9yufs2eyOeM3sBa6yah++7+YeH/PjagVX0BuFqvy38J
# SIG # End signature block