################################################################################
# Write message to log file and output stream
################################################################################
Function Write-LogOutput($message)
{
    Write-Log $message
    Write-Output $message
}

################################################################################
# Install AX SSRS extension components with HTTP endpoints
################################################################################
Function Install-AxSsrsExtension
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$config,
        [Parameter(Mandatory=$true)]
        [string]$log
    )

    Import-Module "$PSScriptRoot\AosCommon.psm1" -DisableNameChecking

    # Initialize log file
    Initialize-Log $log
    $settings = Decode-Settings($config)
    Write-LogOutput $("")
    Write-LogOutput $settings | Format-List *

    # Get EnableSecurity value
    if ($null -eq $settings.EnableSecurity)
    {
        throw "Missing EnableSecurity value."
    }

    [Switch]$enableSecurity = [System.Convert]::ToBoolean($settings.EnableSecurity)

    [Switch]$isReportingClusterDeployment = $false
    [System.Boolean]::TryParse($settings.IsReportingClusterDeployment, [ref]$isReportingClusterDeployment)    

    # Check if use https
    if ((![System.String]::IsNullOrWhiteSpace($settings.SsrsSslCertificateThumbprint)) -and (![System.String]::IsNullOrWhiteSpace($settings.SsrsServerFqdn)))
    {
        Write-LogOutput "Install AX SSRS extension with HTTPS endpoints."
        Install-AxSsrsExtensionForHttps -config $config -log $log
        return
    }

    # Gets account list to acess reports
    [string[]] $accounts = $null
    if ($null -ne $settings.AccountListToAccessReports)
    {
        $accounts = $settings.AccountListToAccessReports.split(',')
    }

    # Use AxReportVmRoleStartupTask.exe to install reporting extensions
    Write-LogOutput $("Start installing AX SSRS extensions ...")

    [string] $reportServerUri = "http://localhost:80/ReportServer"
    [string] $ManagementAssemblyPath = Join-Path -Path $PSScriptRoot -ChildPath "Microsoft.Dynamics.AX.Framework.Management.dll"
	[string] $SystemReportTimeoutConfigName = "SystemReportTimeout"
	[string] $SessionTimeoutConfigName = "SessionTimeout"
    Import-Module $ManagementAssemblyPath
    
    # Need to install SSRS extension first with windows auth to install data sources for reporting cluster mode
    if ($isReportingClusterDeployment)
    {
        $settings.IsReportingClusterDeployment = "False"
        $settings.EnableSecurity = "True"
        $settingsJson = ConvertTo-Json $settings
        $windowsAuthConfig = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($settingsJson))

        Setup-SSRSExtension -config $windowsAuthConfig -log $log -ErrorAction Stop

        # Set SSRS system report timeout to 1 hour
        Write-LogOutput $("Set the SSRS system report timeout to 60 minutes...")
        Set-SsrsConfigurationInfoTimeout -timeoutInSeconds 3600 -reportServerUri $reportServerUri -configName $SystemReportTimeoutConfigName

		# Set SSRS session timeout to 1 hour
        Write-LogOutput $("Set the SSRS session timeout to 60 minutes...")
		Set-SsrsConfigurationInfoTimeout -timeoutInSeconds 3600 -reportServerUri $reportServerUri -configName $SessionTimeoutConfigName

        # Set execution log days kept to 1 day
        # The records of execution log would be uploaded to Kusto every 5 minutes
        $dayskeptValue = 1
        Write-LogOutput $("Set SSRS execution log days kept value to $dayskeptValue days...")
        Set-SsrsExecutionLogDaysKept -daysKept $dayskeptValue -reportServerUri $reportServerUri

        $settings.IsReportingClusterDeployment = "True"
        $settings.EnableSecurity = $enableSecurity.ToString();

        # Install shared data sources
        Install-DataSource -reportServerUri $reportServerUri -log $log

        # Create the root report folder /Dynamics
        Install-AxReportRootFolder -ReportServerAddress "localhost" -SkipReportServerAdminCheck  -ErrorAction Stop | Tee-Object -Variable InstallLog
        Add-Content -Path $log -Value $InstallLog
    }

    # Deploy SSRS extension
    Setup-SSRSExtension -config $config -log $log -ErrorAction Stop
    Write-LogOutput $("Completed installing AX SSRS extension.")
		
    #Added this step to warmup SSRS to avoid the timeout error
    $serviceName = Get-SsrsServiceName
    Write-LogOutput ("The reporting service name is: $serviceName.")
    Restart-WindowsService -log $log -computerName $env:COMPUTERNAME -serviceName $serviceName -ErrorAction stop
    Test-ReportServer -reportServerUri $reportServerUri -log $log -ErrorAction Stop

    # Install shared data sources
    if (-not $isReportingClusterDeployment)
    {
        Install-DataSource -reportServerUri $reportServerUri -log $log
    }

    if ($enableSecurity)
    {
        # Start Creating and configuring AX reports root folder
        Write-LogOutput $("")
        Write-LogOutput $("Start creating and configuring AX reports root folder ...")			
        Install-AxReportRootFolder -Accounts $accounts  -ErrorAction Stop | Tee-Object -Variable InstallLog          
        Add-Content -Path $log -Value $InstallLog
        Write-LogOutput $("Completed creating and configuring AX reports root folder.")
        Write-LogOutput $("")
    }

    # Test the SSRS instance prior to completing this step. If this is not successful then we should fail.
    Restart-WindowsService -log $log -computerName $env:COMPUTERNAME -serviceName $serviceName -ErrorAction stop
    Test-ReportServer -reportServerUri $reportServerUri -log $log -ErrorAction Stop
    Write-LogOutput $("")
}

