Public/Connectors.ps1
|
$ModuleVersion = $myInvocation.MyCommand.Version <# .SYNOPSIS Retrieves existing SEPPmail Exchange Online connectors. .DESCRIPTION Gets information about the SEPPmail inbound and outbound connectors in Exchange Online. SEPPmail uses 2 connectors to transfer messages between the SEPPmail Appliance and Exchange Online. This cmdlet displays the current configuration and status of these connectors. .PARAMETER IncludeTestModeConnectors Includes connectors that are in test mode in the output. Test mode connectors are typically used for testing configurations before going live. .EXAMPLE Get-SM365Connectors Retrieves and displays the SEPPmail inbound and outbound connectors. .EXAMPLE Get-SM365Connectors -IncludeTestModeConnectors Retrieves SEPPmail connectors including those in test mode. .OUTPUTS System.Object Returns connector objects with properties: Name, Enabled, WhenCreated, SmartHosts (outbound), TlsSenderCertificateName (inbound) .NOTES Requires an active Exchange Online PowerShell session. .LINK https://docs.seppmail.com/ch-en/04_com_powershell.html #> function Get-SM365Connectors { [CmdletBinding()] Param ( [Switch]$IncludeTestModeConnectors ) if (!(Test-SM365ConnectionStatus)) { throw [System.Exception] "You're not connected to Exchange Online - please connect prior to using this CmdLet" } else { Write-Information "Connected to Exchange Organization `"$Script:ExODefaultDomain`"" -InformationAction Continue $inbound = Get-SM365InboundConnectorSettings $outbound = Get-SM365OutboundConnectorSettings if ($IncludeTestModeConnectors) { Get-OutboundConnector -IncludeTestModeConnectors:$true |where-object {$_.TestMode -eq $true}|select-object Name,Enabled,WhenCreated,SmartHosts } if (Get-OutboundConnector -outVariable obc | Where-Object Identity -eq $($outbound.Name)) { $obc | Where-Object Identity -eq $($outbound.Name) |select-object Name,Enabled,WhenCreated,SmartHosts } else { Write-Warning "No SEPPmail Outbound Connector with name `"$($outbound.Name)`" found" } if (Get-InboundConnector -outVariable ibc | Where-Object Identity -eq $($inbound.Name)) { $ibc|select-object Name,Enabled,WhenCreated,TlsSenderCertificateName } else { Write-Warning "No SEPPmail Inbound Connector with Name `"$($inbound.Name)`" found" } } } <# .SYNOPSIS Creates SEPPmail Exchange Online connectors for inbound and outbound mail flow. .DESCRIPTION SEPPmail uses 2 connectors to transfer messages between SEPPmail Appliance and Exchange Online. This cmdlet creates both the inbound and outbound connectors with the specified configuration. The cmdlet will: - Create an outbound connector to route mails from Exchange Online to the SEPPmail Appliance - Create an inbound connector to receive mails from the SEPPmail Appliance - Configure TLS certificate validation for secure communication - Optionally add the SEPPmail IP to the anti-spam allow list - Support Certificate Based Connectors (CBC) for MSP setups The cmdlet checks for existing SEPPmail connectors and hybrid configurations before creating new ones. .PARAMETER SEPPmailFQDN The fully qualified domain name (FQDN) of the SEPPmail Appliance. This is used as the SmartHost for the outbound connector. Example: 'securemail.contoso.com' Aliases: FQDN, SMFQDN, SmartHost .PARAMETER TLSCertificateName The name of the TLS certificate used by the SEPPmail Appliance. This can be different from the FQDN if using a wildcard certificate. Read the certificate name in your SEPPmail under SSL => Issued to => Name (CN). Example: '*.contoso.com' or 'securemail.contoso.com' Aliases: TLSCertName, CertName .PARAMETER CBCcertName The certificate name for the inbound connector in Certificate Based Connector (CBC) setups. Required for MSP environments where inbound and outbound connectors use different certificates. When specified, the outbound connector uses TLSCertificateName, and the inbound connector uses CBCcertName. Example: 'inbound.contoso.com' Aliases: SenderCertificateName .PARAMETER Disabled Creates the connectors in a disabled state. Use this if you want to review the configuration before enabling the connectors. .EXAMPLE New-SM365Connectors -SEPPmailFQDN 'securemail.contoso.com' -TLSCertificateName 'securemail.contoso.com' Creates inbound and outbound connectors using the same certificate name as the FQDN. .EXAMPLE New-SM365Connectors -SEPPmailFQDN 'securemail.contoso.com' -TLSCertificateName '*.contoso.com' Creates connectors using a wildcard certificate for TLS validation. .EXAMPLE New-SM365Connectors -SEPPmailFQDN 'securemail.contoso.com' -TLSCertificateName '*.contoso.com' -CBCcertName 'inbound.contoso.com' Creates connectors for an MSP setup with Certificate Based Connectors (CBC). The outbound connector uses the wildcard certificate '*.contoso.com'. The inbound connector uses the specific certificate 'inbound.contoso.com'. See https://docs.seppmail.com/de/09_ht_mso365_ssl_certificate.html?q=CBC for details on CBC setup. .EXAMPLE New-SM365Connectors -SEPPmailFQDN 'securemail.contoso.com' -TLSCertificateName '*.contoso.com' -Disabled Creates the connectors but leaves them disabled for review before activation. .NOTES - Requires an active Exchange Online PowerShell session - Will prompt for confirmation in hybrid environments - Automatically detects and handles existing SEPPmail connectors - Adds SEPPmail IP to anti-spam allow list by default .LINK https://docs.seppmail.com/ch-en/04_com_powershell.html #> function New-SM365Connectors { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'Medium', DefaultParameterSetName = 'FqdnTls' )] param ( [Parameter( Mandatory = $true, HelpMessage = 'FQDN of the SEPPmail Appliance, i.e. securemail.contoso.com', Position = 0 )] [ValidatePattern("^(?!:\/\/)(?=.{1,255}$)((.{1,63}\.){1,127}(?![0-9]*$)[a-z0-9-]+\.?)$")] [Alias('FQDN','SMFQDN','SmartHost')] [String] $SEPPmailFQDN, [Parameter( Mandatory = $true, HelpMessage = 'Name of the certificate if different from the SEPPmail-FQDN. Read the certificate name in your SEPPmail under SSL==>Issued to==>Name (CN)', Position = 1 )] [Alias('TLSCertName','CertName')] [String] $TLSCertificateName, [Parameter( Mandatory = $false, HelpMessage = 'MSP setup requires a second certificate', ParameterSetName = 'FqdnTls', Position = 2 )] [Alias('SenderCertificateName')] [string]$CBCcertName, [Parameter( Mandatory = $false, HelpMessage = 'Disable the connectors on creation' )] [switch]$Disabled #endregion ) begin { if(!(Test-SM365ConnectionStatus)) {throw [System.Exception] "You're not connected to Exchange Online - please connect prior to using this CmdLet"} Write-Information "Connected to Exchange Organization `"$Script:ExODefaultDomain`"" -InformationAction Continue #region collecting existing connectors Write-Verbose "Collecting existing connectors" $allInboundConnectors = Get-InboundConnector $allOutboundConnectors = Get-OutboundConnector Write-Verbose "Testing for hybrid Setup" $HybridInboundConn = $allInboundConnectors |Where-Object {(($_.Name -clike 'Inbound from *') -or ($_.ConnectorSource -clike 'HybridWizard'))} $HybridOutBoundConn = $allOutboundConnectors |Where-Object {(($_.Name -clike 'Outbound to *') -or ($_.ConnectorSource -clike 'HybridWizard'))} #endregion collecting existing connectors #region warn on hybrid if ($HybridInboundConn -or $HybridOutBoundConn) { Write-Warning "!!! - Hybrid Configuration detected - we assume you know what you are doing. Be sure to backup your connector settings before making any change." if($InteractiveSession) { Write-Verbose "Ask user to continue if Hybrid is found." Do { try { [ValidateSet('y', 'Y', 'n', 'N')]$hybridContinue = Read-Host -Prompt "Create SEPPmail connectors in hybrid environment ? (Y/N)" } catch {} } until ($?) if ($hybridContinue -eq 'n') { Write-Verbose "Exiting due to user decision." break } } else { # should we error out here, since connector creation might be dangerous? } } else { Write-Information "No Hybrid Connectors detected, seems to be a clean cloud-only environment" -InformationAction Continue } #endregion warn on hybrid } process { #region - Check existing Outbound Connector Write-Verbose "Read existing SEPPmail outbound connector" $existingSMOutboundConn = $allOutboundConnectors | Where-Object Name -like '`[SEPPmail`]*' # only $false if the user says so interactively [bool]$createOutBound = $true #Set Default Value if ($existingSMOutboundConn) { Write-Warning "Found existing SEPPmail outbound connector with name: `"$($existingSMOutboundConn.Name)`" created on `"$($existingSMOutboundConn.WhenCreated)`" pointing to SEPPmail `"$($existingSMOutboundConn.TlsDomain)`" " if($InteractiveSession) { [string] $tmp = $null Do { try { [ValidateSet('y', 'Y', 'n', 'N')]$tmp = Read-Host -Prompt "Shall we delete and recreate the outbound connector (will only work if no rules use it)? (Y/N)" break } catch {} } until ($?) if ($tmp -eq 'y') { $createOutbound = $true Write-Verbose "Removing existing Outbound Connector $($existingSMOutboundConn.Name) !" if ($PSCmdLet.ShouldProcess($($existingSMOutboundConn.Name), 'Removing existing SEPPmail Outbound Connector')) { $existingSMOutboundConn | Remove-OutboundConnector -Confirm:$false # user already confirmed action if (!$?) { throw $error[0] } } } else { Write-Warning "Leaving existing SEPPmail outbound connector `"$($existingSMOutboundConn.Name)`" untouched." $createOutbound = $false } } else { throw [System.Exception] "Outbound connector $($outbound.Name) already exists" } } else {Write-Verbose "No existing Outbound Connector found"} #endregion - Check existing Outbound Connector #region - Create Outbound Connector $outboundParam = Get-SM365OutboundConnectorSettings Write-verbose "if -disabled switch is used, the connector stays deactivated" if ($Disabled) { $outboundParam.Enabled = $false } Write-Verbose "FQDN and TLS, using $SEPPmailFQDN as SmartHost and $TLSCertificate as TlsDoman" $outboundParam.SmartHosts = $SEPPmailFQDN $outboundParam.TlsDomain = $TLSCertificateName if($createOutbound) { Write-Verbose "Creating SEPPmail Outbound Connector $($outboundParam.Name)!" if ($PSCmdLet.ShouldProcess($($outboundParam.Name), 'Creating Outbound Connector')) { Write-Verbose "Adding creation comment to outbound connector" $Now = Get-Date $outboundParam.Comment += "`n#Created with SEPPmail365 PowerShell Module version $ModuleVersion on $now" Write-Debug "Outbound Connector settings:" $outboundParam.GetEnumerator() | ForEach-Object{ Write-Debug "$($_.Key) = $($_.Value)" } [void](New-OutboundConnector @outboundParam) if(!$?) {throw $error[0]} } } #endregion - Create Outbound Connector #region - Check existing inbound connector Write-Verbose "Read existing SEPPmail Inbound Connector from Exchange Online" $existingSMInboundConn = $allInboundConnectors | Where-Object Name -like '`[SEPPmail`]*' # only $false if the user says so interactively [bool]$createInbound = $true if ($existingSMInboundConn) { Write-Warning "Found existing SEPPmail inbound Connector with name: `"$($existingSMInboundConn.Name)`", created `"$($existingSMInboundConn.WhenCreated)`" incoming SEPPmail is `"$($existingSMInboundConn.TlsSenderCertificateName)`"" if($InteractiveSession) { [string] $tmp = $null Do { try { [ValidateSet('y', 'Y', 'n', 'N')]$tmp = Read-Host -Prompt "Shall we delete and recreate the inbound connector (will only work if no rules use it)? (Y/N)" break } catch {} } until ($?) if ($tmp -eq 'y') { $createInbound = $true Write-Verbose "Removing existing SEPPmail Inbound Connector $($existingSMInboundConn.Name) !" if ($PSCmdLet.ShouldProcess($($existingSMInboundConn.Name), 'Removing existing SEPPmail inbound Connector')) { $existingSMInboundConn | Remove-InboundConnector -Confirm:$false # user already confirmed action if (!$?) { throw $error[0] } } } else { Write-Warning "Leaving existing SEPPmail Inbound Connector `"$($existingSMInboundConn.Name)`" untouched." $createInbound = $false } } else { throw [System.Exception] "Inbound connector $($inboundParam.Name) already exists" } } else {Write-Verbose "No existing Inbound Connector found"} #endregion - Check existing inbound connector #region - Create Inbound Connector Write-Verbose "Read Inbound Connector Settings" $inboundParam = Get-SM365InboundConnectorSettings Write-verbose "if -disabled switch is used, the connector stays deactivated" if ($disabled) { $inboundParam.Enabled = $false } if($createInbound) { Write-Verbose "Modify params based on Parameters given" # Due to ARC Setup of Exo tenants and EFSkipLastIP is $true by default, EFSKipIP´s must be empty in certain setups. # Configure inbound connector parameters based CBCCert given yes or no. if ($CBCcertName) { Write-Verbose "FQDN and CBC CertificateName, using $CBCcertName as TLSCertificateName" $inboundParam.TlsSenderCertificateName = $CBCcertName } else { Write-Verbose "FQDN and CertificateName specified, using $TLSCertificateName as TLSCertificateName" $inboundParam.TlsSenderCertificateName = $TLSCertificateName } Write-Verbose "Creating SEPPmail Inbound Connector $($inboundParam.Name)!" if ($PSCmdLet.ShouldProcess($($inboundParam.Name), 'Creating Inbound Connector')) { Write-Verbose "Adding creation comment to inbound connector" $Now = Get-Date $ModuleVersion = $myInvocation.MyCommand.Version $inboundParam.Comment += "`n#Created with SEPPmail365 PowerShell Module version $ModuleVersion on $now" Write-Debug "Inbound Connector settings:" $inboundParam.GetEnumerator() | Foreach-Object { Write-Debug "$($_.Key) = $($_.Value)" } [void](New-InboundConnector @inboundParam) if(!$?) { throw $error[0] } else { } } } #endRegion - Create InboundConnector } end { } } <# .SYNOPSIS Removes the SEPPmail inbound and outbound connectors from Exchange Online. .DESCRIPTION Removes both SEPPmail connectors (inbound and outbound) from Exchange Online. By default, this cmdlet also removes the SEPPmail Appliance IP address from the anti-spam allow list (Hosted Connection Filter Policy). The cmdlet will: - Remove the SEPPmail outbound connector - Remove the SEPPmail inbound connector - Remove the SEPPmail IP from the Hosted Connection Filter Policy IPAllowList (unless -leaveAntiSpamWhiteList is specified) .PARAMETER leaveAntiSpamWhiteList When specified, the SEPPmail Appliance IP address will remain in the anti-spam allow list even after the connectors are removed. Use this if you plan to recreate the connectors or want to keep the IP address whitelisted for other reasons. .EXAMPLE Remove-SM365Connectors Removes the SEPPmail connectors and removes the SEPPmail IP from the anti-spam allow list. .EXAMPLE Remove-SM365Connectors -leaveAntiSpamWhiteList Removes the connectors but keeps the SEPPmail Appliance IP address in the anti-spam allow list. .EXAMPLE Remove-SM365Connectors -WhatIf Shows what would happen if the cmdlet runs without actually removing the connectors. .NOTES - Requires an active Exchange Online PowerShell session - Supports -WhatIf and -Confirm parameters - The SEPPmail IP is determined from the inbound connector's SenderIPAddresses or TlsSenderCertificateName .LINK https://docs.seppmail.com/ch-en/04_com_powershell.html #> function Remove-SM365Connectors { [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='Medium')] Param ( [Switch]$leaveAntiSpamWhiteList ) if (!(Test-SM365ConnectionStatus)) { throw [System.Exception] "You're not connected to Exchange Online - please connect prior to using this CmdLet" } Write-Information "Connected to Exchange Organization `"$Script:ExODefaultDomain`"" -InformationAction Continue $inbound = Get-SM365InboundConnectorSettings $outbound = Get-SM365OutboundConnectorSettings $hcfp = Get-HostedConnectionFilterPolicy if($PSCmdlet.ShouldProcess($outbound.Name, "Remove SEPPmail outbound connector $($Outbound.Name)")) { if (Get-OutboundConnector | Where-Object Identity -eq $($outbound.Name)) { Remove-OutboundConnector $outbound.Name } else { Write-Warning 'No SEPPmail Outbound Connector found' } } if($PSCmdlet.ShouldProcess($inbound.Name, "Remove SEPPmail inbound connector $($inbound.Name)")) { $InboundConnector = Get-InboundConnector | Where-Object Identity -eq $($inbound.Name) if ($inboundConnector) { Write-Verbose 'Collect Inbound Connector IP for later WhiteListRemoval' [string]$InboundSEPPmailIP = $null if ($inboundConnector.SenderIPAddresses.count -le 1) { $InboundSEPPmailIP = $InboundConnector.SenderIPAddresses[0] } if ($inboundConnector.TlsSenderCertificateName) { try { $InboundSEPPmailIP = ([System.Net.Dns]::GetHostAddresses($($inboundConnector.TlsSenderCertificateName)).IPAddressToString) } catch { $InboundSEPPmailIP = $null } } Remove-InboundConnector $inbound.Name Write-Verbose "If Inbound Connector has been removed, remove also Whitelisted IPs" if ((!($leaveAntiSpamWhiteList)) -and (!(Get-InboundConnector | Where-Object Identity -eq $($inbound.Name))) -and ($InboundSEPPmailIP)) { Write-Verbose "Remove SEPPmail Appliance IP from Whitelist in 'Hosted Connection Filter Policy'" Write-Verbose "Collecting existing WhiteList" [System.Collections.ArrayList]$existingAllowList = $hcfp.IPAllowList Write-verbose "Removing SEPPmail Appliance IP $InboundSEPPmailIP from Policy $($hcfp.Id)" if ($existingAllowList) { $existingAllowList.Remove($InboundSEPPmailIP) Set-HostedConnectionFilterPolicy -Identity $hcfp.Id -IPAllowList $existingAllowList Write-Information "IP: $InboundSEPPmailIP removed from Hosted Connection Filter Policy $hcfp.Id" } } } else { Write-Warning 'No SEPPmail Inbound Connector found' } } } if (!(Get-Alias 'Set-SM365Connectors' -ErrorAction SilentlyContinue)) { New-Alias -Name Set-SM365Connectors -Value New-SM365Connectors } # SIG # Begin signature block # MIIVzAYJKoZIhvcNAQcCoIIVvTCCFbkCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBSMo0bDFMnvk9w # Fti8rgSvuPGzdVZuRBuTZXB3bSs5YaCCEggwggVvMIIEV6ADAgECAhBI/JO0YFWU # jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI # DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM # EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy # dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG # EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv # IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s # hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD # J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7 # P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme # me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz # T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q # RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz # mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc # QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T # OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/ # AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID # AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD # VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV # HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE # VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v # ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE # KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI # hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF # OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC # J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ # pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl # d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH # +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggYaMIIEAqADAgECAhBiHW0M # UgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYD # VQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENv # ZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5 # NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzAp # BgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0G # CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjI # ztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NV # DgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/3 # 6F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05Zw # mRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm # +qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUe # dyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz4 # 4MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBM # dlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQY # MBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritU # pimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNV # HSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsG # A1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1 # YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsG # AQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2Rl # U2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0 # aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURh # w1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0Zd # OaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajj # cw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNc # WbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalO # hOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJs # zkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z7 # 6mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5J # KdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHH # j95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2 # Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/ # L9Uo2bC5a4CH2RwwggZzMIIE26ADAgECAhAMcJlHeeRMvJV4PjhvyrrbMA0GCSqG # SIb3DQEBDAUAMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0 # ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYw # HhcNMjMwMzIwMDAwMDAwWhcNMjYwMzE5MjM1OTU5WjBqMQswCQYDVQQGEwJERTEP # MA0GA1UECAwGQmF5ZXJuMSQwIgYDVQQKDBtTRVBQbWFpbCAtIERldXRzY2hsYW5k # IEdtYkgxJDAiBgNVBAMMG1NFUFBtYWlsIC0gRGV1dHNjaGxhbmQgR21iSDCCAiIw # DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOapobQkNYCMP+Y33JcGo90Soe9Y # /WWojr4bKHbLNBzKqZ6cku2uCxhMF1Ln6xuI4ATdZvm4O7GqvplG9nF1ad5t2Lus # 5SLs45AYnODP4aqPbPU/2NGDRpfnceF+XhKeiYBwoIwrPZ04b8bfTpckj/tvenB9 # P8/9hAjWK97xv7+qsIz4lMMaCuWZgi8RlP6XVxsb+jYrHGA1UdHZEpunEFLaO9Ss # OPqatPAL2LNGs/JVuGdq9p47GKzn+vl+ANd5zZ/TIP1ifX76vorqZ9l9a5mzi/HG # vq43v2Cj3jrzIQ7uTbxtiLlPQUqkRzPRtiwTV80JdtRE+M+gTf7bT1CTvG2L3scf # YKFk7S80M7NydxV/qL+l8blGGageCzJ8svju2Mo4BB+ALWr+gBmCGqrM8YKy/wXR # tbvdEvBOLsATcHX0maw9xRCDRle2jO+ndYkTKZ92AMH6a/WdDfL0HrAWloWWSg62 # TxmJ/QiX54ILQv2Tlh1Al+pjGHN2evxS8i+XoWcUdHPIOoQd37yjnMjCN593wDzj # XCEuDABYw9BbvfSp29G/uiDGtjttDXzeMRdVCJFgULV9suBVP7yFh9pK/mVpz+aC # L2PvqiGYR41xRBKqwrfJEdoluRsqDy6KD985EdXkTvdIFKv0B7MfbcBCiGUBcm1r # fLAbs8Q2lqvqM4bxAgMBAAGjggGpMIIBpTAfBgNVHSMEGDAWgBQPKssghyi47G9I # ritUpimqF6TNDDAdBgNVHQ4EFgQUL96+KAGrvUgJnXwdVnA/uy+RlEcwDgYDVR0P # AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwSgYD # VR0gBEMwQTA1BgwrBgEEAbIxAQIBAwIwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9z # ZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQBMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6 # Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nQ0FSMzYu # Y3JsMHkGCCsGAQUFBwEBBG0wazBEBggrBgEFBQcwAoY4aHR0cDovL2NydC5zZWN0 # aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIzNi5jcnQwIwYIKwYB # BQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMB4GA1UdEQQXMBWBE3N1cHBv # cnRAc2VwcG1haWwuY2gwDQYJKoZIhvcNAQEMBQADggGBAHnWpS4Jw/QiiLQi2EYv # THCtwKsj7O3G7wAN7wijSJcWF7iCx6AoCuCIgGdWiQuEZcv9pIUrXQ6jOSRHsDNX # SvIhCK9JakZJSseW/SCb1rvxZ4d0n2jm2SdkWf5j7+W+X4JHeCF9ZOw0ULpe5pFs # IGTh8bmTtUr3yA11yw4vHfXFwin7WbEoTLVKiL0ZUN0Qk+yBniPPSRRlUZIX8P4e # iXuw7lh9CMaS3HWRKkK89w//18PjUMxhTZJ6dszN2TAfwu1zxdG/RQqvxXUTTAxU # JrrCuvowtnDQ55yXMxkkSxWUwLxk76WvXwmohRdsavsGJJ9+yxj5JKOd+HIZ1fZ7 # oi0VhyOqFQAnjNbwR/TqPjRxZKjCNLXSM5YSMZKAhqrJssGLINZ2qDK/CEcVDkBS # 6Hke4jWMczny8nB8+ATJ84MB7tfSoXE7R0FMs1dinuvjVWIyg6klHigpeEiAaSaG # 5KF7vk+OlquA+x4ohPuWdtFxobOT2OgHQnK4bJitb9aDazGCAxowggMWAgEBMGgw # VDELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDErMCkGA1UE # AxMiU2VjdGlnbyBQdWJsaWMgQ29kZSBTaWduaW5nIENBIFIzNgIQDHCZR3nkTLyV # eD44b8q62zANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCDy8q3uzIhhv1NfJrPpqkcx21tA # JvPMW908SQh52S3nbDANBgkqhkiG9w0BAQEFAASCAgBYRERiXjT24cudf3UpVbLl # 2xJcPOGA+5fKPZdqVqPeYjTVz4ZS6T+u/+vReSl4hBMf+76msQDa00UEr1+0X1Ah # uBL/Ej2qnIMbU6yA+WxmzROC8zp+Kfb+wt9KLIHBID06U5V60nwGLXlpbYiIY4/V # LJ7KncNakUJPbNzeJdc1CMh6zjo2pn7yx2G9C0Ip4QtfkhD8qPGxMwq9QGZ94+fy # cZwQFNneBRlbv+D9DiOYM0PmKz3/D7HjVEERqGmwwWNQZw3OLAuInoPRJV6DV3zL # 7gL9EmEc9JS6vAjkFU5Um7aIKyeAJDQZv3YqKpgg+7eQjZI2oXQ9qAzx9OHnWZ48 # kfpFnamQuVlmrx7iKyH0qPHL9U0OhFnrfEd2NlktecH8exaR1ltmAuHBI40lHQMo # KH0WrEkP4bhAOcnRbn1r394dILcNwPu40rVB0WLw98OY9fde8XyWFO8vZcUrmLZS # nwjDi5EHiK6OysqYgt4PAI6QnvxHm+/al4DnmmHxQG06/VmmmnTRUTE0mIy1fdCC # Q3CEzEvBd8dWqumjSs/b5TO3n/VUp61/dMlO94qiJt7oNoxTx1ftjo/zf6ZhrRnq # e6amQsN0Kgd/fAcoorGTzvqSJ+erECN+30gTwcJHx3F3hzsUBX65y1raOx94yBdk # y0psMSmx/uZKuzijtYZ1Ew== # SIG # End signature block |