functions/mainfunctions.ps1
<#
.Synopsis Installs the Provance Cloud Connector into an Azure Subscription .DESCRIPTION . .EXAMPLE # First Define variables to login $tenantid = '58e65ebc-a255-4f35-b702-318467778665' # Create an Authentication Token and login to the Azure Subscription with a user account with at least contributor rights $cred = New-Object pscredential -ArgumentList ('contrubutoruser@contoso.onmicrosoft.com',(ConvertTo-SecureString -String 'thesecretpassword' -AsPlainText -Force)) $Authcontext = Get-ProvAzureAuthContext -TenantId $tenantid -UserCredential $cred Add-AzureRmAccount -AccountId $tenantid -AccessToken $Authcontext.AccessToken # Define the Installation parameters $instparam = @{ ApplicationId = 'b9ebd12c-9649-4c5a-b70e-2a3c47e6fa0e' ApplicationKey = 'theappkeyvalueyouwanttouseforreadaccess' TenantFQDN = 'contoso.onmicrosoft.com' AANAme = 'PCC-Prod' Location = 'westeurope' ResourceGroup = 'TheTargetResourceGroupsName' SubscriptionId = 'b5002cec-1ead-4f0b-99b1-a3fe4c19ac35' InstallMSCLoudSolutionProvider = 'yes' InstallCreateSampleConnections = 'yes' } # Run the installation (optionally with -verbose for more output) Install-ProvCC @instparam #Verbose mode Install-ProvCC @instparam -verbose #> function Install-ProvCC { [CmdletBinding( SupportsPaging = $false, SupportsShouldProcess = $false, PositionalBinding = $false)] Param ( [Parameter(Mandatory = $true, HelpMessage = 'Enter the Tenant Full Qualified Name of the Tenant you wil install the Provance Cloud Connector into.') ] [ValidateNotNullOrEmpty()] [string]$TenantFQDN, [Parameter(Mandatory = $true, HelpMessage = 'Enter the AppID of a Service Account, which has at least read-rights on the subscription') ] [ValidateNotNullOrEmpty()] [string]$ApplicationId, [Parameter(Mandatory = $true, HelpMessage = 'Enter the Key of the above Service Account.') ] [ValidateNotNullOrEmpty()] [string]$ApplicationKey, [Parameter(Mandatory = $false, HelpMessage = 'The Provance ITSM Cloud Connenctor will be installed into this Automation account. If you want to install to an existing account, make sure the resource group matches and you have entered the correct name. The account name must be between 6 to 50 characters, and can contain only letters, numbers, and hyphens.') ] [ValidatePattern('[0-9a-zA-Z-]{6,50}')] [ValidateNotNullOrEmpty()] [string]$AAName = "Provance-ITSM-Cloud-Connector", [Parameter(Mandatory = $true, HelpMessage = 'Specify the SubscriptionId in which this Azure Automation Account shall be installed') ] [ValidateNotNullOrEmpty()] [Guid]$SubscriptionId, [Parameter(Mandatory = $true, HelpMessage = 'Specify the Resource Group in which this Azure Automation Account shall be installed. If the Resource Group does not exist, it will be created') ] [ValidateNotNullOrEmpty()] [String]$ResourceGroupName, [Parameter(Mandatory = $true, HelpMessage = 'The Location specifies the region/datacenter where this Automation Account is located. This may impact the synchronization performance.') ] [ValidateNotNullOrEmpty()] [ValidateSet('australiasoutheast', 'brazilsouth', 'centralindia', 'canadacentral', 'eastus', 'eastus2', 'japaneast', 'koreacentral', 'northeurope', 'northcentralus', 'southcentralus', 'southeastasia', 'uksouth', 'westcentralus', 'westeurope', 'westus2')] [string]$Location, [Parameter(Mandatory = $true, Helpmessage = 'Installs additional CSP Provider module, connection type, schedule and runbook') ] [ValidateNotNullOrEmpty()] [Validateset('yes', 'no')] [string]$InstallMSCloudSolutionProvider, [Parameter(Mandatory = $true, Helpmessage = 'Installs additional Example Conenctions') ] [ValidateNotNullOrEmpty()] [Validateset('yes', 'no')] [string]$InstallCreateSampleConnections ) begin { Write-Verbose "Checking Prerequisites" # Checking Prerequisites # Reset Prerequisites check variable [bool]$script:prereqsuccessful = $false #Write-verbose "Check if logged in to Azure by testing Get-AzureRMContext for SubscriptionId $($subscriptionID.Guid)" #Test-ProvCCTenantLogin try { $contextSubscriptionName = (Get-AzureRmContext).Subscription.Name $contextSubscriptionId = (Get-AzureRmContext).Subscription.Id } catch { Write-Error "Could not detect AzureRMContext. You are not loggin to Azure from this session. `n Error: $($_)" } if (($($subscriptionID.Guid)) -ne $contextSubscriptionId) { Write-Error "You are logged in to Subscription $contextSubscriptionName with id $contextSubscriptionId, `n which does not match the subscription id $($subscriptionID.Guid) you specified as parameter. `n ThePowerShell Session of the installer needs to be authenticated to the Subscription where the Provance Cloud Connector shall be installed." break } else { Write-Verbose ".Logged on to correct Subscription with id $Subscriptionid" Write-Verbose "Test if ResourceGroup $resourceGroup exists, if not create" # Set PCC Tags $PCCTags = @{ 'PCC-DoNotSync' = 'False' } try { Get-AzureRmResourceGroup -Name $ResourceGroupName -ErrorAction Stop|Out-Null Set-AzureRmResourcegroup -Name $ResourceGroupName -Tag $PCCTags -ErrorAction Stop|Out-Null } catch { Write-Warning "ResourceGroup $ResourceGroupName did not exists, creating in location $location ..." New-AzureRmResourceGroup -Name $ResourceGroupName -Tag $PCCTags -Location $Location |Out-Null } Write-Verbose "..Prerequisites are met" $script:prereqsuccessful = $true } } process { try { #region Start deployment if Prerequ check was successful if ($prereqsuccessful -eq $true) { #region Deploy Azure Automation Account Write-Verbose ".Installing Provance ITSM Cloud Connector" Write-Verbose "..Customizing ARM Template Parameter Object 'armparamobject'" $armparamobject = @{ accountName = $AAName location = $Location sku = 'Basic' doNotSync = $true TenantFQDN = $TenantFQDN ApplicationId = $ApplicationId ApplicationKey = $ApplicationKey SchedSubStarttime = (Get-Date).AddMinutes(10) SchedComputeStartTime = (Get-Date).AddHours(1) SchedServMapStartTime = (Get-Date).AddHours(2) SchedCloudProvStartTime = (Get-Date).AddMinutes(30) MSCloudSolutionProvider = $InstallMSCloudSolutionProvider CreateSampleConnections = $InstallCreateSampleConnections } Write-Verbose "..Deploying Azure Automation Account with Name $($armparamobject.accountName)" $armpath = split-path $PsScriptRoot -Parent Write-Information "Deploying Provance CLoud Connector, this may takee up to five minutes, please be patient. You can want the progress in thge Azure Portal..." $resultPCC = New-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName -TemplateFile "$armpath\ARMTemplates\ProvanceCloudConnector.json" -TemplateParameterObject $armparamobject Start-Sleep -Seconds 5 "Azure Automation Account: $($resultpcc.Parameters.Values.value[0]) created" #endregion #region Create AzureRunAsAccount - Needed for updating Modules #TBD #endregion } else { Write-Error 'Prerequisites are not met, see host-process log above for details or try using the -Verbose switch for more info.' } } catch { Write-Error "Could not deploy Provance ITSM Cloud Connector. `n Error: $_" } } end { } } function Get-ProvCCJobForecast { [CmdletBinding( SupportsPaging = $false, SupportsShouldProcess = $false, PositionalBinding = $false)] [OutputType('Provance.Azure.PCC.JobForecast')] Param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$RunbookName, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ResourceGroupName, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$AutomationAccountName ) try { #Test-PCCTenantLogin Write-Verbose -Message "Find the runbook and get its status" $RB = Get-AzureRmAutomationRunbook -Name $RunbookName -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName if ($RB.State -ne 'Published') { Write-Warning -message "Runbook $RunbookName is not in `'Published`' state. Forecast stopped!" } else { Write-Verbose -Message "Find out if there are schedules linked" $TempSchedRBs = Get-AzureRmAutomationScheduledRunbook -Name $RB.Name -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName Write-Verbose -Message "Find out if none of the schedules is enabled" Foreach ($TempSchedRB in $TempSchedRBs) { if ((Get-AzureRmAutomationSchedule -Name $TempSchedRB.ScheduleName -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName).Isenabled -eq 'True') { $AllStatus += 1 } } if ($TempSchedRBs -eq $null) { Write-Warning -message "Runbook $RunbookName does not have any schedules linked to it. Forecast stopped!" } elseif ($Allstatus -eq $null) { Write-Warning -Message "Runbook $RunbookName does not have any enabled schedules linked to it. Forecast stopped!" } else { Write-Verbose -Message "Runbook exists, is published and schedules are enabled" # Get JobIds Foreach ($TempSchedRB in $TempSchedRBs) { [String[]]$JobIds += $TempSchedRB.JobScheduleId } Write-Verbose -Message "Find Scheduled Runbooks plus parameters" Foreach ($JobID in $JobIDs) { $SchedRB = Get-AzureRmAutomationScheduledRunbook -JobScheduleId $JobId -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName $SchedRBs = [Array]$SchedRBs + $SchedRB Write-Verbose -Message "Using JobID $JobId with Runbook $($SchedRB.RunbookName)" Write-Verbose -Message "Find Schedule Details" foreach ($SchedRB in $SchedRBs) { $Schedule = Get-AzurermAutomationSchedule -Name $SchedRB.ScheduleName -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName } Write-Verbose "Prepare output depending on Connection Type" switch ($runbookName) { 'Sync-AzureSubscriptionRunbook' { $sourceConn = $($SchedRB.Parameters.SubscriptionConnArray) } 'Sync-AzureComputeRunbook' { $sourceConn = $($SchedRB.Parameters.ComputeConnArray) } 'Sync-AzureOMSRunbook' { $sourceConn = $($SchedRB.Parameters.OMSConnArray) } } Write-Verbose -Message "Collect output" $JobForecasthash = [ordered]@{ RunbookName = $($SchedRB.RunbookName); Source = $SourceConn; Target = $($SchedRB.Parameters.ITSMConn); ScheduleName = $($SchedRB.ScheduleName); ScheduleActive = If ($Schedule.IsEnabled) {"Y"} else {"N"}; NextRunTime = Get-Date $Schedule.Nextrun.Ticks; ExpiryTime = if ($schedule.ExpiryTime.Year -eq '9999') {"Never"} else {Get-Date $Schedule.ExpiryTime.Ticks}; Timezone = $Schedule.Timezone; } $Jobforecast = New-Object -TypeName psobject -Property $JobForecasthash $JobForecast.PSObject.TypeNames.Insert(0, 'Provance.Azure.PCC.JobForecast') write-verbose -Message "Found an upcoming Job with Schedule $Schedule.Name at $Schedule.Nextruntime" $JobForecasts = [Array]$JobForecasts + $JobForecast } } Write-Verbose -Message "Send output to console" $output = $JobForecasts|Sort-Object -Property 'NextRunTime' return $output } } catch { Write-Error -Message "Unable to get the Runbook Schedules `n Error: $($_)" -ErrorAction Stop } } function New-ProvCCConnection { [CmdletBinding( SupportsPaging = $false, SupportsShouldProcess = $false)] [OutputType('Provance.Azure.PCC.Connection')] param( [parameter(mandatory = $true, Position = 0)] [ValidateSet('PCC-Provance-ITSM', 'PCC-Azure-Compute', 'PCC-Azure-LogAnalyticsWorkspace', 'PCC-Azure-Subscription', 'PCC-Azure-AutomationAccount')] [ValidateNotNullOrEmpty()] [String]$ConnectionTypeName, [parameter(mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ConnectionName, [parameter(mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ResourcegroupName, [parameter(mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$AutomationAccountName, [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Compute')] [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace')] [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription')] [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount')] [ValidateNotNullOrEmpty()] [String]$ApplicationId, [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Compute')] [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace')] [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription')] [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount')] [ValidateNotNullOrEmpty()] [String]$ApplicationKey, [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription' )] [ValidateNotNullOrEmpty()] [String]$TenantName, [parameter(mandatory = $true)] [String]$TenantId, [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription' )] [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount')] [String]$TenantFQDN, [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription' )] [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount')] [ValidateNotNullOrEmpty()] [String]$SubscriptionName, [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Compute')] [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace')] [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-Subscription' )] [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount')] [ValidateNotNullOrEmpty()] [String]$SubscriptionId, [parameter(mandatory = $true, parameterSetName = 'PCC-Provance-ITSM' )] [ValidateNotNullOrEmpty()] [String]$UserName, [parameter(mandatory = $true, parameterSetName = 'PCC-Provance-ITSM' )] [ValidateNotNullOrEmpty()] [String]$InstanceURL, [parameter(mandatory = $true, parameterSetName = 'PCC-Provance-ITSM' )] [ValidateNotNullOrEmpty()] [SecureString]$Password, [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount' )] [ValidateNotNullOrEmpty()] [String]$AARGName, [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-AutomationAccount' )] [ValidateNotNullOrEmpty()] [String]$AAName, [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace' )] [ValidateNotNullOrEmpty()] [String]$OMSRGName, [parameter(mandatory = $true, parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace' )] [ValidateNotNullOrEmpty()] [String]$OmsWorkspace, [parameter(parameterSetName = 'PCC-Provance-ITSM')] [parameter(parameterSetName = 'PCC-Azure-Subscription')] [parameter(parameterSetName = 'PCC-Azure-LogAnalyticsWorkspace' )] [parameter(parameterSetName = 'PCC-Azure-AutomationAccount')] [ValidateNotNullOrEmpty()] [String]$APIVersion, [parameter(parameterSetName = 'PCC-Azure-Compute')] [ValidateNotNullOrEmpty()] [String]$APIVersionARMVM = '2017-12-01', [parameter(parameterSetName = 'PCC-Azure-Compute')] [ValidateNotNullOrEmpty()] [String]$APIVersionClassicVM = '2016-04-01' ) try { #Test-ProvCCTenantLogin # Insert testing if this connection exists already Write-Verbose "Creating Connection Type $($PSCmdlet.ParameterSetName)" Switch ($ConnectionTypeName) { 'PCC-Azure-AutomationAccount' { $ConnectionFieldData = @{ ApplicationId = $ApplicationId ApplicationKey = $ApplicationKey TenantId = $TenantId TenantFQDN = $TenantFQDN SubscriptionId = $SubscriptionId SubscriptionName = $SubscriptionName AARGName = $AAName AAName = $AARGName APIVersion = if (!($ApiVersion)) {'2015-10-31'} else {$ApiVersion} } } 'PCC-Azure-Subscription' { $ConnectionFieldData = @{ ApplicationId = $ApplicationId ApplicationKey = $ApplicationKey TenantId = $TenantId TenantName = $TenantName TenantFQDN = $TenantFQDN SubscriptionId = $SubscriptionId SubscriptionName = $SubscriptionName APIVersion = if (!($ApiVersion)) {'2016-06-01'} else {$ApiVersion} } } 'PCC-Azure-Compute' { $ConnectionFieldData = @{ ApplicationId = $ApplicationId ApplicationKey = $ApplicationKey TenantId = $TenantId SubscriptionId = $Subscriptionid APIVersionARMVM = if (!($ApiVersionARMVM)) {'2017-12-01'} else {$ApiVersionARMVM} APIVersionClassicVM = if (!($ApiVersionClassicVM)) {'2016-04-01'} else {$ApiVersionClassicVM} } } 'PCC-Provance-ITSM' { $ConnectionFieldData = @{ ApplicationId = '1950a258-227b-4e31-a9cf-717495945fc2' TenantId = $TenantId InstanceURL = $InstanceURL UserName = $UserName Password = (New-Object PSCredential "user",$Password).GetNetworkCredential().Password APIVersion = if (!($ApiVersion)) {'v9.0'} else {$ApiVersion} } } 'PCC-Azure-LogAnalyticsWorkspace' { $ConnectionFieldData = @{ ApplicationId = $ApplicationId ApplicationKey = $ApplicationKey TenantId = $TenantId SubscriptionId = $Subscriptionid OMSRGName = $OMSRGName OMSWorkspace = $OMSWorkspace APIVersion = if (!($ApiVersion)) {'2015-11-01-preview'} else {$ApiVersion} } } } $Connectionparam = @{ 'Name' = $ConnectionName 'ResourceGroupName' = $ResourceGroupName 'AutomationAccountName' = $AutomationAccountName 'ConnectionTypeName' = $($PSCmdlet.ParameterSetName) 'ConnectionFieldValues' = $ConnectionFieldData 'Description' = 'Created with New-PCCConnection function from the Provance.PCCSetup Module' } New-AzureRmAutomationConnection @Connectionparam } catch { Write-Verbose -Message "StatusCode: $_.Exception.Response.StatusCode.value__" Write-Verbose -Message "StatusDescription: $_.Exception.Response.StatusDescription" Write-Error -Message "Unable to create new connection type `n Error: $($_)" -ErrorAction Stop } } function New-ProvCCJob { [CmdletBinding(SupportsPaging = $false, SupportsShouldProcess = $false, PositionalBinding = $false)] [OutputType('Provance.Azure.PCC.Job')] param( [parameter(mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$AutomationAccountName, [parameter(mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$RunbookName, [parameter(mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ResourcegroupName, [parameter(mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$ScheduleName, [ValidateSet('PCC-Azure-Subscription', 'PCC-Azure-Compute', 'PCC-Azure-LogAnalyticsWorkspace')] [parameter(mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$SourceConnectionTypeName, [parameter(mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$SourceConnectionName, [parameter(mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$TargetConnectionName ) try { Write-Verbose "Constructing Parameters ..." switch ($sourceConnectionTypeName) { 'PCC-Azure-Subscription' { $RBParams = @{ SubscriptionConnArray = $SourceConnectionName ITSMConn = $TargetConnectionName } } 'PCC-Azure-Compute' { $RBParams = @{ ComputeConnArray = $SourceConnectionName ITSMConn = $TargetConnectionName } } 'PCC-Azure-LogAnalyticsWorkspace' { $RBParams = @{ OMSConnArray = $SourceConnectionName ITSMConn = $TargetConnectionName } } } $JobParam = @{ ResourceGroupName = $ResourcegroupName AutomationAccountName = $AutomationAccountName RunbookName = $RunbookName ScheduleName = $ScheduleName Parameters = $RBParams } Write-Verbose "Creating Provance ITSM Cloud Connector Job for Runbook $runbookName with Schedule $ScheduleName with Source $SourceConnectionName and target $TargetConnectionName" Register-AzureRmAutomationScheduledRunbook @JobParam } catch { Write-Error "Job Creation failed: Error $($_)" } } # SIG # Begin signature block # MIIaBQYJKoZIhvcNAQcCoIIZ9jCCGfICAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUzJo0kGQ1NqoB+jMwQcGXyzHJ # OtKgghSZMIIE0DCCA7igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UE # BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY # BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290 # IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMx # MDUwMzA3MDAwMFowgbQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMw # EQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEt # MCsGA1UECxMkaHR0cDovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMw # MQYDVQQDEypHbyBEYWRkeSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0g # RzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC54MsQ1K92vdSTYusw # ZLiBCGzDBNliF44v/z5lz4/OYuY8UhzaFkVLVat4a2ODYpDOD2lsmcgaFItMzEUz # 6ojcnqOvK/6AYZ15V8TPLvQ/MDxdR/yaFrzDN5ZBUY4RS1T4KL7QjL7wMDge87Am # +GZHY23ecSZHjzhHU9FGHbTj3ADqRay9vHHZqm8A29vNMDp5T19MR/gd71vCxJ1g # O7GyQ5HYpDNO6rPWJ0+tJYqlxvTV0KaudAVkV4i1RFXULSo6Pvi4vekyCgKUZMQW # OlDxSq7neTOvDCAHf+jfBDnCaQJsY1L6d8EbyHSHyLmTGFBUNUtpTrw700kuH9zB # 0lL7AgMBAAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB # BjAdBgNVHQ4EFgQUQMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0jBBgwFoAUOpqF # BxBnKLbv9r0FQW4gwZTaD94wNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhho # dHRwOi8vb2NzcC5nb2RhZGR5LmNvbS8wNQYDVR0fBC4wLDAqoCigJoYkaHR0cDov # L2NybC5nb2RhZGR5LmNvbS9nZHJvb3QtZzIuY3JsMEYGA1UdIAQ/MD0wOwYEVR0g # ADAzMDEGCCsGAQUFBwIBFiVodHRwczovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9z # aXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQAIfmyTEMg4uJapkEv/oV9PBO9sPpyI # BslQj6Zz91cxG7685C/b+LrTW+C05+Z5Yg4MotdqY3MxtfWoSKQ7CC2iXZDXtHwl # TxFWMMS2RJ17LJ3lXubvDGGqv+QqG+6EnriDfcFDzkSnE3ANkR/0yBOtg2DZ2HKo # cyQetawiDsoXiWJYRBuriSUBAA/NxBti21G00w9RKpv0vHP8ds42pM3Z2Czqrpv1 # KrKQ0U11GIo/ikGQI31bS/6kA1ibRrLDYGCD+H1QQc7CoZDDu+8CL9IVVO5EFdkK # rqeKM+2xLXY2JtwE65/3YR8V3Idv7kaWKK2hJn0KCacuBKONvPi8BDABMIIFADCC # A+igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNV # BAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJm # aWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290 # IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMx # MDUwMzA3MDAwMFowgcYxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMw # EQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9n # aWVzLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydHMuc3RhcmZpZWxkdGVjaC5j # b20vcmVwb3NpdG9yeS8xNDAyBgNVBAMTK1N0YXJmaWVsZCBTZWN1cmUgQ2VydGlm # aWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK # AoIBAQDlkGZL7PlGcakgg77pbL9KyUhpgXVObST2yxcT+LBxWYR6ayuFpDS1FuXL # zOlBcCykLtb6Mn3hqN6UEKwxwcDYav9ZJ6t21vwLdGu4p64/xFT0tDFE3ZNWjKRM # XpuJyySDm+JXfbfYEh/JhW300YDxUJuHrtQLEAX7J7oobRfpDtZNuTlVBv8KJAV+ # L8YdcmzUiymMV33a2etmGtNPp99/UsQwxaXJDgLFU793OGgGJMNmyDd+MB5FcSM1 # /5DYKp2N57CSTTx/KgqT3M0WRmX3YISLdkuRJ3MUkuDq7o8W6o0OPnYXv32JgIBE # Q+ct4EMJddo26K3biTr1XRKOIwSDAgMBAAGjggEsMIIBKDAPBgNVHRMBAf8EBTAD # AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUJUWBaFAmOD07LSy+zWrZtj2z # ZmMwHwYDVR0jBBgwFoAUfAwyH6fZMH/EfWijYqihzqsHWycwOgYIKwYBBQUHAQEE # LjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5zdGFyZmllbGR0ZWNoLmNvbS8w # OwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5zdGFyZmllbGR0ZWNoLmNvbS9z # ZnJvb3QtZzIuY3JsMEwGA1UdIARFMEMwQQYEVR0gADA5MDcGCCsGAQUFBwIBFito # dHRwczovL2NlcnRzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkvMA0GCSqG # SIb3DQEBCwUAA4IBAQBWZcr+8z8KqJOLGMfeQ2kTNCC+Tl94qGuc22pNQdvBE+zc # MQAiXvcAngzgNGU0+bE6TkjIEoGIXFs+CFN69xpk37hQYcxTUUApS8L0rjpf5Mqt # JsxOYUPl/VemN3DOQyuwlMOS6eFfqhBJt2nk4NAfZKQrzR9voPiEJBjOeT2pkb9U # GBOJmVQRDVXFJgt5T1ocbvlj2xSApAer+rKluYjdkf5lO6Sjeb6JTeHQsPTIFwwK # lhR8Cbds4cLYVdQYoKpBaXAko7nv6VrcPuuUSvC33l8Odvr7+2kDRUBQ7nIMpBKG # gc0T0U7EPMpODdIm8QC3tKai4W56gf0wrHofx1l7MIIFPDCCBCSgAwIBAgIJALbL # wjYBUl1HMA0GCSqGSIb3DQEBCwUAMIG0MQswCQYDVQQGEwJVUzEQMA4GA1UECBMH # QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j # b20sIEluYy4xLTArBgNVBAsTJGh0dHA6Ly9jZXJ0cy5nb2RhZGR5LmNvbS9yZXBv # c2l0b3J5LzEzMDEGA1UEAxMqR28gRGFkZHkgU2VjdXJlIENlcnRpZmljYXRlIEF1 # dGhvcml0eSAtIEcyMB4XDTE3MTIxMTIwMzEwMVoXDTE4MDkwNjE1NDIwMFowfTEL # MAkGA1UEBhMCQ0ExDzANBgNVBAgTBlF1ZWJlYzERMA8GA1UEBxMIR2F0aW5lYXUx # JDAiBgNVBAoTG1Byb3ZhbmNlIFRlY2hub2xvZ2llcywgSW5jLjEkMCIGA1UEAxMb # UHJvdmFuY2UgVGVjaG5vbG9naWVzLCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOC # AQ8AMIIBCgKCAQEAzv3zfbU437wH1fLprlbIGBtCLjMKf2XSIWgPIpymOhJeQP07 # H/dGlg8fy4vUJpWS3jwAAAiQfycR8IyCpGTZf1XiPLsdnw4WIwbaYYe6LylA8xhv # 8d8Hassqp2LCZbBhm9ueLySqPM+DykABQOFPYbJVj/WDwd8/KaBCGZw0FXsl+AuB # HeiZ89pjz4oFX+BXrM5/rvVHZuYD6W+UesxxibNrmuMf3JFzfh2Ttr+orMRRCCSt # v0N87EAOkjZ52fIbsKptMHRaywZO1qGIWFlBSTBcCktMlKjVpbZkVCrY81eMhkzb # +nOTpvAaUFNEESekdMveZA8XJoYQ3XoFXU8vjwIDAQABo4IBhTCCAYEwDAYDVR0T # AQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAzAOBgNVHQ8BAf8EBAMCB4AwNQYD # VR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5nb2RhZGR5LmNvbS9nZGlnMnM1LTMu # Y3JsMF0GA1UdIARWMFQwSAYLYIZIAYb9bQEHFwIwOTA3BggrBgEFBQcCARYraHR0 # cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzAIBgZngQwB # BAEwdgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nb2Rh # ZGR5LmNvbS8wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRk # eS5jb20vcmVwb3NpdG9yeS9nZGlnMi5jcnQwHwYDVR0jBBgwFoAUQMK9J47MNIMw # ojPX+2yz8LQsgM4wHQYDVR0OBBYEFOwFSw0KFV9Bs1UypkhJ4XNI/N9JMA0GCSqG # SIb3DQEBCwUAA4IBAQASYv3417VLTHaQ/stRoHy/s4SSSovygnp2luUUChTuXQ9z # SJxzrXwmNbdVZV1X1LrDWHhxTztwOPwDbV6TNSwKhBMTTSZQ9gJCbfQ/gwaqhvbG # 3pFN62FcUHZ0B6xfWTqcxQ+eMLdAzbt52HMkLAGfaFKRiIllM079bxTZ6QiSNHQ5 # 76gDm0V16n3zvPFKA7wJyaWAQY2//UPrBP3B1zxElgock21I6OiLLIe7vBvLvvXw # QuJe/QM+p4sr6OTJGI4OsLI9N4dLpC0gmbz1QCPIvkOQOFsB14bLiqzABSJEkvc8 # C+lF7ABlmdTLnsx+yePeC3Ka9+rKEGyetKKpFFCgMIIFfTCCBGWgAwIBAgIJAO+V # wvSA4xuTMA0GCSqGSIb3DQEBCwUAMIHGMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH # QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3RhcmZpZWxk # IFRlY2hub2xvZ2llcywgSW5jLjEzMDEGA1UECxMqaHR0cDovL2NlcnRzLnN0YXJm # aWVsZHRlY2guY29tL3JlcG9zaXRvcnkvMTQwMgYDVQQDEytTdGFyZmllbGQgU2Vj # dXJlIENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTE3MTExNDA3MDAwMFoX # DTIyMTExNDA3MDAwMFowgYcxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25h # MRMwEQYDVQQHEwpTY290dHNkYWxlMSQwIgYDVQQKExtTdGFyZmllbGQgVGVjaG5v # bG9naWVzLCBMTEMxKzApBgNVBAMTIlN0YXJmaWVsZCBUaW1lc3RhbXAgQXV0aG9y # aXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDm730Ku3SP # yEahtiafyThSMSvGVFw6JhBrYkQYOcH10SjiERRWLn3DD51isWZDIrkxmTdy/zEt # 2m0qf2odGk7KRPeO7OMlEbeGS4Cc11H7OvxG6VSADFbYTkrgGREeDgFxPA8WzeaJ # YFVwJq7kcoFSGN797hHOoYsd/GkD/iqnEjNfYRUcKdaH9b/Yzjwjte6uba5Iepls # Nx0eXWU+zy7bff21Qb1HQ0P0VTuYCbviRJknhKOZKSGuNhQ9CFDzMQbcbsbyx3+o # v/iMaIGp7NHNlk/4hR1rFFmMwPRT/m123J8xGpoYBPPMOHyk15bF/1laR3kAr3fh # bj0OQoUOUFIBAgMBAAGjggGpMIIBpTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQE # AwIGwDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAdBgNVHQ4EFgQUnc8cgP4K1qL8 # WBg+p9NUQO7WFGEwHwYDVR0jBBgwFoAUJUWBaFAmOD07LSy+zWrZtj2zZmMwgYQG # CCsGAQUFBwEBBHgwdjAqBggrBgEFBQcwAYYeaHR0cDovL29jc3Auc3RhcmZpZWxk # dGVjaC5jb20vMEgGCCsGAQUFBzAChjxodHRwOi8vY3JsLnN0YXJmaWVsZHRlY2gu # Y29tL3JlcG9zaXRvcnkvc2ZfaXNzdWluZ19jYS1nMi5jcnQwVAYDVR0fBE0wSzBJ # oEegRYZDaHR0cDovL2NybC5zdGFyZmllbGR0ZWNoLmNvbS9yZXBvc2l0b3J5L21h # c3RlcnN0YXJmaWVsZDJpc3N1aW5nLmNybDBQBgNVHSAESTBHMEUGC2CGSAGG/W4B # BxcCMDYwNAYIKwYBBQUHAgEWKGh0dHA6Ly9jcmwuc3RhcmZpZWxkdGVjaC5jb20v # cmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAFJGgfPKVmOa5BUYGkgzgZUH # APDVCxA0oDWH0E5+lQB0DlDHgv5G6O4Ju2dqL9TAJfhRAS0i+PaXwLOWbz/yxZc9 # jpCNDbVWIRIZdxzXvR7dOSvRPgWFxW1Msip51ys9TQV2ybVAyA+CjVwuNOALYWrT # 2ZhQBEp47lbsLRag4VwYpydVkbfKa4Egad+0V0SHQrWxwnMaj/7PT+b8WilhTxTR # XNWlxRlQ+9wla5Sqwn5PwafeJwv6eGS6nKC00cRPDQ6WDCo46VhOjkmv50J+o93p # 9LM2hkFuoRMrR5O3D8Zcg1jbab4rTDT+f+Wn5eYn9PwbYB7e4WMjRafylm5E3Hox # ggTWMIIE0gIBATCBwjCBtDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmEx # EzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu # MS0wKwYDVQQLEyRodHRwOi8vY2VydHMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS8x # MzAxBgNVBAMTKkdvIERhZGR5IFNlY3VyZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkg # LSBHMgIJALbLwjYBUl1HMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKAC # gAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsx # DjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTf3HPfa9au9rn7iVJHfH7D # T/qL4DANBgkqhkiG9w0BAQEFAASCAQAo0pV17N8f1KyN74QnMzv6Ud2QHw7o/fmE # +toaO96wrXCKxkxSCzrnEywTctf/a+MYTmKhwMG5RJhymAtswM2CMDqm/UjdnwwC # Ehd8f7QVFCfzr57vlsZtenyVidb9K1i+XJG5ID9Y+9N1BfX1NvhZHF5yqSCteqgf # Px+wkIVNiwdZbb4wcOUACebkCt31Po6oNbHyh4WvTrBuJoG0UXMr/ENgXGiFvTcN # l+xxlDE24ddkA9TnELEsGzIHJ4FkWzvsXpERTtO4hGEQBzDEkxfKsrnkU7WoPjbE # g+8Hyl/ZWv1hQwHCQQBUv912iHporgTw/igxZN6I/eAATtOL434qoYICbjCCAmoG # CSqGSIb3DQEJBjGCAlswggJXAgEBMIHUMIHGMQswCQYDVQQGEwJVUzEQMA4GA1UE # CBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3RhcmZp # ZWxkIFRlY2hub2xvZ2llcywgSW5jLjEzMDEGA1UECxMqaHR0cDovL2NlcnRzLnN0 # YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkvMTQwMgYDVQQDEytTdGFyZmllbGQg # U2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyAgkA75XC9IDjG5MwCQYF # Kw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkF # MQ8XDTE4MDgwOTE3MzMyN1owIwYJKoZIhvcNAQkEMRYEFHLtMGF3jQt1cpfrpmqi # QfTlVHmeMA0GCSqGSIb3DQEBAQUABIIBAOGyQfeGUDjLpSVuxLkglZLrX+d7PEtr # o9/1OEaB+jrLvsaLnLk7bFSY+5jK7ZVfCWR2ksPTGvqoCHXLQJs3zow4U58q77sT # N52Rsg1gcKI6018ULk55uLd8XJdrCDrYIYt3n1SIsuyL+M5EoqcibaEFDMzCvlWc # 6cZDcqxNEJrv1QpX9zwy7NW0rI+7YX/FqTOJsDVKLKAEzZL6T2mQ/ym85fIqDH6k # /07XIbyXAuCioHFc4uVaCyfH2oqygs0Lb8o+aXk65r9kfMqfmL5R76PtwRw9Je8m # bsz6m/cBaT4/Jyfb/hwe3dyU3YlQLf3b/vIRz/t+tuVHbBC5+K5nLag= # SIG # End signature block |