################################################################################
# Install AX SSRS extension components with HTTP endpoints
################################################################################
Function Install-AxSsrsExtensionForHttps
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$config,
        [Parameter(Mandatory=$true)]
        [string]$log
    )

    Import-Module "$PSScriptRoot\AosCommon.psm1" -DisableNameChecking

    # Initialize log file
    Initialize-Log $log
    $settings = Decode-Settings($config)
    Write-LogOutput $("")
    Write-LogOutput $settings | Format-List *    

    # Enable security
    [Switch]$enableSecurity = [System.Convert]::ToBoolean($settings.EnableSecurity)

    # IsServiceFabricDeployment (Set to true by LBD deployment)
    [Switch]$isServiceFabricDeployment = $false
    [System.Boolean]::TryParse($settings.IsServiceFabricDeployment, [ref]$isServiceFabricDeployment)

    # Gets account list to acess reports
    [string[]] $accounts = $null
    if ($null -ne $settings.AccountListToAccessReports)
    {
        $accounts = $settings.AccountListToAccessReports.split(',')
    }

    # Make sure HTTPS required parameters are set properly
    $sslCertThumbprint = $settings.SsrsSslCertificateThumbprint
    $serverFqdn = $settings.SsrsServerFqdn
    $httpsPort = $settings.SsrsHttpsPort
    $useHttps = (![System.String]::IsNullOrWhiteSpace($sslCertThumbprint)) -and (![System.String]::IsNullOrWhiteSpace($serverFqdn))
    if (-not $useHttps)
    {
        throw "Install-AxSsrsExtensionForHttps should not be called because SSLCertThumbprint: $sslCertThumbprint, Server FQDN: $serverFqdn."
    }

    $httpsPortValue = 443
    if ($httpsPort)
    {
        if (-not [Int32]::TryParse($settings.SsrsHttpsPort, [ref]$httpsPortValue))
        {
            throw "Invalid vlaue for SsrsHttpsPort. The value is: $httpsPort"
        }
    }

    # Import management module
    [string] $ManagementAssemblyPath = Join-Path -Path $PSScriptRoot -ChildPath "Microsoft.Dynamics.AX.Framework.Management.dll"
    Import-Module $ManagementAssemblyPath
    $lcid = [System.Globalization.CultureInfo]::GetCultureInfo('en-US').LCID

    try 
    {
        # Use AxReportVmRoleStartupTask.exe to install reporting extensions. This will create an http endpoint for data source and ax report folder configuration
        Write-LogOutput $("Start installing AX SSRS extensions ...")
        Setup-SSRSExtension -config $config -log $log -ErrorAction Stop
        Write-LogOutput $("Completed installing AX SSRS extension.")
    
        # Install shared data sources and their parent folder if they do not exist
        Install-DataSource -reportServerUri "http://localhost/reportserver" -log $log
            
        # Start creating and configuring AX reports root folder security
        if ($enableSecurity)
        {
            Write-LogOutput $("")
            Write-LogOutput $("Start creating and configuring AX reports root folder ...")			
            Install-AxReportRootFolder -Accounts $accounts -DeleteExisting:$false -GrantPublishReportPermission:$isServiceFabricDeployment -ErrorAction Stop | Tee-Object -Variable InstallLog
            Add-Content -Path $log -Value $InstallLog
            Write-LogOutput $("Completed creating and configuring AX reports root folder.")
            Write-LogOutput $("")
        }
    }
    finally 
    {
        # Make sure that http endpoint is deleted.
        $rsConfig = Get-RsConfig -ComputerName $env:COMPUTERNAME
        Remove-HttpUrl -rsConfig $rsConfig -lcid $lcid
    }

    # Ensure SSRS endpoints to Use HTTPS
    Write-LogOutput $("Start configuring SSRS HTTPS endpoint with port: $httpsPort, cert: $sslCertThumbprint, FQDN: $serverFqdn")

    $httpsReportServerUrl = "https://" + $serverFqdn + ":" + $httpsPortValue.ToString() + "/ReportServer"
    Write-LogOutput $("HTTPS Report Server URL is: $httpsReportServerUrl")

    Confirm-SsrsHttpsEndpoints -Port $httpsPortValue -Log $log -SslCertThumbprint $sslCertThumbprint -ErrorAction Stop
    Write-LogOutput $("SSRS HTTPS endpoints were configured.")
    Write-LogOutput $("")
        
    # Added this step to warmup SSRS to avoid the timeout error
    $serviceName = Get-SsrsServiceName
    Write-LogOutput ("The reporting service name is: $serviceName.")
    Restart-WindowsService -log $log -computerName $env:COMPUTERNAME -serviceName $serviceName -ErrorAction stop
    $localHttpsReportServerUrl = $("https://localhost:" + $httpsPortValue.ToString() + "/ReportServer")
    Test-ReportServer -reportServerUri $localHttpsReportServerUrl -forceTls12 $true -ignoreServerCertificate $true -log $log -ErrorAction Stop
}


################################################################################
# Install Data source (for reporting that does not need deployment)
################################################################################
Function Install-DataSource
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$reportServerUri,
        [Parameter(Mandatory=$true)]
        [string]$log
    )

    Test-ReportServer -reportServerUri $reportServerUri -log $log -ErrorAction Stop
	Write-LogOutput $("")
    Write-LogOutput $("Start creating report shared data sources...")

    Install-SharedDataSource -ErrorAction Stop | Tee-Object -Variable InstallLog
    Add-Content -Path $log -Value $InstallLog
    Write-LogOutput $("Completed creating report shared data sources.")
}

################################################################################
# Setup SSRS Extension by calling exe
################################################################################
Function Setup-SSRSExtension
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$config,
        [Parameter(Mandatory=$true)]
        [string]$log
    )

    $deployExtensionExe = Join-Path -Path $PSScriptRoot -ChildPath "AxReportVmRoleStartupTask.exe"
    Write-LogOutput $deployExtensionExe
    $allArgs = @("-config", $config)
    & $deployExtensionExe $allArgs *>&1
    $exitCode = $LASTEXITCODE
    if ($exitCode -ne 0)
    {
        throw "Error occurred when running AxReportVmRoleStartupTask.exe to install extension. Please see details in events for AX-ReportPVMSetup."
    }
}


################################################################################
# Uninstall AX SSRS extension components
# $config parameter must have a property EnableSecurity with value "true" or "false"
################################################################################
Function Remove-AxSsrsExtension
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$config,
        [Parameter(Mandatory=$true)]
        [string]$log
    )

    Import-Module "$PSScriptRoot\AosCommon.psm1" -DisableNameChecking

    # Initialize log file
    Initialize-Log $log

    # Verify deployment type
    $settings = Decode-Settings($config)
    Write-LogOutput $("")
    Write-LogOutput $settings | Format-List *
    if ($settings.EnableSecurity -eq $null)
    {
        throw "Missing EnableSecurity value."
    }

    [Switch]$enableSecurity = [System.Convert]::ToBoolean($settings.EnableSecurity)

    # Remove Https
    $removeHttps = $false
    if ($settings.RemoveHttps)
    {
        if (-not [System.Boolean]::TryParse($settings.RemoveHttps, [ref]$removeHttps))
        {
            throw "RemoveHttps must be 'true' or 'false'."
        }
    }

    # Verify/Add IsUninstallOnly value (true) to the $config string
    Write-LogOutput $("Verify/Add IsUninstallOnly parameter to the config string...")
    [string]$uninstallConfig = $config
    if (Get-Member -InputObject $settings -Name "IsUninstallOnly" -MemberType Properties)
    {
        if (![string]::Equals($settings.IsUninstallOnly, "true", [System.StringComparison]::OrdinalIgnoreCase))
        {
            throw "IsUninstallOnly must be true for uninstallation."
        }

        Write-LogOutput $("Completed verifying IsUninstallOnly value in the config string.")
    }
    else
    {
        $settings|Add-Member -type NoteProperty -Name "IsUninstallOnly" -Value "true"
        $uninstallConfig = ConvertTo-Json $settings
        $uninstallConfig = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($uninstallConfig))
        Write-LogOutput $("Completed Adding IsUninstallOnly value in the config string.")
    }

    # Use AxReportVmRoleStartupTask.exe to uninstall reporting extensions
    Write-LogOutput("")
    Write-LogOutput $("Start uninstalling AX SSRS extensions ...")

    $deployExtensionExe = Join-Path -Path $PSScriptRoot -ChildPath "AxReportVmRoleStartupTask.exe"
    $allArgs = @("-config", $uninstallConfig)
    & $deployExtensionExe $allArgs *>&1
    $exitCode = $LASTEXITCODE
    if ($exitCode -eq 0)
    {
        $serviceName = Get-SsrsServiceName
        Write-LogOutput ("The reporting service name is: $serviceName.")
        Restart-WindowsService -log $log -computerName $env:COMPUTERNAME -serviceName $serviceName -ErrorAction stop
        Write-LogOutput $("Completed uninstalling AX SSRS extension.")
    }
    else
    {
        throw "Error occurred when running AxReportVmRoleStartupTask.exe to uninstall extension. Please see details in events for AX-ReportPVMSetup."
    }

    if ($removeHttps)
    {
        Write-LogOutput "Start removing all https endpoints and SSL cert bindings"
        Config-SsrsEndpoint -Port 80 -Log $log -ErrorAction Stop
        Write-LogOutput "Completed removing all https endpoints and SSL cert bindings"
    }
}

################################################################################
# Format report publishing results
################################################################################
Function Format-PublishOutput 
{
    param
    (
        [Parameter(ValueFromPipeline=$true,Position=0)] 
        $result
    )

    process
    {
        if ($result -is [Microsoft.Dynamics.AX.Framework.Management.Reports.ReportDeploymentResult])
        {
            $result | Select-Object ReportName, ReportDeploymentStatus
        }
        else
        {
            $result
        }
    }
}


