#Requires -Version 5.1 [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0, HelpMessage = 'Enter your Azure Subscription Id where to deploy Nimbus assets')] [Alias('s', 'sub')] [guid]$SubscriptionId, [Parameter(Mandatory = $true, Position = 1, HelpMessage = 'Enter the Azure resource group name for Nimbus assets')] [Alias('r', 'resGrp')] [ValidateNotNullOrEmpty()] [string]$resourceGroupName, [Parameter(Mandatory = $true, Position = 2, HelpMessage = 'Enter the resource prefix for Nimbus assets')] [Alias('p', 'prefix')] [ValidateNotNullOrEmpty()] [string]$resourcePrefix, [Parameter(Mandatory = $true, Position = 3, HelpMessage = 'Enter the Azure location where Nimbus assets should be deployed: "Australia East", "Australia Southeast", "Brazil South", "Canada Central", "Central India", "Central US", "East Asia", "East US", "East US 2", "France Central", "Japan East", "Korea Central", "North Central US", "North Europe", "South Africa North", "South Central US", "Southeast Asia", "UK South", "West Central US", "West Europe", "West US", "West US 2')] [Alias('l', 'loc')] [validateSet("Australia East", "Australia Southeast", "Brazil South", "Canada Central", "Central India", "Central US", "East Asia", "East US", "East US 2", "France Central", "Japan East", "Korea Central", "North Central US", "North Europe", "South Africa North", "South Central US", "Southeast Asia", "UK South", "West Central US", "West Europe", "West US", "West US 2")] [string]$location, [Parameter(Mandatory = $true, Position = 4, HelpMessage = 'Provide a list emails of approvers, has to be separated with a semicolon ( ";" )')] [string]$approvers, [Parameter(Mandatory = $false, Position = 5)] [ValidateSet( 'portal.stage.nimbdev.com', 'portal.us-01.stage.nimbdev.com', 'portal.use-01.stage.nimbdev.com', 'portal.us-02.stage.nimbdev.com', 'portal.use-02.stage.nimbdev.com', 'portal.uat.nimbdev.com', 'portal.us-01.uat.nimbdev.com', 'portal.use-01.uat.nimbdev.com', 'portal.nimbload.com', 'portal.load.nimbload.com', 'portal.ch-01.load.nimbload.com', 'portal.chno-01.load.nimbload.com', 'portal.innovator.luware.cloud', 'portal.ch-01.innovator.luware.cloud', 'portal.chno-01.innovator.luware.cloud', 'portal.luware.cloud', 'portal.de-01.luware.cloud', 'portal.dewe-01.luware.cloud', 'portal.ch-01.luware.cloud', 'portal.chno-01.luware.cloud', 'portal.uk-01.luware.cloud','portal.ukso-01.luware.cloud', 'portal.eu-01.luware.cloud', 'portal.euwe-01.luware.cloud' )] [Alias('d', 'dom')] [string]$domain = 'portal.uk-01.luware.cloud' ) if ( $resourceGroupName -notmatch '[a-zA-Z0-9]+' ) { "Resource Group Name not valid, please provide a resource group name matching the following regex: '[a-zA-Z0-9]+'" exit } if ( $resourcePrefix -notmatch '[a-zA-Z0-9]+' ) { "Resource Prefix not valid, please provide a prefix matching the following regex: '[a-zA-Z0-9]+'" exit } if ( -not $env:localTesting ) { try { # make sure tls 1.2 is accepted [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $remoteFile = [System.IO.Path]::GetTempFileName() Invoke-RestMethod "https://$domain/api/manifests/NimbusOnBoarding.ps1" -OutFile $remoteFile -ErrorAction Stop $localHash = Get-FileHash -Algorithm MD5 $PSCommandPath $remoteHash = Get-FileHash -Algorithm MD5 $remoteFile Remove-Item $remoteFile if ( $localHash.hash -ne $remoteHash.hash ) { Write-Host "You are using an outdated version of the script." -ForegroundColor Red Write-Host "Please download the current version from https://$domain/api/manifests/NimbusOnBoarding.ps1" -ForegroundColor Red Write-Host "Exiting." return } } catch { Write-Host "Version checking failed" -ForegroundColor Red Write-Host "Please make sure you can reach https://$domain/api/manifests/NimbusOnBoarding.ps1 " -ForegroundColor Red Write-Host "Exiting." return } } function New-NimbusWebSession { Param ([String]$token, [String]$domain) $webSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession $cookie = New-Object System.Net.Cookie $cookie.Name = "Nimbus.Auth" $cookie.Value = $token $cookie.Domain = $domain $webSession.Cookies.Add($cookie); $webSession } function Connect-ForMfa { Param ([String]$Account) try { Write-Host "Trying to connect using Multifactor Authentication" Write-Host "Press Enter to continue" Read-Host | Out-Null Write-Host "Connecting to AzureAd..." -NoNewline Connect-AzureAD -AccountId $account -ErrorAction Stop | Out-Null Write-Host "[Done]" -ForegroundColor Green } catch [Microsoft.Open.Azure.AD.CommonLibrary.AadAuthenticationFailedException] { Write-Host "[Failed]" -ForegroundColor Red Write-Host "Invalid Credentials provided. Script will be stopped." -ForegroundColor Red return $false } catch [ArgumentException] { Write-Host "[Failed]" -ForegroundColor Red Write-Host "There is already a remote session open. Please close all sessions before running the script." -ForegroundColor Red return $false } catch [System.Management.Automation.Remoting.PSRemotingTransportException] { Write-Host "[Failed]" -ForegroundColor Red Write-Host $_.Exception.Message -ForegroundColor Red return $false } catch { if ($Error[0].Exception -like "*Authentication Error*") { Write-Host "[Failed]" -ForegroundColor Red Write-Host "Error with Authentication. Please try again and check your credentials." -ForegroundColor Red return $false } Write-Host "[Failed]" -ForegroundColor Red Write-Host "An error occurred. Open a new PowerShell Window and rerun the script." -ForegroundColor Red return $false } } try { Import-Module AzureAd -ErrorAction Stop } catch { Install-Module -Name AzureAd -ErrorAction Stop } try { Import-Module Az.Accounts, Az.Resources -ErrorAction Stop } catch { Install-Module -Name Az.Accounts, Az.Resources -ErrorAction Stop } $azureCredentials = $host.ui.PromptForCredential("Azure Credentials prompt", "Please enter your credentials to connect to Azure", "", "NetBiosUserName") if (-not $azureCredentials) { Write-Host "No Credentials provided. Script will be stopped." -ForegroundColor Red Write-Host "Press Enter to quit." Read-Host | Out-Null return } # perhaps need better error handling here Add-AzAccount -Credential $azureCredentials -SubscriptionId $SubscriptionId -ErrorAction Stop | Out-Null Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop | Out-Null $runbookCredentials = $host.ui.PromptForCredential("Azure AD Credentials prompt", "Please enter your credentials to connect to Azure AD", "", "NetBiosUserName") if (-not $runbookCredentials) { Write-Host "No Credentials provided. Script will be stopped." -ForegroundColor Red Write-Host "Press Enter to quit." Read-Host | Out-Null return } try { Write-Host "Connecting to AzureAd..." -NoNewline Connect-AzureAD -Credential $runbookCredentials -ErrorAction Stop | Out-Null Write-Host "[Done]" -ForegroundColor Green } catch [Microsoft.Open.Azure.AD.CommonLibrary.AadAuthenticationFailedException] { Write-Host "[Failed]" -ForegroundColor Red if ($_.Exception.Message -like "* multi-factor authentication *") { $session = Connect-ForMfa -Account $runbookCredentials.UserName if (!$session) { Write-Host "Press Enter to quit." Read-Host | Out-Null return } } else { Write-Host $_.Exception.Message -ForegroundColor Red Write-Host "Press Enter to quit." Read-Host | Out-Null return } } catch { if ($Error[0].Exception -like "*Authentication Error*") { Write-Host "[Failed]" -ForegroundColor Red Write-Host "Error with Authentication. Please try again and check your credentials." -ForegroundColor Red Write-Host "Press Enter to quit." Read-Host | Out-Null return } Write-Host "[Failed]" -ForegroundColor Red Write-Host "An error occurred. Open a new PowerShell Window and rerun the script." -ForegroundColor Red Write-Host "Press Enter to quit." Read-Host | Out-Null return } $token = [Microsoft.Open.Azure.AD.CommonLibrary.AzureSession]::AccessTokens['AccessToken'] $tenant = $token.TenantId $webSession = New-NimbusWebSession -token $token.AccessToken -domain $domain $deploymentParameters = @{ ResourceGroupName = $resourceGroupName prefix = $resourcePrefix location = $location.ToLower() -replace '\s' recipients = $approvers "nimbus-credentials-user" = $runbookCredentials.UserName "nimbus-credentials-password" = $runbookCredentials.Password "nimbus-domain" = "'$domain'" Verbose = $true ErrorAction = "Stop" } if ( $env:localTesting ) { $deploymentParameters.TemplateFile = "template.json" } else { $deploymentParameters.TemplateUri = "https://$domain/api/manifests/template.json" } $resourceGroup = Get-AzResourceGroup -ResourceGroupName $resourceGroupName -ErrorAction SilentlyContinue if ( -not $resourceGroup ) { Write-Host "Resource Group doesn't exist, creating it" $resourceGroup = New-AzResourceGroup -ResourceGroupName $resourceGroupName -Location $location } $deployment = New-AzResourceGroupDeployment @deploymentParameters $callbackUrl = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($deployment.outputs.callbackUrl.value)) if ( -not $env:localTesting ) { # todo: error handling Invoke-RestMethod "https://$domain/api/ms-flow-driver/v1/RunBooks/$tenant" ` -Method:Put ` -ContentType 'application/json' ` -Body ( '"{0}"' -f $callbackUrl ) ` -UseBasicParsing ` -WebSession $webSession } $path = "https://portal.azure.com/#@{0}/resource{1}/providers/Microsoft.Web/connections/{2}" -f ( ( Get-AzContext ).Tenant.Id ), $resourceGroup.ResourceId, $resourcePrefix Write-Host "The script has run successfully." Write-Host "Please, configure and authorize the following connections:" Write-Host "$path-automation/edit" Write-Host "$path-office365/edit" # SIG # Begin signature block # MIIRwAYJKoZIhvcNAQcCoIIRsTCCEa0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU4i4Jd7ny9UctKkEMB8MsdyMI # XAKggg4MMIIGsDCCBJigAwIBAgIQCK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0B # AQwFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVk # IFJvb3QgRzQwHhcNMjEwNDI5MDAwMDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYD # VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD # ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg # Q0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5 # WRuxiEL1M4zrPYGXcMW7xIUmMJ+kjmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJP # DqFX/IiZwZHMgQM+TXAkZLON4gh9NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXz # ENOLsvsI8IrgnQnAZaf6mIBJNYc9URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bq # HPNlaJGiTUyCEUhSaN4QvRRXXegYE2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTC # fMjqGzLmysL0p6MDDnSlrzm2q2AS4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaD # G7dqZy3SvUQakhCBj7A7CdfHmzJawv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urO # kfW+0/tvk2E0XLyTRSiDNipmKF+wc86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7AD # K5GyNnm+960IHnWmZcy740hQ83eRGv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4 # R+Z1MI3sMJN2FKZbS110YU0/EpF23r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlN # Wdt4z4FKPkBHX8mBUHOFECMhWWCKZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0I # U0F8WD1Hs/q27IwyCQLMbDwMVhECAwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYB # Af8CAQAwHQYDVR0OBBYEFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaA # FOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK # BggrBgEFBQcDAzB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v # Y3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4 # oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv # b3RHNC5jcmwwHAYDVR0gBBUwEzAHBgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcN # AQEMBQADggIBADojRD2NCHbuj7w6mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcT # Ep6QRJ9L/Z6jfCbVN7w6XUhtldU/SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WT # auPrINHVUHmImoqKwba9oUgYftzYgBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9 # ntSZz0rdKOtfJqGVWEjVGv7XJz/9kNF2ht0csGBc8w2o7uCJob054ThO2m67Np37 # 5SFTWsPK6Wrxoj7bQ7gzyE84FJKZ9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0 # HKKlS43Nb3Y3LIU/Gs4m6Ri+kAewQ3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL # 6TEa/y4ZXDlx4b6cpwoG1iZnt5LmTl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+1 # 6oh7cGvmoLr9Oj9FpsToFpFSi0HASIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8 # M4+uKIw8y4+ICw2/O/TOHnuO77Xry7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrF # hsP2JjMMB0ug0wcCampAMEhLNKhRILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy # 1lKQ/a+FSCH5Vzu0nAPthkX0tGFuv2jiJmCG6sivqf6UHedjGzqGVnhOMIIHVDCC # BTygAwIBAgIQA3aO19qsnlj9fMyUA6Y6/TANBgkqhkiG9w0BAQsFADBpMQswCQYD # VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD # ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg # Q0ExMB4XDTIyMDUyMDAwMDAwMFoXDTI1MDUyODIzNTk1OVowWTELMAkGA1UEBhMC # Q0gxEDAOBgNVBAgMB1rDvHJpY2gxEDAOBgNVBAcMB1rDvHJpY2gxEjAQBgNVBAoT # CUx1d2FyZSBBRzESMBAGA1UEAxMJTHV3YXJlIEFHMIICIjANBgkqhkiG9w0BAQEF # AAOCAg8AMIICCgKCAgEA3F/RR6ADpLB7eoujW7klwYNd90n6mwFIeijKPyjxqpdG # WoqLQocgh2XgwlkDChcMyS4iO4YY3IKaimNLHGsXXmN7UIZPwc272g5K34jOBCJ/ # hlgLV+ISPKhPKL4dfEM3KCbXqhBLGwfk2jHLiYFcL5YQXtcp+o6QwUYT+sTOwMCv # mToVcREXZ/A2L8YAYi5wgzFBJadtngUzRH5HGXFrUopQRCZd7Xksy5DNcGKDtii2 # Dmvw1YBCHHnPkFFK9IQRWAclsa3H950KzrnXDqhxrDpOmZilmnRy2/cbERUd77ki # sitokdxYg25knl+pW7gLvu0WcZ9sunGV3J824pfQaYzwMa9f/i8XeajPY1WO1HPF # 96rhqHCiIyhaiCD73HnSHzRQWodxLFcfK9UFNh1KNRcSgrn6J5rGaV0qIr38xE0b # +pUEirOgoVX3LdyDkvN0pE6PcEFXOLRbNZI2qFuHhtHGO/NtpGSPiAv2/IaH7Obe # fYpu3wyULYIuk7jUkSBe3BoiATElsS8VP7LF7JV6l+lZrCedEKL/Y4OWLUd508uY # 7rYVvjaCG7UjbQ7lFumizwkeDSADAmVUfjVt+x/wKYcFbqlWrZ3BdZ8hds2zukP0 # ItrVV5/6TyvN2m5i8I5zZVL1rxQeirercs0rx1bVUBC0eQqUHGWcsrDzovNjLGUC # AwEAAaOCAgYwggICMB8GA1UdIwQYMBaAFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB0G # A1UdDgQWBBTR/36vPEsWl8+Wupd1+sr/LI4wtzAOBgNVHQ8BAf8EBAMCB4AwEwYD # VR0lBAwwCgYIKwYBBQUHAwMwgbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0 # MDk2U0hBMzg0MjAyMUNBMS5jcmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0 # LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIw # MjFDQTEuY3JsMD4GA1UdIAQ3MDUwMwYGZ4EMAQQBMCkwJwYIKwYBBQUHAgEWG2h0 # dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBlAYIKwYBBQUHAQEEgYcwgYQwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBcBggrBgEFBQcwAoZQ # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29k # ZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcnQwDAYDVR0TAQH/BAIwADAN # BgkqhkiG9w0BAQsFAAOCAgEAucVmV0nc/HbMGCcLoNMHZKlZTC9Qb9bZfLdei64A # nHIM5ezzyN0M4hYDOsj1hgzHkdU9YhiVvBaaiqwHck7NQr9/xd3ELgWs7DTuDA1h # LyOtqG+IUrFwEz4JFtIYQk/vjGFWN5AM9gI2cmJRrzpqD6SMup8oqN6Xakh9ktEb # mO7pJPQW1vyXqDcbg0licRPJxZJp4uZ1gFLizK1Fe2m+SsI5KXrZ0JSbsm4H4VLS # 6Y5od6+TngIAIA0y5rjyo5xpT6pCWdLpTCatz5qQMEmDeplN2oaisyqEA1zhyP/F # cGAAijoYWCEQuu+R00s2/we7I/Xpv1sWsnGZRv2gQ+BkmQn+5q//GoultzC7fPoC # TZzAFSiH5fM8DlJmiSm41HR0/KPLYfq1/7xbiJZuaXopxdJ1y/m02iGK7ROvUCbk # lQj9xy9Q4WCwxJe018dB0+i0IoijSa8FmjlEW2HfWhY2BdKsNxqM6yzkJFKcMm3j # PP2pg75O+kEhnoPgahY1NQtf6zixtf7ci5XeF/eS6GIzvR52zzY/cnXce86/iESd # +/iEHKmqONIRtn1gV3xUcXotHAnzdQquta8E7yjPRGYbXZhbfju4iVr5rSeo/alC # iYsr69phToJhpN2dMBOUD+O/KApHWo2KS1XikndLu9D2kyr4toj9IGQsWAAZeuf+ # HdcxggMeMIIDGgIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2Vy # dCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25p # bmcgUlNBNDA5NiBTSEEzODQgMjAyMSBDQTECEAN2jtfarJ5Y/XzMlAOmOv0wCQYF # Kw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkD # MQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJ # KoZIhvcNAQkEMRYEFMByB6AXynfDCDLh9jvebhgv8YZiMA0GCSqGSIb3DQEBAQUA # BIICAKaEdBZNF6MIbX6Zyk/BQRTsCe//8fuizXFMYPSRM1mUfhdt36LFoyg8AQaX # dD5paOAdORZkoLACKEBz+7vNMz+uEOrlWz2RhBofBXbBpbNgr5ry/hpmfs38XgR3 # 654I+qoGyan753PX5mWX7TqVDQMtaAW8OlTqoBZX+MUAtkk2mSPfIUh/xH3OtzhO # LmVuFwEdVFpKG37wGt2X3ngpgLMfrjMOPLdFgwRt94988IrPk9LLjddMe7zn2SUZ # aUTvE4ozhxF82/Mcc3WcAjbu0hMPQJtSFRACm61y6pgGP+q2dnoqPhZaTJbeFms8 # C3MYQckd1AWPl97bmUeGqyyUWfulV5JFNM6aJxprLdTu1FnsDDVHtYe0wXbBpzCw # fMEXDAEXYOQm1mn+DH7dg5IvvhBj/cZuQdA5C6MNbuAhHMyiwhPQJ9qkzWs55+/P # DXOy44uLfeupNxegXWmiQmGea5iiRnOspc/Es98t6eLg5ZBkORGsX4gtemOjoBLt # u4nqxZx9YRd48bnXl/zJq0WdIKk9MAePxTBTkl9ze7hsXDuYHZ1dbLbF6CCgexy0 # C9n6nUlXc3xNChZHT+ju5du+fNXxClIrgLRO/rs17zg94dHi/4WpF+xhbuU2XdjZ # biaOUKQPozkLtbqqvX3iFkjBkHKVoKANs1894tdnOXX/c+CG # SIG # End signature block