AzureValidation/Microsoft.AzureStack.AzureValidation.psm1
#Requires -RunAsAdministrator $erroractionpreference = 'stop' Import-LocalizedData LocalizedData -BaseDirectory $PSScriptRoot -Filename Microsoft.AzureStack.AzureValidation.Strings.psd1 Import-Module $PSSCriptRoot\Microsoft.AzureStack.AzureValidation.Internal.psm1 -force Import-Module $PSScriptRoot\..\Microsoft.AzureStack.ReadinessChecker.Utilities.psm1 -Force function Invoke-AzsRegistrationValidation { <# .SYNOPSIS Validates Credential and Subscription for Azure Stack Registration. .DESCRIPTION Validate registration before you begin an Azure Stack deployment: Validates the Azure subscription provided is a supported type. Subscriptions must be a Cloud Service Provider (CSP) or Enterprise Agreement (EA). The account provided can sign in to Azure and is a subscription owner. .EXAMPLE PS C:\> Invoke-AzsRegistrationValidation -RegistrationAccount $credential -RegistrationSubscriptionID 3f764e1c-d0ab-49e3-99aa-44124d56dd2d -AzureEnvironment AzureCloud Validates Credential and Subscription for Azure Stack Registration. .EXAMPLE PS C:\> Invoke-AzsRegistrationValidation -RegistrationAccount $credential -RegistrationSubscriptionID 3f764e1c-d0ab-49e3-99aa-44124d56dd2d -AzureEnvironment CustomCloud -CustomCloudARMEndpoint 'https://management.azurecloud.contoso.com' Validates Credential and Subscription for Azure Stack Registration against custom azure cloud. .PARAMETER RegistrationAccount Specifies the Registration Account intended to be used for Azure Stack registration. .PARAMETER RegistrationSubscriptionID Specifies the Registration Subscription ID intended to be used for Azure Stack registration. .PARAMETER AzureEnvironment Specifies the instance of Azure Services containing the accounts, directories and subscriptions intended to be used for Azure Stack deployment and registration. .PARAMETER CustomCloudARMEndpoint Specifies the custom ARM Endpoint for a custom Azure Environment. .PARAMETER DeploymentDataJSONPath Specifies the Azure Stack deployment deployment data JSON configuration file. Generally only available to the deployment team. .PARAMETER ForceTLS12 Force the use of TLS 1.2, true by default .PARAMETER OutputPath Specifies custom path to save Readiness JSON report and Verbose log file. .PARAMETER CleanReport Specifies whether to purge the existing report and start again with a clean report. Execution history and validation data is lost for all Readiness Checker validations. .LINK Azure Stack Registration Validation - https://aka.ms/AzsValidateAzureRegistration Azure Stack Readiness Checker - https://aka.ms/AzsReadinessChecker #> [OutputType([Array])] [CmdletBinding()] Param( [Parameter(Mandatory = $true, ParameterSetName = 'RegistrationJSON')] [ValidateScript( {Test-Path $_ -Include *.json})] [string] $deploymentDataJSONPath, [Parameter(Mandatory = $false, ParameterSetName = 'Registration')] [ValidateSet('AzureCloud', 'AzureChinaCloud', 'AzureGermanCloud', 'AzureUSGovernment','CustomCloud')] [string] $AzureEnvironment = 'AzureCloud', [Parameter(Mandatory = $false, ParameterSetName = 'Registration')] [Parameter(Mandatory = $false, ParameterSetName = 'RegistrationJSON')] [string] $CustomCloudARMEndpoint, [Parameter(Mandatory = $true, ParameterSetName = 'RegistrationJSON')] [Parameter(Mandatory = $true, ParameterSetName = 'Registration')] [pscredential] $RegistrationAccount, [Parameter(Mandatory = $true, ParameterSetName = 'Registration')] [Parameter(Mandatory = $true, ParameterSetName = 'RegistrationJSON')] [string] $RegistrationSubscriptionID, [Parameter(Mandatory = $false, HelpMessage = "Force the use of TLS 1.2, true by default")] [bool]$ForceTLS12 = $true, [Parameter(HelpMessage = "Directory path for log and report output")] [string]$OutputPath = "$ENV:TEMP\AzsReadinessChecker", [Parameter(HelpMessage = "Remove all previous progress and create a clean report")] [switch]$CleanReport = $false ) try { $thisFunction = $MyInvocation.MyCommand.Name $GLOBAL:OutputPath = $OutputPath Import-Module $PSScriptRoot\..\Microsoft.AzureStack.ReadinessChecker.Reporting.psm1 -Force # Check Azure Module exist and prompt to install if not if (-not (Get-Module AzureRM.Profile -ListAvailable)) { Write-AzsReadinessLog -message ($LocalizedData.MissingAzureRMPSModules) -function $thisFunction -type Error throw $LocalizedData.MissingAzureRMPSModules } Import-Module $PSSCriptRoot\AzureADConfiguration.psm1 -Force -Global Write-Header -invocation $MyInvocation -params $PSBoundParameters # Parse DeploymentData JSON if ($PSCmdlet.ParameterSetName -eq 'RegistrationJSON') { $deploymentDataJSON = ConvertTo-DeploymentData -path $deploymentDataJSONPath $AzureEnvironment = $deploymentDataJSON.DeploymentData.InfraAzureEnvironment } # If user specifies custom azure environment, overwrite the AzureEnvironment as the json path if ($CustomCloudARMEndpoint) { Write-AzsReadinessLog -message ($LocalizedData.UserSpecifiedCustomAzureEnvironment -f $CustomCloudARMEndpoint) -function $thisFunction -type Info $AzureEnvironment = 'CustomCloud' } # Get/Clean Existing Report $readinessReport = Get-AzsReadinessProgress -clean:$CleanReport $readinessReport = Add-AzsReadinessCheckerJob -report $readinessReport $registrationOutput = @{} # Force Security Profile to TLS1.2 if ($ForceTLS12) { # Change Security Protocol to TLS1.2 for the session and track for clean up later. $restoreSecurityProtocol = [Net.ServicePointManager]::SecurityProtocol $tempSecurityProtocol = [Net.SecurityProtocolType]::Tls12 Set-SecurityProtocol -securityProtocol $tempSecurityProtocol } Write-Host "Checking Registration Requirements: " -nonewline $tenantid = Get-RegistrationTenantId -Credential $RegistrationAccount -Subscriptionid $RegistrationSubscriptionID -AzureEnvironment $AzureEnvironment -CustomCloudARMEndpoint $CustomCloudARMEndpoint if ($null -eq $tenantid.tenantid) { throw "{0}" -f $tenantid.errorDetails } else { $registrationSubscription = Get-AzureSubscriptionDetail -tenantid $tenantid.tenantid -subscriptionid $RegistrationSubscriptionID -credential $RegistrationAccount -AzureEnvironment $AzureEnvironment -CustomCloudARMEndpoint $CustomCloudARMEndpoint } ## expand test-azsregostrationaccount to test graph endpoint if (-not $registrationSubscription.errordetails) { $registrationOutput = Test-AzsRegistrationAccount -subscription $registrationSubscription.subscription -subscriptionId $RegistrationSubscriptionID -tenantId $tenantid.tenantid -Credential $RegistrationAccount -AzureEnvironment $AzureEnvironment -CustomCloudARMEndpoint $CustomCloudARMEndpoint if ($registrationOutput.result -ne 'OK') { Write-Host "Fail " -foregroundColor Red Write-Host ("Error Details for registration account {0}:" -f $registrationAccount.Username) $registrationOutput.errorDetails | ForEach-Object {Write-Host "$_" -foregroundcolor Yellow} Write-Host ("Additional help URL {0}" -f "https://aka.ms/AzsRemediateRegistration") } else { Write-Host "OK" -foregroundColor Green } } else { Write-Host "Fail " -foregroundColor Red Write-Host ("Error Details for registration account {0}:" -f $registrationAccount.Username) $registrationSubscription.errorDetails | ForEach-Object {Write-Host "$_" -foregroundcolor Yellow} Write-Host ("Additional help URL {0}" -f "https://aka.ms/AzsRemediateRegistration") } $registrationOutput.Add('SubscriptionDetail', $registrationSubscription) } catch { Write-Host "Fail " -foregroundColor Red $errorDetail = ("Checking Registration failed with: {0}" -f $_.exception.Message) Write-Host ("Error Details for registration account {0}:" -f $registrationAccount.Username) $errorDetail | ForEach-Object {Write-Host "$_" -foregroundcolor Yellow} } finally { # Write results to readiness report $readinessReport.AzureValidation.AzureRegistration = $registrationOutput $readinessReport = Close-AzsReadinessCheckerJob -report $readinessReport Write-AzsReadinessProgress -report $readinessReport Write-AzsReadinessReport -report $readinessReport # Remove global variables Remove-Variable -Name OutputPath # Restore TLS back to default if ($ForceTLS12) { Set-SecurityProtocol -securityProtocol $restoreSecurityProtocol } Write-Footer -invocation $MyInvocation } } function Invoke-AzsAzureIdentityValidation { <# .SYNOPSIS Validates Service Administrator and AAD Tenant for Azure Stack Identity .DESCRIPTION Validate identity before you begin an Azure Stack Deployment Validates Service Administrator provided is a Global Administrator of the AAD Tenant directory provided. .EXAMPLE PS C:\> Invoke-AzsAzureIdentityValidation -AADServiceAdministrator $credential -AzureEnvironment AzureCloud -AADDirectoryTenantName contoso.onmicrosoft.com Validates Service Administrator and AAD Tenant for Azure Stack Identity .EXAMPLE PS C:\> Invoke-AzsAzureIdentityValidation -AADServiceAdministrator $credential -AzureEnvironment CustomCloud -CustomCloudARMEndpoint 'https://management.azurecloud.contoso.com' -AADDirectoryTenantName contoso.onmicrosoft.com Validates Service Administrator and AAD Tenant for Azure Stack Identity .PARAMETER AADServiceAdministrator Specifies Azure Active Directory Service Administrator intended to be used for Azure Stack deployment. .PARAMETER AADDirectoryTenantName Specifies the Azure Active Directory name intended to be used for Azure Stack deployment. .PARAMETER AzureEnvironment Specifies the instance of Azure Services containing the accounts, directories and subscriptions. .PARAMETER CustomCloudARMEndpoint Specifies the custom ARM Endpoint for a custom Azure Environment. .PARAMETER ForceTLS12 Force the use of TLS 1.2, true by default .PARAMETER OutputPath Specifies custom path to save Readiness JSON report and Verbose log file. .PARAMETER CleanReport Specifies whether to purge the existing report and start again with a clean report. Execution history and validation data is lost for all Readiness Checker validations. .LINK Azure Stack Identity Validation - https://aka.ms/AzsValidateAzureIdentity Azure Stack Readiness Checker - https://aka.ms/AzsReadinessChecker #> [CmdletBinding()] Param( [Parameter(Mandatory = $true, ParameterSetName = 'Install')] [Parameter(Mandatory = $true, ParameterSetName = 'InstallJSON')] [pscredential] $AADServiceAdministrator, [Parameter(Mandatory = $true, ParameterSetName = 'InstallJSON')] [ValidateScript( {Test-Path $_ -Include *.json})] [string] $deploymentDataJSONPath, [Parameter(Mandatory = $false, ParameterSetName = 'Install')] [ValidateSet('AzureCloud', 'AzureChinaCloud', 'AzureGermanCloud', 'AzureUSGovernment', 'CustomCloud')] [string] $AzureEnvironment = 'AzureCloud', [Parameter(Mandatory = $false, ParameterSetName = 'Install')] [Parameter(Mandatory = $false, ParameterSetName = 'InstallJSON')] [string] $CustomCloudARMEndpoint, [Parameter(Mandatory = $true, ParameterSetName = 'Install', HelpMessage = "Enter primary domain name of Azure Tenant Directory")] [string]$AADDirectoryTenantName, [Parameter(Mandatory = $false, HelpMessage = "Force the use of TLS 1.2, true by default")] [bool]$ForceTLS12 = $true, [Parameter(HelpMessage = "Directory path for log and report output")] [string]$OutputPath = "$ENV:TEMP\AzsReadinessChecker", [Parameter(HelpMessage = "Remove all previous progress and create a clean report")] [switch]$CleanReport = $false ) try { $thisFunction = $MyInvocation.MyCommand.Name $GLOBAL:OutputPath = $OutputPath Import-Module $PSScriptRoot\..\Microsoft.AzureStack.ReadinessChecker.Reporting.psm1 -Force # Check Azure Module exist and prompt to install if not if (-not (Get-Module AzureRM.Profile -ListAvailable)) { Write-AzsReadinessLog -message ($LocalizedData.MissingAzureRMPSModules) -function $thisFunction -type Error throw $LocalizedData.MissingAzureRMPSModules } Import-Module $PSSCriptRoot\AzureADConfiguration.psm1 -Force -Global Write-Header -invocation $MyInvocation -params $PSBoundParameters if ($PSCmdlet.ParameterSetName -eq 'InstallJSON') { $deploymentDataJSON = ConvertTo-DeploymentData -path $deploymentDataJSONPath $AzureEnvironment = $deploymentDataJSON.DeploymentData.InfraAzureEnvironment $AADDirectoryTenantName = $deploymentDataJSON.DeploymentData.InfraAzureDirectoryTenantName } # If user specifies custom azure environment, overwrite the AzureEnvironment as the json path if ($CustomCloudARMEndpoint) { Write-AzsReadinessLog -message ($LocalizedData.UserSpecifiedCustomAzureEnvironment -f $CustomCloudARMEndpoint) -function $thisFunction -type Info $AzureEnvironment = 'CustomCloud' } # Get/Clean Existing Report $readinessReport = Get-AzsReadinessProgress -clean:$CleanReport $readinessReport = Add-AzsReadinessCheckerJob -report $readinessReport $serviceAdministratorOutput = @{} # Force Security Profile to TLS1.2 if ($ForceTLS12) { # Change Security Protocol to TLS1.2 for the session and track for clean up later. $restoreSecurityProtocol = [Net.ServicePointManager]::SecurityProtocol $tempSecurityProtocol = [Net.SecurityProtocolType]::Tls12 Set-SecurityProtocol -securityProtocol $tempSecurityProtocol } Write-AzsReadinessLog -Message ("Starting Azure Identity Validation`n") -Type Info -Function $thisFunction -toScreen Write-Host "Checking Installation Requirements: " -nonewline $serviceAdministratorOutput = Test-AzsServiceAdministrator -AADServiceAdministrator $AADServiceAdministrator -AzureEnvironment $AzureEnvironment -CustomCloudARMEndpoint $CustomCloudARMEndpoint -AADDirectoryTenantName $AADDirectoryTenantName if ($serviceAdministratorOutput.result -ne 'OK') { Write-Host "Fail " -foregroundColor Red if ($serviceAdministratorOutput.errorDetails -ne @()) { Write-Host ("Error Details for Service Administrator Account {0}" -f $AADServiceAdministrator.Username) $serviceAdministratorOutput.errorDetails | ForEach-Object {Write-Host "$_" -foregroundcolor Yellow} Write-Host ("Additional help URL {0}" -f "https://aka.ms/AzsRemediateAzureIdentity") } } else { Write-Host "OK" -foregroundColor Green } Write-AzsReadinessLog -Message ("`nFinished Azure Identity Validation") -Type Info -Function $thisFunction -toScreen } catch { Write-Host "Fail " -foregroundColor Red $errorDetail = ("Checking Azure Identity failed with: {0}" -f $_.exception.Message) Write-Host "Error Details for Identity:" $errorDetail | ForEach-Object {Write-Host "$_" -foregroundcolor Yellow} } finally { # Write results to readiness report $readinessReport.AzureValidation.AzureInstallResult = $serviceAdministratorOutput $readinessReport = Close-AzsReadinessCheckerJob -report $readinessReport Write-AzsReadinessProgress -report $readinessReport Write-AzsReadinessReport -report $readinessReport # Remove global variables Remove-Variable -Name OutputPath # Restore TLS back to default if ($ForceTLS12) { Set-SecurityProtocol -securityProtocol $restoreSecurityProtocol } Write-Footer -invocation $MyInvocation } } # SIG # Begin signature block # MIIjhwYJKoZIhvcNAQcCoIIjeDCCI3QCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAlsy3dCQDUqt2y # BDcgRe9ugTFKkFv70rBupeVkyKOLqKCCDYUwggYDMIID66ADAgECAhMzAAABiK9S # 1rmSbej5AAAAAAGIMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ4WhcNMjEwMzAzMTgzOTQ4WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQCSCNryE+Cewy2m4t/a74wZ7C9YTwv1PyC4BvM/kSWPNs8n0RTe+FvYfU+E9uf0 # t7nYlAzHjK+plif2BhD+NgdhIUQ8sVwWO39tjvQRHjP2//vSvIfmmkRoML1Ihnjs # 9kQiZQzYRDYYRp9xSQYmRwQjk5hl8/U7RgOiQDitVHaU7BT1MI92lfZRuIIDDYBd # vXtbclYJMVOwqZtv0O9zQCret6R+fRSGaDNfEEpcILL+D7RV3M4uaJE4Ta6KAOdv # V+MVaJp1YXFTZPKtpjHO6d9pHQPZiG7NdC6QbnRGmsa48uNQrb6AfmLKDI1Lp31W # MogTaX5tZf+CZT9PSuvjOCLNAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUj9RJL9zNrPcL10RZdMQIXZN7MG8w # VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh # dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzQ1ODM4NjAfBgNVHSMEGDAW # gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw # MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx # XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB # ACnXo8hjp7FeT+H6iQlV3CcGnkSbFvIpKYafgzYCFo3UHY1VHYJVb5jHEO8oG26Q # qBELmak6MTI+ra3WKMTGhE1sEIlowTcp4IAs8a5wpCh6Vf4Z/bAtIppP3p3gXk2X # 8UXTc+WxjQYsDkFiSzo/OBa5hkdW1g4EpO43l9mjToBdqEPtIXsZ7Hi1/6y4gK0P # mMiwG8LMpSn0n/oSHGjrUNBgHJPxgs63Slf58QGBznuXiRaXmfTUDdrvhRocdxIM # i8nXQwWACMiQzJSRzBP5S2wUq7nMAqjaTbeXhJqD2SFVHdUYlKruvtPSwbnqSRWT # GI8s4FEXt+TL3w5JnwVZmZkUFoioQDMMjFyaKurdJ6pnzbr1h6QW0R97fWc8xEIz # LIOiU2rjwWAtlQqFO8KNiykjYGyEf5LyAJKAO+rJd9fsYR+VBauIEQoYmjnUbTXM # SY2Lf5KMluWlDOGVh8q6XjmBccpaT+8tCfxpaVYPi1ncnwTwaPQvVq8RjWDRB7Pa # 8ruHgj2HJFi69+hcq7mWx5nTUtzzFa7RSZfE5a1a5AuBmGNRr7f8cNfa01+tiWjV # Kk1a+gJUBSP0sIxecFbVSXTZ7bqeal45XSDIisZBkWb+83TbXdTGMDSUFKTAdtC+ # r35GfsN8QVy59Hb5ZYzAXczhgRmk7NyE6jD0Ym5TKiW5MIIHejCCBWKgAwIBAgIK # YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm # aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw # OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD # VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG # 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la # UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc # 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D # dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+ # lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk # kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6 # A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd # X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL # 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd # sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3 # T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS # 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI # bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL # BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD # uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv # c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF # BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h # cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA # YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn # 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7 # v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b # pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/ # KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy # CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp # mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi # hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb # BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS # oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL # gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX # cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCFVgwghVUAgEBMIGVMH4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p # Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAGIr1LWuZJt6PkAAAAA # AYgwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIH+K # E5PVrUuzEAX2vy/uG35KcIBKuH5ix7QIloMsEflnMEIGCisGAQQBgjcCAQwxNDAy # oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20wDQYJKoZIhvcNAQEBBQAEggEADhjDPpr6A55ZumAuLJr6wPm+FsuCBd6zcgSa # ZZfJrEsNFBlHp3Z6psefBTW+ePyvG3j4ywPK2Bw+VCDASMvXuaIVBNn1whRZUsK8 # AXjaddDF3HnDu0xTf98EFE8Jl4+1p3dQdBK19AeDb1sLClQXYWmNkzA1qjDDy9XL # uqLVQovqn6fctolHxpJ4rKFTsefT7B/yQx2MqXChFYY4bI3D0eWRlB9dlEeM+IWf # 39Xvi605fXhcKCQfn9Gjt7A4wftEKVnkZQ5SB+2Hd1TPwI6kA98GVoHK2a52a7Nk # 8xR8zS3SZWvKWdzll8ahPPQzfijyKbv4lV4VZ+dZTxIynTFl/6GCEuIwghLeBgor # BgEEAYI3AwMBMYISzjCCEsoGCSqGSIb3DQEHAqCCErswghK3AgEDMQ8wDQYJYIZI # AWUDBAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGE # WQoDATAxMA0GCWCGSAFlAwQCAQUABCBqHK4r8iSbSXOTKRrEuguz0jZFmSJuJeCM # etsjWIh9XQIGYAXkHH/ZGBMyMDIxMDEyMDAzMjYxNi44NTJaMASAAgH0oIHQpIHN # MIHKMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQL # ExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMSYwJAYDVQQLEx1UaGFsZXMg # VFNTIEVTTjozRTdBLUUzNTktQTI1RDElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt # U3RhbXAgU2VydmljZaCCDjkwggTxMIID2aADAgECAhMzAAABUjBLXYms5nBHAAAA # AAFSMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw # MB4XDTIwMTExMjE4MjYwNVoXDTIyMDIxMTE4MjYwNVowgcoxCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVy # aWNhIE9wZXJhdGlvbnMxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjNFN0EtRTM1 # OS1BMjVEMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIB # IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArsxuhImYdLWgkm7MDIrqTE2J # 226Bc449Q7g22709EVygQlZf7pgPlMtteA5h4hYZHrkXZSwdMmuUvbpuWiq+5QQa # mc77SoBjYAkWw0xvWLupMw8z080EbpVSL6FlctICE5xMqCdTt5uSD6bCwTUAnV7I # ft02Re9yQHLm9tW58Zv+LMXuM03W3bbQa6l/PySRdlRJwD/jAbxdlEEqOl1AGkyg # vxzwzwnHvyLDaAMcSwyNcB4SJao0QZ7eBzOR3Ch62a7x/rx54oYpHZRM4d340BaM # JNXxuz1YZjutDub1XagPh/d9eIRxDUCNHG6PkpEovEkiUizYsYI9Hlnj04e6WwID # AQABo4IBGzCCARcwHQYDVR0OBBYEFITdrtqsI9ZdnNof5FCw7gUSbHsUMB8GA1Ud # IwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0 # dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0 # YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKG # Pmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENB # XzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUH # AwgwDQYJKoZIhvcNAQELBQADggEBAFXFJ3Hxakms0GwxF393ddP7qYlkFOR3U28B # vb/W3lSA2huKBC8iHDROnugmzgTJT1PrJqWGHJyt47nDagocKri5sXYtoj8uIkOr # 4wHQafflRVpawalLDV2c4wqYDAmY+m7vF6tDZ3ZeFsgWyNCZLuvL1DRuMLDHSj93 # c/tTM5PUlJmt4+x8jQOefXaPZ4SpqGTJ+XbX9N0L8ZWhMDAGj5PcblL/QTfHDbxZ # 6VpOJixEUFurQN61ytLKBCEik2BuzrHu6DF2Q2D1sX/aBYWCs2cP0sJ4XQaI9kuX # smBNwLhf2V80d4Xad/1xs2XjnREXxctawu2QcIQyGo3hTIudxp8wggZxMIIEWaAD # AgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzET # MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV # TWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBD # ZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3 # MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw # DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x # JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkq # hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWl # CgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/Fg # iIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeR # X4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/Xcf # PfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogI # Neh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB # 5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvF # M2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAP # BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjE # MFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kv # Y3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEF # BQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w # a2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8E # gZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5t # aWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcC # AjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUA # bgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Pr # psz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOM # zPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCv # OA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v # /rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99 # lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1kl # D3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQ # Hm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30 # uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp # 25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HS # xVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi6 # 2jbb01+P3nSISRKhggLLMIICNAIBATCB+KGB0KSBzTCByjELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJp # Y2EgT3BlcmF0aW9uczEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046M0U3QS1FMzU5 # LUEyNUQxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoB # ATAHBgUrDgMCGgMVAL9unlSWrpnJk3IXeoamskDDQ15boIGDMIGApH4wfDELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z # b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDjsbQXMCIY # DzIwMjEwMTIwMDM0MDA3WhgPMjAyMTAxMjEwMzQwMDdaMHQwOgYKKwYBBAGEWQoE # ATEsMCowCgIFAOOxtBcCAQAwBwIBAAICNT4wBwIBAAICEbIwCgIFAOOzBZcCAQAw # NgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgC # AQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQBr47BR8wt+7KAyZxPeaBf2T8JaCOWt # auZ1dJ5bgHDIZTJ+Fvmn4bDwVLsNDPdiYd0wVm4VSFxmgcr4/9UBD4aqgh855T+6 # a0Y5CDSMEotSUzZR9HNCkbmhxDwi++s6YVFxdnu81ATJve9O4pEzXRQDIlT5NZWB # I91VmSkGaBVKATGCAw0wggMJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv # ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD # QSAyMDEwAhMzAAABUjBLXYms5nBHAAAAAAFSMA0GCWCGSAFlAwQCAQUAoIIBSjAa # BgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIP8tNn5i # g9t2e9e+d81U9QDfd/WnlM00QYmzt/ZSvRQwMIH6BgsqhkiG9w0BCRACLzGB6jCB # 5zCB5DCBvQQgk+5cx6OLJVCMXxBqfC10DYpP3nCur7rhliHJga67J6YwgZgwgYCk # fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAVIwS12JrOZwRwAA # AAABUjAiBCDYIiJkCNknEljeVlsGQNI56VKSG6gYEPUOYgeBvL9oSTANBgkqhkiG # 9w0BAQsFAASCAQB+jIC3Ue5D+DJ0JV7i79QBCNi2W7Rvwlrkoq5gPMrnjHg8IV7N # E/aVnGgHBntSi/R+3xx+vlxGpbw5GwXhh7iWdGjRdDMOkF/At6e9bl71euvuOKtW # OJeEbcLVgKG+F6NFBxysqxUT8NHz59mIjH8ABFA3eGTu11zR7mM1IGrWyn3nm8nv # P8lGu8y3a4RGvkuCSMI6NmOlnQ49+S2kr99a/gXN483OeqVY/EsVSTPVr071jig9 # rZVkJRCJ8V16U5rV0fRxmDWD1E6R6MERLXae4g+baaZlHsK5KWHA3VfCFcjO6nqQ # 01DfBtBBmJ2ZFPcc35ZjSUqa8KeRozrtpTdP # SIG # End signature block |