################################################################################
# Deploy AX reports To SSRS server
################################################################################
Function Deploy-AxReport
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$config,
        [Parameter(Mandatory=$true)]
        [string]$log
    )

    Import-Module "$PSScriptRoot\AosCommon.psm1" -DisableNameChecking

    # Initialize the log file
    Initialize-Log $log

    # Getting values from the JSON configuration string
    $settings = Decode-Settings($config)

    [string]$reportingServers = $settings."BiReporting.ReportingServers"
    [string]$packageInstallLocation = $settings."Microsoft.Dynamics.AX.AosConfig.AzureConfig.bindir"
    [string]$useHttps = $settings."BiReporting.SsrsUseHttps"
    [string]$httpsPort = $settings."BiReporting.SsrsHttpsPort"
    [string[]]$module = $settings.Module 
    [string[]]$reportName = $settings.ReportName

    # Popuate default values 
    Write-LogOutput $('Microsoft.Dynamics.AX.AosConfig.AzureConfig.bindir: ' + $packageInstallLocation)
    Write-LogOutput $('Module: ' + $module)
    Write-LogOutput $('ReportName: ' + $reportName)

    if ($module -eq $null -or $module.Length -eq 0)
    {
        $module = "*"
    }

    if ($reportName -eq $null -or $reportName.Length -eq 0)
    {
        $reportName = "*"
    }

    Write-LogOutput ""

    # Getting Protocol and Port for ReportServer service
    $protocol = "http://"
    $port = 80

    Write-LogOutput $("Getting the protocol and port ...")
    if (-not [String]::IsNullOrWhiteSpace($useHttps))
    {
        $useHttpsValue = $false
        if (-not [Boolean]::TryParse($useHttps, [ref]$useHttpsValue))
        {
            throw "Invalid value for BiReporting.SsrsUseHttps. The value is : $($useHttps)"
        }
    
        if ($useHttpsValue)
        {
            $protocol = "https://"
            $port = 443
            if (-not [String]::IsNullOrWhiteSpace($httpsPort))
            {
                if (-not [Int32]::TryParse($httpsPort, [ref]$port))
                {
                    throw "Invalid vlaue for BiReporting.SsrsHttpsPort. The value is: $httpsPort"
                }
            }
        }
    }
    
    Write-LogOutput $("Protocol: $protocol; Port: $port")
    Write-LogOutput ""

    # Split report servers string
    Write-LogOutput $('Reporting Servers: ' + $reportingServers)
    $rsServers = $reportingServers.Split(",", [System.StringSplitOptions]::RemoveEmptyEntries)|%{$_.trim()}
    $rsServers = $rsServers.Where({-not [System.String]::IsNullOrWhiteSpace($_)})
    
    # Test each SSRS instance prior to deploying any reports. If this is not successful
    # then there is no need to deploy reports.
    $reportServerUrls = @{}
    foreach ($rsServer in $rsServers)
    {
        [string]$rsUrl = $($protocol + $rsServer + ":" + $port.ToString() + "/ReportServer")
        Write-LogOutput $("Testing: $rsUrl ...")
        Test-ReportServer -reportServerUri $rsUrl -log $log -ErrorAction Stop
        $reportServerUrls.Add($rsServer, $rsUrl)
    }

    Write-LogOutput $("Testing reporting services completed.")
    Write-LogOutput ""
    
    # Start deploying reports
    Write-LogOutput $("Start deploying reports ...")
    $startTime = $(Get-Date)

    if ($rsServers.Count -eq 1)
    {
        [string]$ManagementAssemblyPath = Join-Path -Path $PSScriptRoot -ChildPath "Microsoft.Dynamics.AX.Framework.Management.dll"
        Import-Module $ManagementAssemblyPath

        $err = @()
        Publish-AXReport -MaxDegreeOfParallelism 1 -ErrorAction Continue -ErrorVariable err -ReportName $reportName -SkipReportServerAdminCheck -ReportServerAddress $reportServerUrls.Values[0] -BinDirectory $PackageInstallLocation -DeleteExisting -Module $module *>&1 | Format-PublishOutput | Tee-Object -Variable DeployReportsLog
        Add-Content -Path $log -Value $($DeployReportsLog | Out-String)
        Write-LogOutput $(($(Get-Date) - $startTime).TotalSeconds.ToString() + " Seconds.")

        if ($err.Count -gt 0)
        {
            throw "Errors occured during report deployment."
        }
    }
    else
    {
        foreach ($rsServer in $rsServers)
        {
            Start-Job -Name $("Job" + $rsServer) -ScriptBlock {
                Param
                (
                    [Parameter(Mandatory=$true)]
                    [string]$scriptRoot,
                    [Parameter(Mandatory=$true)]
                    [string]$rsUrlArg,
                    [Parameter(Mandatory=$true)]
                    [string[]]$reportNameArg,
                    [Parameter(Mandatory=$true)]
                    [string]$packageInstallLocationArg,
                    [Parameter(Mandatory=$true)]
                    [string[]]$moduleArg
                )

                Import-Module "$scriptRoot\AosCommon.psm1" -Force -DisableNameChecking -ErrorAction Stop
                Import-Module "$scriptRoot\Reporting.psm1" -Force -DisableNameChecking -ErrorAction Stop

                [string]$ManagementAssemblyPath = Join-Path -Path $scriptRoot -ChildPath "Microsoft.Dynamics.AX.Framework.Management.dll"
                Import-Module $ManagementAssemblyPath -ErrorAction Stop

                $err = @()
                Publish-AXReport -MaxDegreeOfParallelism 1 -ErrorAction Continue -ErrorVariable err -ReportName $reportNameArg -SkipReportServerAdminCheck -ReportServerAddress $rsUrlArg -BinDirectory $packageInstallLocationArg -DeleteExisting -Module $moduleArg *>&1 | Format-PublishOutput | Out-String -OutVariable DeployReportsLog
                return @{"Error" = $err; "Log" = $DeployReportsLog}
            } -ArgumentList $PSScriptRoot, $reportServerUrls[$rsServer], $reportName, $packageInstallLocation, $module
        }

        $allErrors = @() 
        foreach ($rsServer in $rsServers)
        {
            $job = Get-Job $("Job" + $rsServer)
            $jobResult = Receive-Job -Job $job -Wait -AutoRemoveJob

            if ($jobResult."Error")
            {
                $allErrors += $jobResult."Error"
            }

            if ($jobResult."Log")
            {
                Write-LogOutput $($jobResult."Log" | Out-String)
            }
        }

        Write-LogOutput $(($(Get-Date) - $startTime).TotalSeconds.ToString() + " Seconds.")

        foreach ($error in $allErrors)
        {
            if ($error.Count -gt 0)
            {
                throw @("Errors occured during report deployment for server " + $rsServer)
            }
        }
    }
}


################################################################################
# Remove all AX reports from SSRS server
################################################################################
Function Remove-AllAxReports
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$config,
        [Parameter(Mandatory=$true)]
        [string]$log
    )

    Import-Module "$PSScriptRoot\AosCommon.psm1" -DisableNameChecking

    # Initialize the log file
    Initialize-Log $log

    # Getting values from the JSON configuration string
    $settings = Decode-Settings($config)

    [string]$reportingServers = $settings."BiReporting.ReportingServers"
    [string[]]$reportName = $settings.ReportName
    [string]$useHttps = $settings."BiReporting.SsrsUseHttps"
    [string]$httpsPort = $settings."BiReporting.SsrsHttpsPort"    

    # populate default values
    Write-LogOutput $('ReportName: ' + $reportName)
    if ($reportName -eq $null -or $reportName.Length -eq 0)
    {
        $reportName = "*"
    }

    # Getting Protocol and Port for ReportServer service
    $protocol = "http://"
    $port = 80

    Write-LogOutput $("Getting the protocol and port ...")
    if (-not [String]::IsNullOrWhiteSpace($useHttps))
    {
        $useHttpsValue = $false
        if (-not [Boolean]::TryParse($useHttps, [ref]$useHttpsValue))
        {
            throw "Invalid value for BiReporting.SsrsUseHttps. The value is : $($useHttps)"
        }
    
        if ($useHttpsValue)
        {
            $protocol = "https://"
            $port = 443
            if (-not [String]::IsNullOrWhiteSpace($httpsPort))
            {
                if (-not [Int32]::TryParse($httpsPort, [ref]$port))
                {
                    throw "Invalid vlaue for BiReporting.SsrsHttpsPort. The value is: $httpsPort"
                }
            }
        }
    }
    
    Write-LogOutput $("Protocol: $protocol; Port: $port")
    Write-LogOutput ""    

    # split report servers string
    Write-LogOutput $('Reporting Servers: ' + $reportingServers)
    $rsServers = $reportingServers.Split(",", [System.StringSplitOptions]::RemoveEmptyEntries)|%{$_.trim()}
    $rsServers = $rsServers.Where({-not [System.String]::IsNullOrWhiteSpace($_)})
    
    # Test each SSRS instance prior to deploying any reports. If this is not successful
    # then there is no need to deploy reports.
    $reportServerUrls = @{}
    foreach ($rsServer in $rsServers)
    {
        [string]$rsUrl = $($protocol + $rsServer + ":" + $port.ToString() + "/ReportServer")
        Write-LogOutput $("Testing: $rsUrl ...")
        Test-ReportServer -reportServerUri $rsUrl -log $log -ErrorAction Stop
        $reportServerUrls.Add($rsServer, $rsUrl)
    }
    Write-LogOutput $("Testing reporting services completed.")
    Write-LogOutput ""

    # Start clearing reports
    Write-LogOutput $("Start removing reports ....")
    $startTime = $(Get-Date)

    if ($rsServers.Count -eq 1)
    {
        [string]$ManagementAssemblyPath = Join-Path -Path $PSScriptRoot -ChildPath "Microsoft.Dynamics.AX.Framework.Management.dll"
        Import-Module $ManagementAssemblyPath

        Remove-AxReport -ErrorAction Continue -MaxDegreeOfParallelism 1 -ReportName $reportName -ReportServerAddress $reportServerUrls.Values[0] *>&1 |  Format-PublishOutput | Tee-Object -Variable ReportRemovalLog
        Add-Content -Path $log -Value $ReportRemovalLog
        Write-LogOutput $(($(Get-Date) - $startTime).TotalSeconds.ToString() + " Seconds.")
    }
    else
    {
        foreach ($rsServer in $rsServers)
        {
            Start-Job -Name $("RmJob" + $rsServer) -ScriptBlock {
                Param
                (
                    [Parameter(Mandatory=$true)]
                    [string]$scriptRoot,
                    [Parameter(Mandatory=$true)]
                    [string]$rsUrlArg,
                    [Parameter(Mandatory=$true)]
                    [string[]]$reportNameArg
                )

                Import-Module "$scriptRoot\AosCommon.psm1" -Force -DisableNameChecking -ErrorAction Stop
                Import-Module "$scriptRoot\Reporting.psm1" -Force -DisableNameChecking -ErrorAction Stop

                [string]$ManagementAssemblyPath = Join-Path -Path $scriptRoot -ChildPath "Microsoft.Dynamics.AX.Framework.Management.dll"
                Import-Module $ManagementAssemblyPath -ErrorAction Stop

                Remove-AxReport -ErrorAction Continue -MaxDegreeOfParallelism 1 -ReportName $reportNameArg -ReportServerAddress $rsUrlArg *>&1 | Format-PublishOutput | Out-String -OutVariable ReportRemovalLog
            } -ArgumentList $PSScriptRoot, $reportServerUrls[$rsServer], $reportName
        }

        foreach ($rsServer in $rsServers)
        {
            $job = Get-Job $("RmJob" + $rsServer)
            $jobResultLog = Receive-Job -Job $job -Wait -AutoRemoveJob

            if ($jobResultLog)
            {
                Write-LogOutput $($jobResultLog | Out-String)
            }
        }

        Write-LogOutput $(($(Get-Date) - $startTime).TotalSeconds.ToString() + " Seconds.")
    }
}

################################################################################
# Install report fonts to SSRS server
################################################################################
Function Install-Font
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$config,
        [Parameter(Mandatory=$true)]
        [string]$log,
        [Parameter(Mandatory=$true)]
        [string]$fontFilePath
    )

    Import-Module "$PSScriptRoot\AosCommon.psm1" -DisableNameChecking

    # Initialize the log file
    Initialize-Log $log

    # Start installing fonts
    Write-Output("")
    Write-LogOutput "Start installing fonts to SSRS ..."
    Write-LogOutput $("Font file path: " + $fontFilePath)
    $MangementAssemblyPath = Join-Path -Path $PSScriptRoot -ChildPath "Microsoft.Dynamics.AX.Framework.Management.dll"
    Import-Module $MangementAssemblyPath

    (Get-ChildItem -Path $fontFilePath -Filter "*.ttf").FullName | Install-ReportFont *>&1 | Tee-Object -Variable ReportFontLog
    Add-Content -Path $log -Value $ReportFontLog

    # Restart SSRS
    $serviceName = Get-SsrsServiceName
    Write-LogOutput ("The reporting service name is: $serviceName.")
    Get-Service -Name $serviceName | Restart-Service *>&1 | Tee-Object -Variable RestartSsrsLog
    Add-Content -Path $log -Value $RestartSsrsLog

    Write-LogOutput $("Completed installing fonts to SSRS.")
}

#####################################################
# Configure SSRS web service and web app protocols
#####################################################
function Config-SsrsEndpoint
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [int]$Port,
        [Parameter(Mandatory=$true)]
        [string]$log,
        [Parameter(Mandatory=$false)]
        [string]$SslCertThumbprint
    )

    Import-Module "$PSScriptRoot\AosCommon.psm1" -DisableNameChecking

    $rsConfig = Get-RsConfig -ComputerName $env:COMPUTERNAME
    if (!$rsConfig)
    {
        throw "Could not find reporting service WMI object MSReportServer_ConfigurationSetting"
    }

    $lcid = [System.Globalization.CultureInfo]::GetCultureInfo('en-US').LCID
    $rsWebServiceAppName = 'ReportServerWebService'
    $reportManagerAppName = 'ReportServerWebApp'

    # Remove all existing ResvervedUrls
    $result = $rsConfig.ListReservedUrls()
    Verify-SsrsWmiCall -resultObject $result -methodName 'ListReservedurls'
    if ($result.Application)
    {
        for ($i = 0; $i -lt $result.Application.length; $i++)
        {
            $removeResult = $rsConfig.RemoveURL($result.Application[$i], $result.UrlString[$i], $lcid)
            Verify-SsrsWmiCall -resultObject $removeResult -methodName 'RemoveURL'
            Write-LogOutput $([string]::Format("Removed URL Application={0} UrlString= {1}", $result.Application[$i], $result.UrlString[$i]))
        }
    }

    $removedIpPorts = New-Object -TypeName System.Collections.Generic.HashSet[string]

    # Remove all SSL Certficate Bindings from Reporting Service
    $result = $rsConfig.ListSSLCertificateBindings($lcid)
    if ($result.Application)
    {
        for ($i = 0; $i -lt $result.Application.length; $i++)
        {
            $removeResult = $rsConfig.RemoveSSLCertificateBindings($result.Application[$i], $result.CertificateHash[$i], $result.IPAddress[$i], $result.Port[$i], $lcid)
            Verify-SsrsWmiCall -resultObject $removeResult -methodName 'RemoveSSLCertificateBindings'
            Write-LogOutput $([string]::Format("Removed SSL Binding Application={0} Certificate={1} IPAddress={2} Port={3}", $result.Application[$i], $result.CertificateHash[$i], $result.IPAddress[$i], $result.Port[$i]))

            Remove-SSLBindings -ipAddress $($result.IPAddress[$i]).ToString() -port $($result.Port[$i]).ToString() -removedIpPorts $removedIpPorts
        }
    }

    # Remove all SSL Certficate Bindings and ssl bindings from OS
    if ($SslCertThumbprint)
    {
        Remove-SSLBindings -ipAddress "0.0.0.0" -port $Port.ToString() -removedIpPorts $removedIpPorts
        Remove-SSLBindings -ipAddress "[::]" -port $Port.ToString() -removedIpPorts $removedIpPorts
        Remove-ReservedUrl -url "https://+:$($Port.ToString())/ReportServer/"
        Remove-ReservedUrl -url "https://+:$($Port.ToString())/Reports/"
    }

    # Reserve URL for web service and web app
    $urlString = $([string]::Format("http://+:{0}", $Port))
    if ($SslCertThumbprint)
    {
        $urlString = [string]::Format("https://+:{0}", $Port)
    }

    $rsConfig.SetVirtualDirectory($rsWebServiceAppName, "ReportServer", $lcid)
    $result = $rsConfig.ReserveURL($rsWebServiceAppName, $urlString, $lcid)
    Verify-SsrsWmiCall -resultObject $result -methodName 'ReserveURL'
    Write-LogOutput $([string]::Format("Reserved URL string {0} for {1}", $urlString, $rsWebServiceAppName))

    $rsConfig.SetVirtualDirectory($reportManagerAppName, "Reports", $lcid)
    $result = $rsConfig.ReserveURL($reportManagerAppName, $urlString, $lcid)
    Verify-SsrsWmiCall -resultObject $result -methodName 'ReserveURL'
    Write-LogOutput $([string]::Format("Reserved URL string {0} for {1}", $urlString, $reportManagerAppName))

    # Create SSL Certificate Bindings for web service and web app
    if ($SslCertThumbprint)
    {
        $ipV4Address = "0.0.0.0";
        $ipV6Address = "::";

        $result = $rsConfig.CreateSSLCertificateBinding($rsWebServiceAppName, $SslCertThumbprint, $ipV4Address, $Port, $lcid);
        Verify-SsrsWmiCall -resultObject $result -methodName 'CreateSSLCertificateBinding'
        Write-LogOutput $([string]::Format("Created SSL Certificate Binding Application={0} SslCertThumbPrint={1} IPAddress={2} Port={3}", $rsWebServiceAppName, $SslCertThumbprint, $ipV4Address, $Port))

        $result = $rsConfig.CreateSSLCertificateBinding($rsWebServiceAppName, $SslCertThumbprint, $ipV6Address, $Port, $lcid);
        Verify-SsrsWmiCall -resultObject $result -methodName 'CreateSSLCertificateBinding'
        Write-LogOutput $([string]::Format("Created SSL Certificate Binding Application={0} SslCertThumbPrint={1} IPAddress={2} Port={3}", $rsWebServiceAppName, $SslCertThumbprint, $ipV6Address, $Port))

        $result = $rsConfig.CreateSSLCertificateBinding($reportManagerAppName, $SslCertThumbprint, $ipV4Address, $Port, $lcid);
        Verify-SsrsWmiCall -resultObject $result -methodName 'CreateSSLCertificateBinding'
        Write-LogOutput $([string]::Format("Created SSL Certificate Binding Application={0} SslCertThumbPrint={1} IPAddress={2} Port={3}", $reportManagerAppName, $SslCertThumbprint, $ipV4Address, $Port))

        $result = $rsConfig.CreateSSLCertificateBinding($reportManagerAppName, $SslCertThumbprint, $ipV6Address, $Port, $lcid);
        Verify-SsrsWmiCall -resultObject $result -methodName 'CreateSSLCertificateBinding'
        Write-LogOutput $([string]::Format("Created SSL Certificate Binding Application={0} SslCertThumbPrint={1} IPAddress={2} Port={3}", $reportManagerAppName, $SslCertThumbprint, $ipV6Address, $Port))
    }

    #Restart reporting services service
    $serviceName = Get-SsrsServiceName
    Write-LogOutput ("The reporting service name is: $serviceName.")
    Restart-WindowsService -computerName $env:COMPUTERNAME -serviceName $serviceName -log $log
}

#####################################################
# Confirm SSRS web service and web app HTTPS endpoints
#####################################################
function Confirm-SsrsHttpsEndpoints
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$false)]
        [string]$SslCertThumbprint,
        [Parameter(Mandatory=$true)]
        [int]$Port,
        [Parameter(Mandatory=$true)]
        [string]$log
    )

    Import-Module "$PSScriptRoot\AosCommon.psm1" -DisableNameChecking

    $rsConfig = Get-RsConfig -ComputerName $env:COMPUTERNAME
    if (!$rsConfig)
    {
        throw "Could not find reporting service WMI object MSReportServer_ConfigurationSetting"
    }

    $lcid = [System.Globalization.CultureInfo]::GetCultureInfo('en-US').LCID
    $rsWebServiceAppName = 'ReportServerWebService'
    $reportManagerAppName = 'ReportServerWebApp'

    # Test whether local HTTPS URL is configured
    $serviceName = Get-SsrsServiceName
    Write-LogOutput ("The reporting service name is: $serviceName.")
    Restart-WindowsService -log $log -computerName $env:COMPUTERNAME -serviceName $serviceName -ErrorAction stop
    $localHttpsReportServerUrl = $("https://localhost:" + $httpsPortValue.ToString() + "/ReportServer")

    $reconfigEndoints = $false
    $httpsEndpointExists = $true
    try 
    {
        Test-ReportServer -reportServerUri $localHttpsReportServerUrl -forceTls12 $true -ignoreServerCertificate $true -log $log -ErrorAction Stop
    }
    catch 
    {
        $httpsEndpointExists = $false
    }

    if (-not $httpsEndpointExists)
    {
        # No https endpoint, so there is no need to validate.
        $reconfigEndoints = $true
    }
    else
    {
        # Validate whether SSL Bindings need to be updated
        $expectedSslBindings = @{}
        $expectedSslBindings.Add($("$rsWebServiceAppName-0.0.0.0-$Port-$SslCertThumbprint"), 1)
        $expectedSslBindings.Add($("$rsWebServiceAppName-::-$Port-$SslCertThumbprint"), 1)
        $expectedSslBindings.Add($("$reportManagerAppName-0.0.0.0-$Port-$SslCertThumbprint"), 1)
        $expectedSslBindings.Add($("$reportManagerAppName-::-$Port-$SslCertThumbprint"), 1)
        
        $result = $rsConfig.ListSSLCertificateBindings($lcid)
        $foundBindingCount = 0
        if ($result.Application -and $result.Application.Length -eq $expectedSslBindings.Count)
        {
            for ($i = 0; $i -lt $result.Application.length; $i++)
            {
                $bindingString = $("$($result.Application[$i])-$($result.IPAddress[$i])-$($result.Port[$i])-$($result.CertificateHash[$i])")
                if ($expectedSslBindings.ContainsKey($bindingString))
                {
                    Write-LogOutput "Found $bindingString"
                    $foundBindingCount++
                }
            }
        }

        if ($foundBindingCount -ne $expectedSslBindings.Count)
        {
            # SSL bindings do not have expected values, needs reconfig
            $reconfigEndoints = $true
        }
        else
        {
            # Remove all Http based URLs
            Write-LogOutput "SSRS reserved URLs and SSL bindings are already configured. Skip configuring."
            Remove-HttpUrl -rsConfig $rsConfig -lcid $lcid
        }
    }

    if ($reconfigEndoints)
    {
        Write-LogOutput "SSRS reserved URLs and SSL bindings need to be reconfigured."
        Config-SsrsEndpoint -Port $Port -log $log -SslCertThumbprint $SslCertThumbprint    
    }
}

####################################################################
# Remove SSL bindings from network configuration
####################################################################
function Remove-SSLBindings
{
    param 
    (
        [Parameter(Mandatory=$true)]
        [string]$ipAddress,
        [Parameter(Mandatory=$true)]
        [string]$port,
        [Parameter(Mandatory=$true)]
        [AllowEmptyCollection()]
        [System.Collections.Generic.HashSet[string]]$removedIpPorts
    )

    if ($ipAddress -eq "::")
    {
        $ipAddress = "[::]"
    }

    $ipAddressWithPort = "$($ipAddress):$($port)"
    if (!$removedIpPorts.Contains($ipAddressWithPort))
    {
        $showCommand = $("netsh http show sslcert ipport=$ipAddressWithPort")
        Write-LogOutput ""
        Write-LogOutput("Check SSL cert bindings from computer network config with '$showCommand")
        $netshResult = Invoke-Expression $showCommand -ErrorAction Stop
        Write-LogOutput $netshResult

        if ($netshResult.Count -ge 10)
        {
            $removeCommand = $("netsh http delete sslcert ipport=$ipAddressWithPort")
            Write-LogOutput("Remove SSL cert bindings from computer network config with '$removeCommand")
            $netshResult = Invoke-Expression $removeCommand -ErrorAction Stop
            $removedIpPorts.Add($ipAddressWithPort) | Out-Null
            Write-LogOutput $netshResult
        }
    }
}

####################################################################
# Remove reserved URL
####################################################################
function Remove-ReservedUrl
{
    param 
    (
        [Parameter(Mandatory=$true)]
        [string]$url
    )

    $showCommand = $("netsh http show urlacl url=$url")
    Write-LogOutput ""
    Write-LogOutput $("Check reserved URL with $showCommand")
    $netshResult = Invoke-Expression $showCommand -ErrorAction Stop
    Write-LogOutput $netshResult

    if ($netshResult.Count -ge 6)
    {
        $removeCommand = $("netsh http delete urlacl url=$url")
        Write-LogOutput $("Remove reserved URL with $removeCommand")
        $netshResult = Invoke-Expression $removeCommand -ErrorAction Stop
        Write-LogOutput $netshResult
    }
}

####################################################################
# Remove all HTTP based URLs
####################################################################
function Remove-HttpUrl
{
    param 
    (
        [Parameter(Mandatory=$true)]
        $rsConfig,
        [Parameter(Mandatory=$true)]
        $lcid
    )

    Write-LogOutput "Remove all HTTP URLs..."
    $result = $rsConfig.ListReservedUrls()
    Verify-SsrsWmiCall -resultObject $result -methodName 'ListReservedurls'
    if ($result.Application)
    {
        for ($i = 0; $i -lt $result.Application.length; $i++)
        {
            if ($result.UrlString[$i] -and $result.UrlString[$i].StartsWith("http://", [System.StringComparison]::OrdinalIgnoreCase))
            {
                $removeResult = $rsConfig.RemoveURL($result.Application[$i], $result.UrlString[$i], $lcid)
                Verify-SsrsWmiCall -resultObject $removeResult -methodName 'RemoveURL'
                Write-LogOutput $([string]::Format("Removed URL Application={0} UrlString= {1}", $result.Application[$i], $result.UrlString[$i]))
            }
        }
    }    
}

####################################################################
# Verify SSRS WMI calls
####################################################################
function Verify-SsrsWmiCall
{
    param
    (
        $resultObject,
        $methodName
    )

    if (!$resultObject)
    {
        throw $("Returned Null object when calling $methodName")
    }

    if ($resultObject.HRESULT -ne 0)
    {
        throw $("Error occured when calling {0}. HResult = {1} Error={2}" -f $methodName, $resultObject.HRESULT, $resultObject.Error)
    }
}


################################################################################
# Test the SSRS Server
################################################################################
Function Test-ReportServer
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$reportServerUri,
        [Parameter(Mandatory=$false)]
        [bool]$ignoreServerCertificate = $false,
        [Parameter(Mandatory=$false)]
        [bool]$forceTls12 = $false,
        [Parameter(Mandatory=$true)]
        [string]$log
    )

    # Initialize the log file
    Initialize-Log $log

    Write-LogOutput $('Checking status of Report Server URL: ' + $reportServerUri)

    # Assume a 400 response code
    $statusCode = 400

	$MaxNumberOfRetries = 5
    $retry = 1
    while($retry -le $MaxNumberOfRetries)
    {
        try
        {
            try
            {
                # Invoke the web request and get the status
                $uri = New-Object -TypeName System.Uri($reportServerUri)
                [System.Net.HttpWebRequest]$request = [System.Net.HttpWebRequest]::CreateHttp($uri)
        
                $request.Timeout = 5 * 60 * 1000 
                $request.UseDefaultCredentials = $true
                $request.KeepAlive = $false
                if ($ignoreServerCertificate)
                {
                    $request.ServerCertificateValidationCallback = {$true}
                }

                if ($forceTls12)
                {
                    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
                }

                [System.Net.WebResponse]$response = $request.GetResponse()
                $statusCode = $response.StatusCode
            }
            catch [System.Net.WebException]
            {
                Write-LogOutput $('Failure! Status check of Report Server URL: ' + $reportServerUri)
                Write-LogOutput $($_.Exception.ToString())

                throw "An exception of type System.Net.WebException occurred when making an http request to: " + $reportServerUri + ". Refer to the log file for more details."
            }
    
            # check the status code is 200 OK 
            if ($statusCode -eq 200)
            {
                Write-LogOutput $('Success! Status check of Report Server URL: ' + $reportServerUri)
            }
            else
            {
                Write-LogOutput $('Failure! Status check of Report Server URL: ' + $reportServerUri)
                Write-LogOutput $('StatusCode value: ' + $statusCode)

                throw "Http response contains StatusCode of " + $statusCode + ". Unable to communicate with the SQL Server ReportServer service."
            }
	
            break
        }
        catch
        {
            if ($retry -lt $MaxNumberOfRetries)
            {
                $retry++
                [int]$waitSeconds = 10
                Write-LogOutput $('Wait ' + $waitSeconds + ' seconds and retry count ' + $retry + '(' + $MaxNumberOfRetries + ')')
                Start-Sleep -Seconds $waitSeconds
            }
            else
            {
                throw
            }
        }
    }
}

################################################################################
# Restart a windows service
################################################################################
function Restart-WindowsService
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$log,
        [Parameter(Mandatory=$true)]
        [string]$computerName,
        [Parameter(Mandatory=$true)]
        [string]$serviceName
    )

    Import-Module "$PSScriptRoot\AosCommon.psm1" -DisableNameChecking

    # Initialize log file
    Initialize-Log $log

    $retryCount = 3;

    while ($retryCount -gt 0)
    {
        Write-LogOutput $("Restart " + $serviceName + " service on " + $computerName + "...")
        
        try
        {
            Get-Service -ErrorAction Stop -Name $serviceName -ComputerName $computerName | Restart-Service -ErrorAction Stop -Force *>&1 | Tee-Object -Variable RestartServiceLog
            Add-Content -Path $log -Value $RestartServiceLog
            break
        }
        catch
        {
            $retryCount -= 1;
            if ($retryCount -le 0)
            {
                throw
            }

            Start-Sleep -Seconds 30
        }
    }

    Write-LogOutput $($serviceName + " service restarted on " + $computerName)
}

################################################################################
# Get reporting service config WMI object
################################################################################
function Get-RsConfig
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$ComputerName
    )

    Import-Module "$PSScriptRoot\AosCommon.psm1" -DisableNameChecking

    try
    {
        # SSRS 2019
        Write-Log "Searching SSRS 2019 WMI object"
        $rsconfig = Get-WmiObject -ErrorAction Stop –namespace "root\Microsoft\SqlServer\ReportServer\RS_SSRS\v15\Admin" –class MSReportServer_ConfigurationSetting –ComputerName $ComputerName -Filter "InstanceName='SSRS'"
        Write-Log "Found SSRS 2019 WMI object"
    }
    catch
    {
        try
        {
            # SSRS 2016
            Write-Log "Searching SSRS 2016 WMI object"
            $rsconfig = Get-WmiObject -ErrorAction Stop –namespace "root\Microsoft\SqlServer\ReportServer\RS_MSSQLSERVER\v13\Admin" –class MSReportServer_ConfigurationSetting –ComputerName $ComputerName -Filter "InstanceName='MSSQLSERVER'"
            Write-Log "Found SSRS 2016 WMI object"
        }
        catch
        {
            Write-Log $($_.Exception.ToString())
            throw "SSRS WMI object was not found."
        }
    }

    return $rsconfig
}

################################################################################
# Set SSRS system report timeout limit
################################################################################
function Set-SsrsConfigurationInfoTimeout
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [ValidateRange(1800, 7200)]
        [int]$timeoutInSeconds,
        [Parameter(Mandatory=$true)]
        [string]$reportServerUri,
		[Parameter(Mandatory=$true)]
        [string]$configName
    )

    Set-SsrsConfigurationSystemProperty -reportServerUri $reportServerUri -propertyName $configName -propertyValue $timeoutInSeconds
}

################################################################################
# Set SSRS execution log days kept property value
################################################################################
function Set-SsrsExecutionLogDaysKept
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [ValidateRange(0, 60)]
        [int]$daysKept,
        [Parameter(Mandatory=$true)]
        [string]$reportServerUri
    )

    $propertyName = "ExecutionLogDaysKept"
    Set-SsrsConfigurationSystemProperty -reportServerUri $reportServerUri -propertyName $propertyName -propertyValue $daysKept
}

################################################################################
# Set SSRS system report timeout limit
################################################################################
function Set-SsrsConfigurationSystemProperty
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [string]$reportServerUri,
		[Parameter(Mandatory=$true)]
        [string]$propertyName,
        [Parameter(Mandatory=$true)]
        [string]$propertyValue
    )

    $proxyUri = [System.IO.Path]::Combine($reportServerUri, "ReportService2005.asmx")
    $rsProxy = New-WebServiceProxy -Uri $proxyUri -UseDefaultCredential
    $systemProperties = $rsProxy.GetSystemProperties($null)
    if (-not $systemProperties)
    {
        throw "Could not get SSRS system properties"
    }

    $systemProperty = $systemProperties | Where-Object {$_.Name -eq $propertyName}
    if (-not $systemProperty)
    {
        throw "Could not find SSRS system property $propertyName"
    }

    # set system report timeout 
    $systemProperty.Value = $propertyValue
    $changeProperties = @($systemProperty)
    $rsProxy.SetSystemProperties($changeProperties)
}

################################################################################
# Get SSRS service name
################################################################################
function Get-SsrsServiceName
{
    Import-Module "$PSScriptRoot\AosCommon.psm1" -DisableNameChecking

    $productNamePath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
    $productNameItem = 'ProductName'
    $ssrs2019ServiceName = 'SQLServerReportingServices'
    $ssrs2016ServiceName = 'ReportServer'
    $ssrsService = Get-Service -Name $ssrs2019ServiceName -ErrorAction SilentlyContinue
        
    if ($ssrsService)
    {
        Write-Log "The SSRS 2019 reporting services name is set to $ssrsService"
        $ssrsServiceName = $ssrsService.Name;
    }
    else
    {
        $ssrsService = Get-Service -Name $ssrs2016ServiceName -ErrorAction SilentlyContinue

        if ($ssrsService)
        {
            Write-Log "The SSRS 2016 reporting services name is set to $ssrsService"
            $ssrsServiceName = $ssrsService.Name;
        }
    }

    if ($ssrsServiceName)
    {
        Write-Log "The SSRS service name from reporting services is $ssrsServiceName."
        return $ssrsServiceName
    }
    else
    {
        Write-Log 'Looking up reporting services name from OS.'
        if (Test-Path -Path $productNamePath -PathType Container)
        {
            $productNamePathItem = Get-ItemProperty -Path $productNamePath 
            $productNameMember = Get-Member -InputObject $productNamePathItem -Name $productNameItem

            if($productNameMember)
            {
                $productName = (Get-ItemProperty -Path $productNamePath -Name $productNameItem).$productNameItem
                Write-Log 'The product name is: ' + $productName
            }
        }

        if (($productName -eq 'Windows Server 2016 Datacenter') -or ($productName -eq 'Windows Server 2016 Standard'))
        {
            return $ssrs2016ServiceName
        }

        if (($productName -eq 'Windows Server 2019 Datacenter') -or  ($productName -eq 'Windows Server 2019 Standard'))
        {
            return $ssrs2019ServiceName
        }

        throw "The product name $productName is not a supported product"
    }
}
# SIG # Begin signature block
# MIIoLQYJKoZIhvcNAQcCoIIoHjCCKBoCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCVVfwGbQln0ko9
# xtZI9EeJWWhVmG7bLJ+MLOuyNevoxKCCDXYwggX0MIID3KADAgECAhMzAAADTrU8
# esGEb+srAAAAAANOMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjMwMzE2MTg0MzI5WhcNMjQwMzE0MTg0MzI5WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDdCKiNI6IBFWuvJUmf6WdOJqZmIwYs5G7AJD5UbcL6tsC+EBPDbr36pFGo1bsU
# p53nRyFYnncoMg8FK0d8jLlw0lgexDDr7gicf2zOBFWqfv/nSLwzJFNP5W03DF/1
# 1oZ12rSFqGlm+O46cRjTDFBpMRCZZGddZlRBjivby0eI1VgTD1TvAdfBYQe82fhm
# WQkYR/lWmAK+vW/1+bO7jHaxXTNCxLIBW07F8PBjUcwFxxyfbe2mHB4h1L4U0Ofa
# +HX/aREQ7SqYZz59sXM2ySOfvYyIjnqSO80NGBaz5DvzIG88J0+BNhOu2jl6Dfcq
# jYQs1H/PMSQIK6E7lXDXSpXzAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUnMc7Zn/ukKBsBiWkwdNfsN5pdwAw
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwMDUxNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAD21v9pHoLdBSNlFAjmk
# mx4XxOZAPsVxxXbDyQv1+kGDe9XpgBnT1lXnx7JDpFMKBwAyIwdInmvhK9pGBa31
# TyeL3p7R2s0L8SABPPRJHAEk4NHpBXxHjm4TKjezAbSqqbgsy10Y7KApy+9UrKa2
# kGmsuASsk95PVm5vem7OmTs42vm0BJUU+JPQLg8Y/sdj3TtSfLYYZAaJwTAIgi7d
# hzn5hatLo7Dhz+4T+MrFd+6LUa2U3zr97QwzDthx+RP9/RZnur4inzSQsG5DCVIM
# pA1l2NWEA3KAca0tI2l6hQNYsaKL1kefdfHCrPxEry8onJjyGGv9YKoLv6AOO7Oh
# JEmbQlz/xksYG2N/JSOJ+QqYpGTEuYFYVWain7He6jgb41JbpOGKDdE/b+V2q/gX
# UgFe2gdwTpCDsvh8SMRoq1/BNXcr7iTAU38Vgr83iVtPYmFhZOVM0ULp/kKTVoir
# IpP2KCxT4OekOctt8grYnhJ16QMjmMv5o53hjNFXOxigkQWYzUO+6w50g0FAeFa8
# 5ugCCB6lXEk21FFB1FdIHpjSQf+LP/W2OV/HfhC3uTPgKbRtXo83TZYEudooyZ/A
# Vu08sibZ3MkGOJORLERNwKm2G7oqdOv4Qj8Z0JrGgMzj46NFKAxkLSpE5oHQYP1H
# tPx1lPfD7iNSbJsP6LiUHXH1MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
# /Xmfwb1tbWrJUnMTDXpQzTGCGg0wghoJAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAANOtTx6wYRv6ysAAAAAA04wDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEICCs57Dg2p7XKkSECEs0oCgR
# KX0GP+piXOGp1nEHMN7JMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEA0YwT2+ZGVkUJMm+kdzRumYLsRPMVtvX75Zr8ODNfxqxozgB/QpgcaftU
# UURJ2WgWZTuifog4R/ttxYObTG/cVB9EpErxE3dSNp2r/DEQ69J3bw2aGq1DpP6n
# lO1lnbhGGKrpkpMHcMa8wA8vTSFtYweqV0xnIICaCWKFjFMi+kcFys1gulWjN3jp
# 7w7OMb4qsKLEDrlkxZSIOBmuh4rGJlI6+xICwnuLnCSyhgHdGCw2ZHPw4n91p5vG
# 9B+WhuOppzljn4vAKJ596jp+YjAehpujW/nGHhXl4MycIMnDbZmp5+p/IUB8nOmA
# heZqZ8ZxODtV9MrHgXaZ+6FYvCTRk6GCF5cwgheTBgorBgEEAYI3AwMBMYIXgzCC
# F38GCSqGSIb3DQEHAqCCF3AwghdsAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCAlby0gZCfns+6Lj+fD+x14U7iSOiIlrg84+LM+DDze0gIGZSieArm+
# GBMyMDIzMTAxOTA3MDEzMC44MDFaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046MzcwMy0w
# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
# ghHtMIIHIDCCBQigAwIBAgITMwAAAdTk6QMvwKxprAABAAAB1DANBgkqhkiG9w0B
# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMzA1MjUxOTEy
# MjdaFw0yNDAyMDExOTEyMjdaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046MzcwMy0wNUUwLUQ5NDcxJTAjBgNV
# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQCYU94tmwIkl353SWej1ybWcSAbu8FLwTEtOvw3uXMp
# a1DnDXDwbtkLc+oT8BNti8t+38TwktfgoAM9N/BOHyT4CpXB1Hwn1YYovuYujoQV
# 9kmyU6D6QttTIKN7fZTjoNtIhI5CBkwS+MkwCwdaNyySvjwPvZuxH8RNcOOB8ABD
# hJH+vw/jev+G20HE0Gwad323x4uA4tLkE0e9yaD7x/s1F3lt7Ni47pJMGMLqZQCK
# 7UCUeWauWF9wZINQ459tSPIe/xK6ttLyYHzd3DeRRLxQP/7c7oPJPDFgpbGB2HRJ
# aE0puRRDoiDP7JJxYr+TBExhI2ulZWbgL4CfWawwb1LsJmFWJHbqGr6o0irW7IqD
# kf2qEbMRT1WUM15F5oBc5Lg18lb3sUW7kRPvKwmfaRBkrmil0H/tv3HYyE6A490Z
# FEcPk6dzYAKfCe3vKpRVE4dPoDKVnCLUTLkq1f/pnuD/ZGHJ2cbuIer9umQYu/Fz
# 1DBreC8CRs3zJm48HIS3rbeLUYu/C93jVIJOlrKAv/qmYRymjDmpfzZvfvGBGUbO
# px+4ofwqBTLuhAfO7FZz338NtsjDzq3siR0cP74p9UuNX1Tpz4KZLM8GlzZLje3a
# HfD3mulrPIMipnVqBkkY12a2slsbIlje3uq8BSrj725/wHCt4HyXW4WgTGPizyEx
# TQIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFDzajMdwtAZ6EoB5Hedcsru0DHZJMB8G
# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQC0xUPP+ytwktdRhYlZ9Bk4/bLzLOzq+wcC
# 7VAaRQHGRS+IPyU/8OLiVoXcoyKKKiRQ7K9c90OdM+qL4PizKnStLDBsWT+ds1ha
# yNkTwnhVcZeA1EGKlNZvdlTsCUxJ5C7yoZQmA+2lpk04PGjcFhH1gGRphz+tcDNK
# /CtKJ+PrEuNj7sgmBop/JFQcYymiP/vr+dudrKQeStcTV9W13cm2FD5F/XWO37Ti
# +G4Tg1BkU25RA+t8RCWy/IHug3rrYzqUcdVRq7UgRl40YIkTNnuco6ny7vEBmWFj
# cr7Skvo/QWueO8NAvP2ZKf3QMfidmH1xvxx9h9wVU6rvEQ/PUJi3popYsrQKuogp
# hdPqHZ5j9OoQ+EjACUfgJlHnn8GVbPW3xGplCkXbyEHheQNd/a3X/2zpSwEROOcy
# 1YaeQquflGilAf0y40AFKqW2Q1yTb19cRXBpRzbZVO+RXUB4A6UL1E1Xjtzr/b9q
# z9U4UNV8wy8Yv/07bp3hAFfxB4mn0c+PO+YFv2YsVvYATVI2lwL9QDSEt8F0RW6L
# ekxPfvbkmVSRwP6pf5AUfkqooKa6pfqTCndpGT71HyiltelaMhRUsNVkaKzAJrUo
# ESSj7sTP1ZGiS9JgI+p3AO5fnMht3mLHMg68GszSH4Wy3vUDJpjUTYLtaTWkQtz6
# UqZPN7WXhjCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNQ
# MIICOAIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjM3MDMtMDVFMC1EOTQ3MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQAt
# M12Wjo2xxA5sduzB/3HdzZmiSKCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA6NsFETAiGA8yMDIzMTAxOTAxMjk1
# M1oYDzIwMjMxMDIwMDEyOTUzWjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDo2wUR
# AgEAMAoCAQACAiHWAgH/MAcCAQACAhNBMAoCBQDo3FaRAgEAMDYGCisGAQQBhFkK
# BAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJ
# KoZIhvcNAQELBQADggEBALWo7/SGnmQ3P8QCnt/aysLeS6ZHvSyaJOqTBS9hyhcv
# w+Q4p7IKrWuoga3yABY3Eps+F5QCQOteH+G+UhyTXsZKOsDruTbjyRlGNsCcMBes
# 6mo3gZVD4/t3twYxXxSp77tkc3jY6fB7ZbM+9m24kvnuu0JoY2zUq9OHRU/cFI3/
# /sl2gQ4YdxvTzzN8GpvYFzMT2xoC59q7kxcgSg10G/clUB/EEICtfGCWkg1WXJkY
# zPsViHmRwX7NKgVHgcmiYtjFO10yAsAkS8TsrR9vo3ewQdOwaR1dxCxhrmRqxndc
# zXHn1PkN+drcK26+hU2rtyS72IIAmwIPlRkpndX92dsxggQNMIIECQIBATCBkzB8
# MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk
# bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N
# aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAdTk6QMvwKxprAABAAAB
# 1DANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEE
# MC8GCSqGSIb3DQEJBDEiBCBY5oO4lcfTTpJ+H+ScpEEJPzrNHNqL+TWcCTQaJzYY
# +zCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIMzqh/rYFKXOlzvWS5xCtPi9
# aU+fBUkxIriXp2WTPWI3MIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
# IDIwMTACEzMAAAHU5OkDL8CsaawAAQAAAdQwIgQgCPT1oZ5lerviPAwL6s2wi8wA
# rv049xOALb+kMV5LXhowDQYJKoZIhvcNAQELBQAEggIAZwlbb7be4wWd9yWQ+YVw
# +3MBLQv0EPDVnoMwP7zkDX/PduMaZKG186gkyDL1RPv5WrxPXs6YOgeBzorruqaN
# RMXp3Y+kVCbH3QjsFqewcgSt6bnudtGT2IkzomB1xzhAzxJuCqgDW9FzYTnrnGEj
# Vhjqb4MJRtfdZaDujnmuFZFiE90nlV8My5i4ua3bbTm9D5FH2HdSo/Rn3+cuY5Fm
# ROzH32oPp9t/mHIZG41W+P4EOds8Tue/rh/POjCPrbJgAIIaaXuPVHNgfiTVXfNq
# xVOGl3oHOZFXhjTFiO1dAhTQDRYaGZcHNKiMo69CPImlD0le2ajf7xIZVRIsOpqb
# s+mb9t7rDhkpJ9LLkJwrl8e+9QorliIVe8YyL6N8zGz6rFYPpv1ua81K7Ra/+U1/
# 2kQqdeUR/WmBk/KNaeasvpwCQxNg7E4+Bo6wYXzMc/ytbvVtMFsBnXGoqyoWBox0
# FdV/5JxxKKU+j10GT+U1btPv/ME28gJ44d1xtePNXsiMdzncAIB17jSXNC78jLQr
# WM+7ZTye5Je2HJmCzo0PDzfVLtONxNx9LeazAg2AtDYbdMmHjEoagbU/QX8nf7zV
# 8o+S3hYe5SYCyzfMX3C8bPWfFk+WqEd/qEPhPfSxV69ik+uNhcMEMAYBU860qDSN
# IYZdt1AemYLOELH5dTFBwgE=
# SIG # End signature block
