Obs/bin/SBRPClient/content/Microsoft.AzureStack.Diagnostics.SupportService.psm1
<###################################################
# # # Copyright (c) Microsoft. All rights reserved. # # # ##################################################> if (Test-Path "$PSScriptRoot\bin") { # Loaded from WindowsPowerShell\Modules $clientBinaryDirectory = "$PSScriptRoot\bin" } elseif (Test-Path "$PSScriptRoot\..\lib\net46") { # Loaded from NugetStore $clientBinaryDirectory = "$PSScriptRoot\..\lib\net46" } elseif (Test-Path "$PSScriptRoot\..\..\lib") { # Loaded from NugetStore : used in Remote Support $clientBinaryDirectory = "$PSScriptRoot\..\..\lib" } elseif (Test-Path "$PSScriptRoot\..\lib") { # Loaded from NugetStore : used in Log Collection $clientBinaryDirectory = "$PSScriptRoot\..\lib" } else { throw "Unknown $PSScriptRoot" } Write-Verbose "Client Binary resolved to - [$clientBinaryDirectory], All the binaries will be loaded from here" -Verbose Add-Type -Path "$clientBinaryDirectory\Newtonsoft.Json.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.SupportBridge.LogCollector.Client.Contract.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.SupportBridge.LogCollector.Client.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.SupportBridge.LogCollector.Client.Models.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.Common.Operations.Contract.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.SupportBridge.Management.Client.Contract.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.SupportBridge.Management.Client.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.SupportBridge.Mgmt.Client.Models.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.Common.Infrastructure.ServiceRegistry.ServiceTypeRegistry.dll" -ErrorAction Stop -Verbose:$false | Out-Null function Create-SupportControllerClientWithApplicationGateway { [CmdletBinding()] Param( [Parameter(Mandatory = $false, ValueFromPipeline = $true)] [string] $Endpoint = 'https://ASAppGateway:4443' ) # Create Instance of Support Controller Client Object. [System.TimeSpan] $defaultDelay = [System.TimeSpan]::FromSeconds(5) [System.TimeSpan] $maxRetryTime = [System.TimeSpan]::FromSeconds(30) #Create Instance with gateway resolver. $subrControllerClient = [Microsoft.AzureStack.SupportBridge.LogCollector.Client.LogCollectorClientFactory]::CreateGatewayInstance($Endpoint, $defaultDelay, $maxRetryTime) return $subrControllerClient } # This works while reaching out to SUBR from other VM's where SF is installed and SDN is working # as this requires VIP name resolution. function Create-SupportControllerClientWithServiceResolver { [CmdletBinding()] Param([string[]]$clientConnectionEndpoints = 'ASSRSFClient:19000' ) #Bugfix: Bug 3140655: Accessing ERCS VM Fails With "Unable to load DLL 'FabricClient.dll'" $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.Common.Infrastructure.ServiceDiscovery.ServiceFabric.Contract.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.Common.Infrastructure.ServiceDiscovery.ServiceFabric.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.Common.Infrastructure.ServiceRegistry.ServiceFabricTypeRegistry.dll" -ErrorAction Stop -Verbose:$false | Out-Null $resolver = [Microsoft.AzureStack.Common.Infrastructure.ServiceDiscovery.ServiceFabric.ServiceResolverFactory]::CreateServiceResolver( [Microsoft.AzureStack.Common.Infrastructure.ServiceRegistry.ServiceFabricTypeRegistry.ServiceFabricTypes]::TypeMap, $clientConnectionEndpoints) # Create Instance of Support Controller Client Object. [System.TimeSpan] $defaultDelay = [System.TimeSpan]::FromSeconds(5) [System.TimeSpan] $maxRetryTime = [System.TimeSpan]::FromSeconds(60) #Create Instance with gateway resolver. $subrControllerClient = [Microsoft.AzureStack.SupportBridge.LogCollector.Client.LogCollectorClientFactory]::CreateInstanceUsingServiceResolver($resolver, $defaultDelay, $maxRetryTime) return $subrControllerClient } # This works when service is running as WinSvC locally on the node. function Create-LogCollectorClienttWithLocalServiceResolver { $serviceId = [System.Guid]"754dbc04-8f91-4cb6-a10f-899dac573fa0" $serviceUri = [System.Uri]'http://localhost:7345' $dict = New-Object "System.Collections.Generic.Dictionary``2[System.Guid,System.Uri]" $dict.Add($serviceId, $serviceUri) # Create Instance of Support Controller Client Object. [System.TimeSpan] $defaultDelay = [System.TimeSpan]::FromSeconds(5) [System.TimeSpan] $maxRetryTime = [System.TimeSpan]::FromSeconds(60) Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.Common.Infrastructure.ServiceDiscovery.WinSvc.dll" -ErrorAction Stop -Verbose:$false | Out-Null $resolver = New-Object -TypeName 'Microsoft.AzureStack.Common.Infrastructure.ServiceDiscovery.WinSvc.ServiceResolver' -ArgumentList @($dict) #Create Instance with gateway resolver. $subrControllerLogCollectorClient = [Microsoft.AzureStack.SupportBridge.LogCollector.Client.LogCollectorClientFactory]::CreateInstanceUsingServiceResolver($resolver, $defaultDelay, $maxRetryTime, $null, $true) return $subrControllerLogCollectorClient } # This works while reaching out to SUBR from other VM's where SF is installed and SDN is working # as this requires VIP name resolution. function Create-SupportControllerMgmtClientWithServiceResolver { [CmdletBinding()] Param([string[]]$clientConnectionEndpoints = 'ASSRSFClient:19000' ) $isASZ = Is-ASZ if ($isASZ){ return Create-SupportControllerMgmtClientWithLocalServiceResolver -skipSPNAuth $true; } $ProviderName = [system.environment]::GetEnvironmentVariable("AzureStackProviderName",[System.EnvironmentVariableTarget]::Machine) if (($ProviderName -ne $null) -and ($ProviderName -ieq "Microsoft.HCI")){ return Create-SupportControllerMgmtClientWithLocalServiceResolver -skipSPNAuth $true; } #Bugfix: Bug 3140655: Accessing ERCS VM Fails With "Unable to load DLL 'FabricClient.dll'" $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.Common.Infrastructure.ServiceDiscovery.ServiceFabric.Contract.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.Common.Infrastructure.ServiceDiscovery.ServiceFabric.dll" -ErrorAction Stop -Verbose:$false | Out-Null Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.Common.Infrastructure.ServiceRegistry.ServiceFabricTypeRegistry.dll" -ErrorAction Stop -Verbose:$false | Out-Null $resolver = [Microsoft.AzureStack.Common.Infrastructure.ServiceDiscovery.ServiceFabric.ServiceResolverFactory]::CreateServiceResolver( [Microsoft.AzureStack.Common.Infrastructure.ServiceRegistry.ServiceFabricTypeRegistry.ServiceFabricTypes]::TypeMap, $clientConnectionEndpoints) # Create Instance of Support Controller Client Object. [System.TimeSpan] $defaultDelay = [System.TimeSpan]::FromSeconds(5) [System.TimeSpan] $maxRetryTime = [System.TimeSpan]::FromSeconds(60) #Create Instance with gateway resolver. $subrControllerMgmtClient = [Microsoft.AzureStack.SupportBridge.Management.Client.ManagementClientFactory]::CreateInstanceUsingServiceResolver($resolver, $defaultDelay, $maxRetryTime) return $subrControllerMgmtClient } # This works when service is running as WinSvC locally on the node. function Create-SupportControllerMgmtClientWithLocalServiceResolver { [CmdletBinding()] Param([bool]$skipSPNAuth = $false ) $serviceId = [System.Guid]"ea126685-c89e-4294-959f-bba6bf75b4aa" $serviceUri = [System.Uri]'http://localhost:80/diagnostics' $dict = New-Object "System.Collections.Generic.Dictionary``2[System.Guid,System.Uri]" $dict.Add($serviceId, $serviceUri) # Create Instance of Support Controller Client Object. [System.TimeSpan] $defaultDelay = [System.TimeSpan]::FromSeconds(5) [System.TimeSpan] $maxRetryTime = [System.TimeSpan]::FromSeconds(60) Add-Type -Path "$clientBinaryDirectory\Microsoft.AzureStack.Common.Infrastructure.ServiceDiscovery.WinSvc.dll" -ErrorAction Stop -Verbose:$false | Out-Null $resolver = New-Object -TypeName 'Microsoft.AzureStack.Common.Infrastructure.ServiceDiscovery.WinSvc.ServiceResolver' -ArgumentList @(,$dict) #Create Instance with gateway resolver. $subrControllerMgmtClient = [Microsoft.AzureStack.SupportBridge.Management.Client.ManagementClientFactory]::CreateInstanceUsingServiceResolver($resolver, $defaultDelay, $maxRetryTime, $null, $skipSPNAuth) return $subrControllerMgmtClient } <# .SYNOPSIS Sends Azure Stack Diagnostic Logs to Microsoft. .DESCRIPTION Makes a request to Support Bridge Service to upload diagnostic logs for stamp. .PARAMETER FilterByRole Optional. Filter by Infrastructure Role type. .PARAMETER FilterByResourceProvider Optional. Filter by Value-add resource provider type. .PARAMETER FromDate Optional. Start time to use for logs to collect. .PARAMETER ToDate Optional. End time to use for logs to collect. .EXAMPLE The example below sends last 4 hour logs to Microsoft. PS C:\> Send-AzureStackDiagnosticLog .EXAMPLE The example below sends last 4 hour Support Service and WAS logs to Microsoft. PS C:\> Send-AzureStackDiagnosticLog -FilterByRole SupportBridgeController,WAS .NOTES #> function Send-AzureStackDiagnosticLog { Param( [Parameter(Mandatory=$false)] [string[]] $FilterByRole, [Parameter(Mandatory=$false)] [string[]] $FilterByResourceProvider, [Parameter(Mandatory=$false)] [nullable[DateTime]] $FromDate, [Parameter(Mandatory=$false)] [nullable[DateTime]] $ToDate ) if ($FromDate -eq $null) { $FromDate = (Get-Date).AddHours(-4) Write-Host "FromDate parameter not specified. Setting to default value $FromDate" } if ($ToDate -eq $null) { $ToDate = Get-Date Write-Host "ToDate parameter not specified. Setting to default value $ToDate" } $logCollectionModel = Create-LogCollectionModel -FilterByRole $FilterByRole -FilterByResourceProvider $FilterByResourceProvider -FromDate $FromDate -ToDate $ToDate $subrControllerClient = Create-SupportControllerClientWithServiceResolver $collectionTask = $subrControllerClient.SubmitOnDemandCollectionJob("default", $logCollectionModel, [System.Threading.CancellationToken]::None) $collectionTask.Wait() $operationId = $collectionTask.Result Write-Host "Successfully submitted on-demand. Operation tracking Id: $operationId" [Microsoft.AzureStack.Common.Operations.OperationState]$runningState = [Microsoft.AzureStack.Common.Operations.OperationState]::Running [Microsoft.AzureStack.Common.Operations.OperationState]$currentState = Get-LogCollectionStatus -SubrControllerClient $subrControllerClient -OperationId $operationId Write-Host "Current log collection status: $currentState" while ($currentState -eq $runningState) { Write-Host "Waiting for log collection to complete..." Start-Sleep -s 120 $currentState = Get-LogCollectionStatus -SubrControllerClient $subrControllerClient -OperationId $operationId } Write-Host "Log collection ended with status: $currentState" } function Send-DiagnosticData { [CmdletBinding(DefaultParametersetName='LogCollection')] Param( [Parameter(Mandatory=$false, ParameterSetName='ToShare')] [Parameter(Mandatory=$false, ParameterSetName='LogCollection')] [string[]] $FilterByRole, [Parameter(Mandatory=$false, ParameterSetName='ToShare')] [Parameter(Mandatory=$false, ParameterSetName='LogCollection')] [nullable[DateTime]] $FromDate, [Parameter(Mandatory=$false, ParameterSetName='ToShare')] [Parameter(Mandatory=$false, ParameterSetName='LogCollection')] [nullable[DateTime]] $ToDate, [Parameter(Mandatory=$false, ParameterSetName='ToShare')] [Parameter(Mandatory=$false, ParameterSetName='LogCollection')] [bool] $CollectSddc = $true, [Parameter(Mandatory=$true, ParameterSetName='ToShare')] [switch] $ToSMBShare, [Parameter(Mandatory=$true, ParameterSetName='FromShare')] [switch] $FromSMBShare, [Parameter(Mandatory=$false, ParameterSetName='FromShare')] [string] $LogFolderToParse, [Parameter(Mandatory=$true, ParameterSetName='FromShare')] [Parameter(Mandatory=$true, ParameterSetName='ToShare')] [ValidateNotNullOrEmpty()] [string] $SharePath, [Parameter(Mandatory=$false, ParameterSetName='FromShare')] [Parameter(Mandatory=$false, ParameterSetName='ToShare')] [ValidateNotNullOrEmpty()] [PSCredential] $ShareCredential, [Parameter(Mandatory=$false)] [switch] $BypassObsAgent ) if ($FromDate -eq $null) { $FromDate = (Get-Date).AddHours(-1) Write-Host "FromDate parameter not specified. Setting to default value $FromDate" } if ($ToDate -eq $null) { $ToDate = Get-Date Write-Host "ToDate parameter not specified. Setting to default value $ToDate" } if ($ToDate -gt (Get-Date).addMinutes(5)) { $OldToDate = $ToDate $ToDate = (Get-Date) $warningMessage = "Log Collection To Date cannot be greater than current datetime. Changed Log Collection ToDate from $OldToDate to $ToDate" Write-Warning $warningMessage } if ($FromDate -gt (Get-Date)) { Write-Error "Log Collection From Date cannot be greater than current datetime. Aborting log collection." return } if ($ToDate -le $FromDate) { Write-Error "ToDate cannot be less than or equal to FromDate. Aborting log collection." return } $correlationId = [guid]::NewGuid() Write-Host "The correlation Id is $correlationId. This is used to query for this log collection in the diagnostic pipeline." if (!$ToSMBShare) { try { $pathToDiagnosticJson = "$env:SystemDrive\Gmacache\JsonDropLocation\AEODiagnostics.json" $diagnosticsJson = Get-Content -Raw $pathToDiagnosticJson | ConvertFrom-json $region = $diagnosticsJson.ConstantVariables.MONITORING_AEO_REGION $deviceArmResourceUri = $diagnosticsJson.ConstantVariables.MONITORING_AEO_DEVICE_ARM_RESOURCE_URI Write-Host "The DeviceARM Uri is $deviceArmResourceUri" Write-Host "The region is $region" } catch { Write-Host "Could not get DeviceARM Uri or region. Error: $_" } } # For now, FromSMBShare and ToSMBShare can only be used if we bypass obs agent. # Path through observability agent has not been implemented yet. if ($FromSMBShare -or $ToSMBShare) { if ($FromSMBShare) { $shareParam = "FromSMBShare" } else { $shareParam = "ToSMBShare" } Write-Host "Bypassing the observability agent, as parameter $shareParam was passed in." $BypassObsAgent = $true } if (-not $BypassObsAgent -and (Is-ObservabilityAgentRunning)) { Write-Host "Observability Agent is running." $logCollectionModel = Create-LogCollectionModel -FilterByRole $FilterByRole -FromDate $FromDate -ToDate $ToDate ` -CollectSddc $CollectSddc -CorrelationId $correlationId $subrControllerClient = Create-LogCollectorClienttWithLocalServiceResolver $collectionTask = $subrControllerClient.SubmitOnDemandCollectionJob("default", $logCollectionModel, [System.Threading.CancellationToken]::None) $collectionTask.Wait() $operationId = $collectionTask.Result Write-Host "Successfully submitted on-demand. Log collection Job Id: $operationId. This is used to track the log collection with Get-LogCollectionHistory." [Microsoft.AzureStack.Common.Operations.OperationState]$runningState = [Microsoft.AzureStack.Common.Operations.OperationState]::Running [Microsoft.AzureStack.Common.Operations.OperationState]$currentState = Get-LogCollectionStatus -SubrControllerClient $subrControllerClient -OperationId $operationId Write-Host "Current log collection status: $currentState" while ($currentState -eq $runningState) { Write-Host "Waiting for log collection to complete..." Start-Sleep -s 120 $currentState = Get-LogCollectionStatus -SubrControllerClient $subrControllerClient -OperationId $operationId } Write-Host "Log collection ended with status: $currentState" } else { Write-Host " Bypassing the observability agent and collecting logs directly from LogOrchestrator. There will be no record of this log collection in the log collection history. Only collecting logs from the current host, $env:COMPUTERNAME. " # Call Get-DiagnosticLog with the right parameters (including filtering for local node) # We are running in local mode, which means collect logs only for this node. $filterByNode = @($env:COMPUTERNAME) $getDiagLogParams = @{ TracingContext = $correlationId BypassedObsAgent = $true } # Don't pass in parameters used in collecting logs if we are using FromShare parameter set, because # in that case, we skip log collection. if ($PSCmdlet.ParameterSetName -ne 'FromShare') { $getDiagLogParams.Add("IncludeGetSDDCLogs", $CollectSddc) $getDiagLogParams.Add("FilterByRole", $FilterByRole) $getDiagLogParams.Add("FilterByNode", $filterByNode) $getDiagLogParams.Add("LogCollectionStartTimeUTC", $FromDate) $getDiagLogParams.Add("LogCollectionEndTimeUTC", $ToDate) $getDiagLogParams.Add("LogCollectionJobType", "OnDemand") $getDiagLogParams.Add("LocalMode", $true) } if ($FromSMBShare) { $getDiagLogParams.Add("FromSMBShare", $FromSMBShare) } if ($ToSMBShare) { $getDiagLogParams.Add("ToSMBShare", $ToSMBShare) } if ($SharePath) { $getDiagLogParams.Add("SharePath", $SharePath) } if ($ShareCredential) { $getDiagLogParams.Add("ShareCredential", $ShareCredential) } if ($LogFolderToParse) { $getDiagLogParams.Add("LogFolderToParse", $LogFolderToParse) } Write-Host "Calling Get-DiagnosticLog." Get-DiagnosticLog @getDiagLogParams Write-Host "Get-DiagnosticLog is complete." } } <# .SYNOPSIS Gets the log colllection history. .DESCRIPTION Gets history of logs collected on the stamp. .EXAMPLE PS C:\> Get-LogCollectionHistory .NOTES #> function Get-LogCollectionHistory { Param( [Parameter(Mandatory=$false)] [nullable[DateTime]] $FromDate = (Get-Date).AddDays(-7) ) $logCollectionTable = $null $isASZ = Is-ASZ $subrControllerClient = $null if ($isASZ) { $subrControllerClient = Create-LogCollectorClienttWithLocalServiceResolver } else { $subrControllerClient = Create-SupportControllerClientWithServiceResolver } $fromDateString = $FromDate.ToString("MMddyyyyHHmmss") $getLogHistoryTask = $subrControllerClient.GetLogCollectionHistory([System.Threading.CancellationToken]::None, $fromDateString) $getLogHistoryTask.Wait() $logCollectionRecords = $getLogHistoryTask.Result $logCollectionData = [object[]]::new($logcollectionRecords.Count) $index = 0 foreach ($logcollectionRecord in $logCollectionRecords) { $newRecord = [ordered]@{ TimeCollected = $logcollectionRecord.CollectionTime Status = $logcollectionRecord.State LogCollectionId = $logCollectionRecord.OperationId CollectionFromDate = $logcollectionRecord.FromDate CollectionToDate = $logcollectionRecord.ToDate Type = $logcollectionRecord.JobType LogUploadSizeMb = $logcollectionRecord.UploadDetails.UploadSizeInMb UploadNumberOfFiles = $logcollectionRecord.UploadDetails.UploadNumberOfFiles Directory = $logcollectionRecord.UploadDetails.UploadDirectory Location = $logcollectionRecord.LogLocation Error = $logcollectionRecord.Error.Message -replace "`r`n",'; ' "----------" = "---------------------------------------------------------" } $logCollectionData[$index++] = $newRecord } $logCollectionTable = $logCollectionData | Sort-Object { [DateTime]$_.TimeCollected.DateTime } -Descending if ($logCollectionTable.count -eq 0) { Write-Host "No records in time range." } return $logCollectionTable } <# .SYNOPSIS Enables proactive log collection. .DESCRIPTION Enables proactive log collection. .EXAMPLE The example below enables proactive log collection. PS C:\> Enable-ProactiveLogCollection .NOTES #> function Enable-ProactiveLogCollection { $isASZ = Is-ASZ $subrControllerClient = $null if ($isASZ) { $subrControllerClient = Create-LogCollectorClienttWithLocalServiceResolver $enableProactiveTask = $subrControllerClient.EnableASZProactiveLogCollection([System.Threading.CancellationToken]::None) } else { $subrControllerClient = Create-SupportControllerClientWithServiceResolver $enableProactiveTask = $subrControllerClient.EnableLogCollection([System.Threading.CancellationToken]::None) } $enableProactiveTask.Wait() # check if enabled $enabled = Check-ProactiveEnabled -SubrControllerClient $subrControllerClient -IsASZ $isASZ if ($enabled) { return "enabled" } else { throw "Proactive log collection could not be enabled." } } <# .SYNOPSIS Disables proactive log collection. .DESCRIPTION Disables proactive log collection. .EXAMPLE The example below enables disables log collection. PS C:\> Disable-ProactiveLogCollection .NOTES #> function Disable-ProactiveLogCollection { $isASZ = Is-ASZ $subrControllerClient = $null if ($isASZ) { $subrControllerClient = Create-LogCollectorClienttWithLocalServiceResolver $disableProactiveTask = $subrControllerClient.DisableASZProactiveLogCollection([System.Threading.CancellationToken]::None) } else { $subrControllerClient = Create-SupportControllerClientWithServiceResolver $disableProactiveTask = $subrControllerClient.DisableLogCollection([System.Threading.CancellationToken]::None) } $disableProactiveTask.Wait() # check if enabled $enabled = Check-ProactiveEnabled -SubrControllerClient $subrControllerClient -IsASZ $IsASZ if ($enabled) { throw "Proactive log collection could not be disabled." } else { return "disabled" } } function Check-ProactiveEnabled { Param( [Parameter(Mandatory=$true)] [Microsoft.AzureStack.SupportBridge.LogCollector.Client.Contract.ILogCollectorClient] $SubrControllerClient, [Parameter(Mandatory=$true)] [bool] $IsASZ ) if ($IsASZ) { $logCollectionConfigTask = $SubrControllerClient.GetASZProactiveLogCollectionState([System.Threading.CancellationToken]::None) $logCollectionConfigTask.Wait() $proactiveStatus = $logCollectionConfigTask.Result return ($proactiveStatus -eq "enabled") } else { $logCollectionConfigTask = $SubrControllerClient.GetScheduledLogCollectionConfiguration([System.Threading.CancellationToken]::None) $logCollectionConfigTask.Wait() $logCollectionConfig = $logCollectionConfigTask.Result return $logCollectionConfig.Enabled } } <# .SYNOPSIS Gets the proactive log collection state. .DESCRIPTION Gets the proactive log collection state. .EXAMPLE The example below gets the proactive log collection state.. PS C:\> Get-ProactiveLogCollectionState .NOTES #> function Get-ProactiveLogCollectionState { $isASZ = Is-ASZ $subrControllerClient = $null if ($isASZ) { $subrControllerClient = Create-LogCollectorClienttWithLocalServiceResolver } else { $subrControllerClient = Create-SupportControllerClientWithServiceResolver } $enabled = Check-ProactiveEnabled -SubrControllerClient $subrControllerClient -IsASZ $IsASZ if ($enabled) { return "enabled" } else { return "disabled" } } <# .SYNOPSIS Gets Support Service configuration settings. .DESCRIPTION Support Service configuration settings. .PARAMETER IncludeRegistrationObjectId Optional. Requires internet connectivity. Retrieves registration identity object id. .EXAMPLE The example below gets registration details if stamp was registered or else null. PS C:\> Get-AzureStackSupportConfiguration .NOTES Requires Support VM to have internet connectivity. #> function Get-AzureStackSupportConfiguration { Param( [Parameter(Mandatory=$false)] [Switch] $IncludeRegistrationObjectId ) try { Write-Host "Fetching registration details from Support Service." $includePropertyName = $null if ($IncludeRegistrationObjectId) { $includePropertyName = "objectId" } $subrControllerClient = Create-SupportControllerClientWithServiceResolver $getRegistrationDetailsTask = $subrControllerClient.GetLogCollectionRegistrationDetails([System.Threading.CancellationToken]::None, $includePropertyName) $getRegistrationDetailsTask.Wait() [Microsoft.AzureStack.SupportBridge.LogCollector.Client.Models.LogCollectionRegistrationDetailsClientModelExt]$registrationDetails = $getRegistrationDetailsTask.Result if ($registrationDetails.RegistrationResourceId -eq $null) { Write-Error "Registration Details not found. This can happen either if Azure Stack is not registered or Disconnected." } else { Write-Host "Successfully fetched registration details." return ($registrationDetails | ConvertTo-Json -Depth 2) } } catch { echo $_.Exception|format-list -force Write-Error "Get-AzureStackSupportConfiguration failed with $_" } } <# .SYNOPSIS Enables Cloud connection. .DESCRIPTION Enables Cloud connection. .EXAMPLE The example below enables cloud connection. PS C:\> Enable-AzsCloudConnection .NOTES Requires Support VM to have internet connectivity. #> function Enable-AzsCloudConnection { try { Write-Host "Enabling cloud connection..." $subrControllerMgmtClient = Create-SupportControllerMgmtClientWithServiceResolver $enableMgmtTask = $subrControllerMgmtClient.EnableRemoteManagement([System.Threading.CancellationToken]::None) $enableMgmtTask.Wait() Write-Host "Successfully enabled Cloud connection." } catch { echo $_.Exception|format-list -force Write-Error "Enable-AzsCloudConnection failed with $_" } finally { } } <# .SYNOPSIS Disables Cloud connection. .DESCRIPTION Disables Cloud connection. .EXAMPLE The example below disables Cloud connection. PS C:\> Disable-AzsCloudConnection .NOTES Requires Support VM to have internet connectivity. #> function Disable-AzsCloudConnection { try { Write-Host "Disabling Cloud connection..." $subrControllerMgmtClient = Create-SupportControllerMgmtClientWithServiceResolver $enableMgmtTask = $subrControllerMgmtClient.DisableRemoteManagement([System.Threading.CancellationToken]::None) $enableMgmtTask.Wait() Write-Host "Successfully disabled cloud connection." } catch { echo $_.Exception|format-list -force Write-Error "Disable-AzsCloudConnection failed with $_" } finally { } } <# .SYNOPSIS Adds cloud action. .DESCRIPTION Adds cloud action. .EXAMPLE The example below to add cloud action. PS C:\> Add-AzsCloudAction -SubsystemName $name -Expiration $date -Comments "sample access" .NOTES Requires Support VM to have internet connectivity. #> function Add-AzsCloudAction { Param( [Parameter(Mandatory=$true)] [string] $SubsystemName, [Parameter(Mandatory=$false)] [nullable[DateTime]] $Expiration, [Parameter(Mandatory=$false)] [string] $Comments ) try { if ($Expiration -eq $null) { $Expiration = (Get-Date).AddDays(8) Write-Host "Expiration parameter not specified. Setting to default value $Expiration" } Write-Host "Adding Cloud Action..." Write-Host "Parameters - SubsystemName: $SubsystemName Expiration: $Expiration Comments: $Comments" $subrControllerMgmtClient = Create-SupportControllerMgmtClientWithServiceResolver $mgmtAccessModel = Create-ManagementAccessModel -SubsystemName $SubsystemName -Expiration $Expiration -Comments $Comments $addMgmtAccessTask = $subrControllerMgmtClient.AddorUpdateActionConsent($mgmtAccessModel, [System.Threading.CancellationToken]::None) $addMgmtAccessTask.Wait() [Microsoft.AzureStack.SupportBridge.Management.Client.Models.SubsystemAccessClientModel]$mgmtAccessDetails = $addMgmtAccessTask.Result if ($mgmtAccessDetails -eq $null -or $mgmtAccessDetails.SubsystemName -eq $null) { Write-Error "Cloud action could not be added. This can happen if Cloud connection is not enabled. Try Enabling Cloud connection and then run this again." } else { Write-Host "Successfully added Cloud action." Write-Output $mgmtAccessDetails } } catch { echo $_.Exception|format-list -force Write-Error "Add-AzsCloudAction failed with $_" } finally { } } <# .SYNOPSIS Removes Cloud action. .DESCRIPTION Removes Cloud action. .EXAMPLE The example below removes cloud action. PS C:\> Remove-AzsCloudAction SubsystemName $name .NOTES Requires Support VM to have internet connectivity. #> function Remove-AzsCloudAction { Param( [Parameter(Mandatory=$true)] [string] $SubsystemName ) try { Write-Host "Removing Cloud action..." Write-Host "Parameters - SubsystemName: $SubsystemName" $subrControllerMgmtClient = Create-SupportControllerMgmtClientWithServiceResolver $deleteMgmtAccessTask = $subrControllerMgmtClient.RemoveActionConsent($SubsystemName, [System.Threading.CancellationToken]::None) $deleteMgmtAccessTask.Wait() Write-Host "Successfully removed Cloud action." } catch { echo $_.Exception|format-list -force Write-Error "Remove-AzsCloudAction failed with $_" } finally { } } <# .SYNOPSIS Gets Cloud actions. .DESCRIPTION Gets Cloud actions. .EXAMPLE The example below Gets Cloud actions. PS C:\> Get-AzsCloudAction .NOTES Requires Support VM to have internet connectivity. #> function Get-AzsCloudAction { Param( [Parameter(Mandatory=$false)] [switch] $IncludeExpired ) try { Write-Host "Getting list of Cloud actions..." Write-Host "Parameters - IncludeExpired: $IncludeExpired" $subrControllerMgmtClient = Create-SupportControllerMgmtClientWithServiceResolver $getMgmtAccessTask = $subrControllerMgmtClient.GetActionConsent($IncludeExpired, [System.Threading.CancellationToken]::None) $getMgmtAccessTask.Wait() [Microsoft.AzureStack.SupportBridge.Management.Client.Models.SubsystemAccessClientModel[]]$mgmtAccessDetails = $getMgmtAccessTask.Result if ($mgmtAccessDetails -eq $null -or $mgmtAccessDetails.SubsystemName -eq $null) { Write-Host "Cloud actions list is empty. " } else { Write-Host "Successfully retrieved Cloud actions list." Write-Output $mgmtAccessDetails } } catch { echo $_.Exception|format-list -force Write-Error "Get-AzsCloudAction failed with $_" } finally { } } <# .SYNOPSIS Enables Remote Support. .DESCRIPTION Enables Remote Support allows authorized Microsoft Support users to remotely access the device for diagnostics or repair depending on the access level granted. .PARAMETER AccessLevel Controls the remote operations that can be performed. This can be either Diagnostics or DiagnosticsAndRepair. .PARAMETER ExpireInMinutes Optional. Defaults to 8 hours. .PARAMETER SasCredential Optional. If provided by Microsoft Support, uses it to open remote support connection. .PARAMETER AgreeToRemoteSupportConsent Optional. If set to true then records user consent as provided and proceeds without prompt. .EXAMPLE The example below enables remote support for diagnostics only for 1 day. After expiration no more remote access is allowed. PS C:\> Enable-RemoteSupport -AccessLevel Diagnostics -ExpireInMinutes 1440 .NOTES Requires Support VM to have stable internet connectivity. #> function Enable-RemoteSupport { Param( [Parameter(Mandatory=$true)] [ValidateSet("Diagnostics","DiagnosticsRepair")] [string] $AccessLevel, [Parameter(Mandatory=$false)] [int] $ExpireInMinutes = 480, [Parameter(Mandatory=$false)] [string] $SasCredential, [Parameter(Mandatory=$false)] [switch] $AgreeToRemoteSupportConsent ) try { if ($ExpireInMinutes -lt 60) { Write-Error "ExpireInMinutes cannot be less than 1 hour(60 minutes)." return; } if ($ExpireInMinutes -gt 20160) { Write-Error "ExpireInMinutes cannot exceed beyond 14 days(20160 minutes)." return; } if ($AgreeToRemoteSupportConsent -ne $true) { Write-Host "`r`n`r`nBy approving this request, the Microsoft support organization or the Azure engineering team supporting this feature ('Microsoft Support Engineer') will be given direct access to your device for troubleshooting purposes and/or resolving the technical issue described in the Microsoft support case. `r`n`r`nDuring a remote support session, a Microsoft Support Engineer may need to collect logs. By enabling remote support, you have agreed to a diagnostic logs collection by Microsoft Support Engineer to address a support case You also acknowledge and consent to the upload and retention of those logs in an Azure storage account managed and controlled by Microsoft. These logs may be accessed by Microsoft in the context of a support case and to improve the health of Azure Stack Hub. `r`n`r`nThe data will be used only to troubleshoot failures that are subject to a support ticket, and will not be used for marketing, advertising, or any other commercial purposes without your consent. The data may be retained for up to ninety (90) days and will be handled following our standard privacy practices (https://privacy.microsoft.com/en-US/). Any data previously collected with your consent will not be affected by the revocation of your permission." while(1) { Write-Host "`r`nProceed with enabling remote support?" Write-Host "[Y] Yes [N] No: " -ForegroundColor Yellow -NoNewline $confirmation = Read-Host if ($confirmation -ieq 'Y' -or $confirmation -ieq 'YES') { break; } elseif ($confirmation -ieq 'N' -or $confirmation -ieq 'NO') { return; } } } # Arc Extension registry key check $agentInstalltype = (Get-ItemProperty -Path 'HKLM:\SYSTEM\Software\Microsoft\AzureStack\Observability\RemoteSupport' -ErrorAction SilentlyContinue).InstallType $arcExtensionRootPath = (Get-ItemProperty -Path 'HKLM:\SYSTEM\Software\Microsoft\AzureStack\Observability\RemoteSupport' -ErrorAction SilentlyContinue).ExtensionRootPath $JeaConfigSource = "RegistrationModule" if($agentInstalltype -eq "ArcExtension"){ if($(Get-Service "Observability Remote Support Agent" -ErrorAction SilentlyContinue).Status -eq "Running"){ $scriptPath = Join-Path -Path $arcExtensionRootPath -ChildPath 'Common\ConfigureJeaEndpoints.ps1' $scriptArguments = " -Constants RemoteSupportConstants -JeaConfigSource $JeaConfigSource" Write-Host "JEA configuration script path and arguments are : $scriptPath $scriptArguments" Write-Host "Configuring JEA Endpoints from '$JeaConfigSource'" # Configure JEA, will overwrite if JEA is already installed by startup task if(Test-Path -Path $scriptPath){ Invoke-Expression -Command "& '$scriptPath' $scriptArguments" } } } $targetService = "PowerShell" Write-Host "`r`n`r`Enabling Remote Support for '$AccessLevel' expiring in '$ExpireInMinutes' minutes." $subrControllerMgmtClient = Create-SupportControllerMgmtClientWithServiceResolver if(![string]::IsNullOrEmpty($SasCredential)){ $mgmtAccessModel = Create-RemoteSupportAccessRequestModel -TargetService $targetService -AccessLevel $AccessLevel -ExpireInMinutes $ExpireInMinutes -SasCredential $SasCredential } else { $mgmtAccessModel = Create-RemoteSupportAccessRequestModel -TargetService $targetService -AccessLevel $AccessLevel -ExpireInMinutes $ExpireInMinutes } $addMgmtAccessTask = $subrControllerMgmtClient.AddorUpdateRemoteSupportAccess($mgmtAccessModel, [System.Threading.CancellationToken]::None) $addMgmtAccessTask.Wait() [Microsoft.AzureStack.SupportBridge.Management.Client.Models.RemoteSupportAccessResponseClientModel]$mgmtAccessDetails = $addMgmtAccessTask.Result if ($mgmtAccessDetails -eq $null) { Write-Error "Remote Support could not be Enabled." } else { Write-Host "Remote Support successfully Enabled." Write-Output $mgmtAccessDetails } } catch { echo $_.Exception|format-list -force Write-Error "Enable-RemoteSupport failed with $_" } finally { } } <# .SYNOPSIS Disables Remote Support. .DESCRIPTION Disable Remote Support revokes all access levels previously granted. Any existing support sessions will be terminated, and new sessions can no longer be established. .EXAMPLE The example below disables remote support. PS C:\> Disable-RemoteSupport .NOTES #> function Disable-RemoteSupport { try { Write-Host "Disabling Remote Support." $subrControllerMgmtClient = Create-SupportControllerMgmtClientWithServiceResolver $disableRemoteSupportMgmtTask = $subrControllerMgmtClient.RevokeRemoteSupportAccess([System.Threading.CancellationToken]::None) $disableRemoteSupportMgmtTask.Wait() Write-Host "Remote Support successfully Disabled." } catch { echo $_.Exception|format-list -force Write-Error "Disable-RemoteSupport failed with $_" } finally { } } <# .SYNOPSIS Gets Remote Support Access. .DESCRIPTION Gets remote support access. .PARAMETER IncludeExpired Optional. Defaults to false. Indicates whether to include past expired entries. .EXAMPLE The example below retrieves access level granted for remote support. The result will also include expired consents in the last 30 days. PS C:\> List-RemoteSupportAccess -IncludeExpired $true .NOTES #> function Get-RemoteSupportAccess { Param( [Parameter(Mandatory=$false)] [switch] $IncludeExpired ) try { Write-Host "Retrieving Remote Support access. IncludeExpired is set to '$IncludeExpired'" $subrControllerMgmtClient = Create-SupportControllerMgmtClientWithServiceResolver $listRemoteSupportAccessMgmtTask = $subrControllerMgmtClient.ListRemoteSupportAccess($IncludeExpired, [System.Threading.CancellationToken]::None) $listRemoteSupportAccessMgmtTask.Wait() [Microsoft.AzureStack.SupportBridge.Management.Client.Models.RemoteSupportAccessResponseClientModel[]]$mgmtAccessDetails = $listRemoteSupportAccessMgmtTask.Result if ($mgmtAccessDetails -eq $null -or $mgmtAccessDetails.Length -eq 0) { Write-Host "No remote support access exists. " } else { Write-Output $mgmtAccessDetails } } catch { echo $_.Exception|format-list -force Write-Error "Get-RemoteSupportAccess failed with $_" } finally { } } <# .SYNOPSIS Gets Remote Support Session History Details. .DESCRIPTION Session history represents all remote accesses made by Microsoft Support for either Diagnostics or DiagnosticsRepair based on the Access Level granted. .PARAMETER SessionId Optional. Session Id to get details for a specific session. If omitted then lists all sessions starting from date 'FromDate'. .PARAMETER IncludeSessionTranscript Optional. Defaults to false. Indicates whether to include complete session transcript. Transcript provides details on all operations performed during the session. .PARAMETER FromDate Optional. Defaults to last 7 days. Indicates date from where to start listing sessions from until now. .EXAMPLE The example below retrieves session history with transcript details for the specified session. PS C:\> Get-RemoteSupportSessionHistory -SessionId 467e3234-13f4-42f2-9422-81db248930fa -IncludeSessionTranscript $true .EXAMPLE The example below lists session history starting from last 7 days (default) to now. PS C:\> Get-RemoteSupportSessionHistory .NOTES #> function Get-RemoteSupportSessionHistory { Param( [Parameter(Mandatory=$false)] [string] $SessionId, [Parameter(Mandatory=$false)] [switch] $IncludeSessionTranscript, [Parameter(Mandatory=$false)] [DateTime] $FromDate = (Get-Date).AddDays(-7) ) try { $subrControllerMgmtClient = Create-SupportControllerMgmtClientWithServiceResolver if($SessionId.Length -eq 0) { $currentTime = Get-Date; if ($FromDate -gt $currentTime) { Write-Error "From date cannot be a date in future." return; } [TimeSpan]$daysDifference = $currentTime - $FromDate; $totalDays = [math]::Round($daysDifference.TotalDays) if ($totalDays -gt 45) { Write-Error "From date cannot be past 45 days." return; } Write-Host "Listing Session History for last '$totalDays' days." $listRemoteSupportSessionMgmtTask = $subrControllerMgmtClient.ListRemoteSupportSession($FromDate, $false, [System.Threading.CancellationToken]::None) $listRemoteSupportSessionMgmtTask.Wait() [Microsoft.AzureStack.SupportBridge.Management.Client.Models.RemoteSupportSessionResponseClientModel[]]$listMgmtSessionDetails = $listRemoteSupportSessionMgmtTask.Result if ($listMgmtSessionDetails -eq $null -or $listMgmtSessionDetails.Length -eq 0) { Write-Host "No remote support session exists. " } else { Write-Output $listMgmtSessionDetails } } else { Write-Host "Retrieving Session History for Id '$SessionId'. Include session transcript was set to '$IncludeSessionTranscript'" $getRemoteSupportSessionMgmtTask = $subrControllerMgmtClient.GetRemoteSupportSession($SessionId, $IncludeSessionTranscript, [System.Threading.CancellationToken]::None) $getRemoteSupportSessionMgmtTask.Wait() [Microsoft.AzureStack.SupportBridge.Management.Client.Models.RemoteSupportSessionResponseClientModel]$getMgmtSessionDetails = $getRemoteSupportSessionMgmtTask.Result if ($getMgmtSessionDetails -eq $null) { Write-Host "No remote support session with id '$SessionId' exists." } else { Write-Output $getMgmtSessionDetails } } } catch { echo $_.Exception|format-list -force Write-Error "Get-RemoteSupportSessionHistory failed with $_" } finally { } } #Helper functions for creating remote management access objects. function Create-ManagementAccessModel { [CmdletBinding()] Param( [Parameter(Mandatory=$true)] [string] $SubsystemName, [Parameter(Mandatory=$false)] [DateTime] $Expiration, [Parameter(Mandatory=$false)] [string] $Comments ) $mgmtAccessModel = New-Object -TypeName 'Microsoft.AzureStack.SupportBridge.Management.Client.Models.SubsystemAccessClientModel' $mgmtAccessModel.SubsystemName = $SubsystemName $mgmtAccessModel.ExpiresAt = $Expiration $mgmtAccessModel.Comments = $Comments Write-Output $mgmtAccessModel } #Helper functions for creating client model objects. function Create-LogCollectionModel { [CmdletBinding()] Param( [Parameter(Mandatory=$false)] [string[]] $FilterByRole, [Parameter(Mandatory=$false)] [string[]] $FilterByResourceProvider, [Parameter(Mandatory=$true)] [DateTime] $FromDate, [Parameter(Mandatory=$true)] [DateTime] $ToDate, [Parameter(Mandatory=$false)] [bool] $CollectSddc = $false, [Parameter(Mandatory=$false)] [Guid] $CorrelationId = [System.Guid]::Empty ) $logCollectionModel = New-Object -TypeName 'Microsoft.AzureStack.SupportBridge.LogCollector.Client.Models.LogCollectionJobClientModel' $logCollectionModel.FilterRoles = $FilterByRole $logCollectionModel.FilterResourceProviders = $FilterByResourceProvider $logCollectionModel.FromDate = $FromDate $logCollectionModel.ToDate = $ToDate $logCollectionModel.CollectSddc = $CollectSddc $logCollectionModel.CorrelationId = $CorrelationId Write-Output $logCollectionModel } function Get-LogCollectionStatus { [CmdletBinding()] Param( [Parameter(Mandatory=$true)] [Microsoft.AzureStack.SupportBridge.LogCollector.Client.Contract.ILogCollectorClient] $SubrControllerClient, [Parameter(Mandatory=$true)] [string] $OperationId ) $collectionStatusTask = $SubrControllerClient.GetLogCollectionJobOperationStatus($OperationId, [System.Threading.CancellationToken]::None) $collectionStatusTask.Wait() $collectionStatus = $collectionStatusTask.Result $collectionStatusRecord = $collectionStatus.StatusRecord [Microsoft.AzureStack.Common.Operations.OperationState]$collectionState = $collectionStatusRecord.State Write-Output $collectionState } #Helper functions for creating remote support access request object. function Create-RemoteSupportAccessRequestModel { [CmdletBinding()] Param( [Parameter(Mandatory=$true)] [string] $TargetService, [Parameter(Mandatory=$true)] [string] $AccessLevel, [Parameter(Mandatory=$true)] [int] $ExpireInMinutes, [Parameter(Mandatory=$false)] [string] $SasCredential ) $ExpiresAt=[system.datetimeoffset]::now.AddMinutes($ExpireInMinutes) $mgmtRemoteSupportReqAccessModel = New-Object -TypeName 'Microsoft.AzureStack.SupportBridge.Management.Client.Models.RemoteSupportAccessRequestClientModel' $mgmtRemoteSupportReqAccessModel.TargetService = $TargetService $mgmtRemoteSupportReqAccessModel.AccessLevel = $AccessLevel $mgmtRemoteSupportReqAccessModel.ExpiresAt = $ExpiresAt if(![String]::IsNullOrWhiteSpace($SasCredential)) { Write-Host "Using provided SAS credential to make remote support connection." $mgmtRemoteSupportReqAccessModel.SasCredential = $SasCredential } Write-Output $mgmtRemoteSupportReqAccessModel } function Is-ASZ { try { $value = Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Microsoft\AzureStack" -Name "DeviceType" -ErrorAction SilentlyContinue if ($value -eq "AzureEdge" -or $value -eq "HCI") { return $true } else { return $false } } catch { # could fail because Hub environment or because ASZ deployment failed before the key was created. # If failed in ASZ before key created, then cmdlets (get-logcollectionhistory, enable/disable proactive, #get-proactivelogcollectionstate) will fail anyway, because observability agent isn't up. Write-Host "DeviceType not found. Assuming DeviceType is not AzureEdge" return $false } } function Is-ObservabilityAgentRunning { try { $service = get-service -name "AzureStack Observability Agent" return ($service.Status -eq "Running") } catch { Write-Error "Could not get AzureStack Observability Agent service: $_" return $false } } Set-Alias -Name Send-AzureStackDiagnosticLogs -Value Send-AzureStackDiagnosticLog $isASZ = Is-ASZ if ($isASZ) { Export-ModuleMember -Function Send-DiagnosticData Export-ModuleMember -function Get-LogCollectionHistory Export-ModuleMember -Function Enable-ProactiveLogCollection Export-ModuleMember -Function Disable-ProactiveLogCollection Export-ModuleMember -Function Get-ProactiveLogCollectionState Export-ModuleMember -Function Enable-RemoteSupport Export-ModuleMember -Function Disable-RemoteSupport Export-ModuleMember -Function Get-RemoteSupportAccess Export-ModuleMember -Function Get-RemoteSupportSessionHistory } else { # if returns false, could be because Hub or because ASZ failed early in deployment. # To Be safe, export everything. Export-ModuleMember -Function Send-AzureStackDiagnosticLog Export-ModuleMember -Function Send-DiagnosticData Export-ModuleMember -function Get-LogCollectionHistory Export-ModuleMember -Function Enable-ProactiveLogCollection Export-ModuleMember -Function Disable-ProactiveLogCollection Export-ModuleMember -Function Get-ProactiveLogCollectionState Export-ModuleMember -Function Get-AzureStackSupportConfiguration Export-ModuleMember -Function Enable-AzsCloudConnection Export-ModuleMember -Function Disable-AzsCloudConnection Export-ModuleMember -Function Add-AzsCloudAction Export-ModuleMember -Function Remove-AzsCloudAction Export-ModuleMember -Function Get-AzsCloudAction Export-ModuleMember -Function Enable-RemoteSupport Export-ModuleMember -Function Disable-RemoteSupport Export-ModuleMember -Function Get-RemoteSupportAccess Export-ModuleMember -Function Get-RemoteSupportSessionHistory } # SIG # Begin signature block # MIInwgYJKoZIhvcNAQcCoIInszCCJ68CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCMovjPcVsyRdC1 # Qal4qux/bM524LjyXKtw+cfrIpy77aCCDXYwggX0MIID3KADAgECAhMzAAADTrU8 # 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 # /Xmfwb1tbWrJUnMTDXpQzTGCGaIwghmeAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAANOtTx6wYRv6ysAAAAAA04wDQYJYIZIAWUDBAIB # BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIHW6Zo+tQRAKvNP7h5GNeCRX # fL86D1ecvnskQoHzJHjDMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A # cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB # BQAEggEAwdr6laGXvITiqs3qih2Lbz6EVY1YNR/V2esEwLQlyb2JlYifqdNQXhg9 # wuOUmpcmK6tIATjGIBxcTk0sNAlbRZSnYNGAew8xHpMRpiogbJ5YEWrdUca91LCG # 3PdP4jlH0FHakkX2acASMDnLYfxnNEwUzOAZiiLlUGRNzEnC089LLVCi4jOKZHSb # s60718qwKvnGTg0R9V8tviYwWHEksVWcQSfI3JGLwXW1u+AdH0Ahe6Pd07RhY9AD # YNg5XLseYjh+UZ0lsdCaXcLMrM8Bp1JgfOukuGW+bPOsPOYFz2+KNmZx4ITPfAWp # 6K8/fJvBCLRlge8FAAgAiFvEZKucXKGCFywwghcoBgorBgEEAYI3AwMBMYIXGDCC # FxQGCSqGSIb3DQEHAqCCFwUwghcBAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFZBgsq # hkiG9w0BCRABBKCCAUgEggFEMIIBQAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl # AwQCAQUABCAXHiTeqQSKPtUOokshICgy8RVkdMcfOv6H6C/nadouTQIGZQrjflcR # GBMyMDIzMDkyMjA4MzIxMy44MjJaMASAAgH0oIHYpIHVMIHSMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl # bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNO # OjJBRDQtNEI5Mi1GQTAxMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT # ZXJ2aWNloIIRezCCBycwggUPoAMCAQICEzMAAAGxypBD7gvwA6sAAQAAAbEwDQYJ # KoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcNMjIw # OTIwMjAyMTU5WhcNMjMxMjE0MjAyMTU5WjCB0jELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3Bl # cmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjoyQUQ0LTRC # OTItRkEwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCC # AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIaiqz7V7BvH7IOMPEeDM2Uw # CpM8LxAUPeJ7Uvu9q0RiDBdBgshC/SDre3/YJBqGpn27a7XWOMviiBUfMNff51Nx # KFoSX62Gpq36YLRZk2hN1wigrCO656z5pVTjJp3Q8jdYAJX3ruJea3ccfTgxAgT3 # Uv/sP4w0+yZAYa2JZalV3MBgIFi3VwKFA4ClQcr+V4SpGzqz8faqabmYypuJ35Zn # 8G/201pAN2jDEOu7QaDC0rGyDdwSTVmXcHM46EFV6N2F69nwfj2DZh74gnA1DB7N # FcZn+4v1kqQWn7AzBJ+lmOxvKrURlV/u19Mw1YP+zVQyzKn5/4r/vuYSRj/thZr+ # FmZAUtTAacLzouBENuaSBuOY1k330eMp8nndSNUsUjj/nn7gcdFqzdQNudJb+Xxm # Rwi9LwjA0/8PlOsKTZ8Xw6EEWPVLfNojSuWpZMTaMzz/wzSPp5J02kpYmkdl50lw # yGRLO5X7iWINKmoXySdQmRdiGMTkvRStXKxIoEm/EJxCaI+k4S3+BWKWC07EV5T3 # UG7wbFb4LfvgbbaKM58HytAyjDnO9fEi0vrp8JFTtGhdtwhEEkraMtGVt+CvnG0Z # lH4mvpPRPuJbqE509e6CqmHwzTuUZPFMFWvJn4fPv0d32Ws9jv2YYmE/0WR1fULs # +TxxpWgn1z0PAOsxSZRPAgMBAAGjggFJMIIBRTAdBgNVHQ4EFgQU9Jtnke8NrYSK # 9fFnoVE0pr0OOZMwHwYDVR0jBBgwFoAUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXwYD # VR0fBFgwVjBUoFKgUIZOaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j # cmwvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3JsMGwG # CCsGAQUFBwEBBGAwXjBcBggrBgEFBQcwAoZQaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIw # MjAxMCgxKS5jcnQwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcD # CDAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQELBQADggIBANjnN5JqpeVShIrQ # IaAQnNVOv1cDEmCkD6oQufX9NGOX28Jw/gdkGtMJyagA0lVbumwQla5LPhBm5LjI # UW/5aYhzSlZ7lxeDykw57wp2AqoMAJm7bXcXtJt/HyaRlN35hAhBV+DmGnBIRcE5 # C2bSFFY3asD50KUSCPmKl/0NFadPeoNqbj5ZUna8VAfMSDsdxeyxjs8r/9Vpqy8l # gIVBqRrXtFt6n1+GFpJ+2AjPspfPO7Y+Y/ozv5dTEYum5eDLDdD1thQmHkW8s0BB # DbIOT3d+dWdPETkf50fM/nALkMEdvYo2gyiJrOSG0a9Z2S/6mbJBUrgrkgPp2HjL # kycR4Nhwl67ehAhWxJGKD2gRk88T2KKXLiRHAoYTZVpHbgkYLspBLJs9C77ZkuxX # uvIOGaId7EJCBOVRMJygtx8FXpoSu3jWEdau0WBMXxhVAzEHTu7UKW3Dw+KGgW7R # Rlhrt589SK8lrPSvPM6PPnqEFf6PUsTVO0bOkzKnC3TOgui4JhlWliigtEtg1SlP # MxcdMuc9uYdWSe1/2YWmr9ZrV1RuvpSSKvJLSYDlOf6aJrpnX7YKLMRoyKdzTkcv # Xw1JZfikJeGJjfRs2cT2JIbiNEGK4i5srQbVCvgCvdYVEVZXVW1Iz/LJLK9XbIkM # MjmECJEsa07oadKcO4ed9vY6YYBGMIIHcTCCBVmgAwIBAgITMwAAABXF52ueAptJ # mQAAAAAAFTANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT # Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNh # dGUgQXV0aG9yaXR5IDIwMTAwHhcNMjEwOTMwMTgyMjI1WhcNMzAwOTMwMTgzMjI1 # WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCAiIwDQYJKoZIhvcNAQEB # BQADggIPADCCAgoCggIBAOThpkzntHIhC3miy9ckeb0O1YLT/e6cBwfSqWxOdcjK # NVf2AX9sSuDivbk+F2Az/1xPx2b3lVNxWuJ+Slr+uDZnhUYjDLWNE893MsAQGOhg # fWpSg0S3po5GawcU88V29YZQ3MFEyHFcUTE3oAo4bo3t1w/YJlN8OWECesSq/XJp # rx2rrPY2vjUmZNqYO7oaezOtgFt+jBAcnVL+tuhiJdxqD89d9P6OU8/W7IVWTe/d # vI2k45GPsjksUZzpcGkNyjYtcI4xyDUoveO0hyTD4MmPfrVUj9z6BVWYbWg7mka9 # 7aSueik3rMvrg0XnRm7KMtXAhjBcTyziYrLNueKNiOSWrAFKu75xqRdbZ2De+JKR # Hh09/SDPc31BmkZ1zcRfNN0Sidb9pSB9fvzZnkXftnIv231fgLrbqn427DZM9itu # qBJR6L8FA6PRc6ZNN3SUHDSCD/AQ8rdHGO2n6Jl8P0zbr17C89XYcz1DTsEzOUyO # ArxCaC4Q6oRRRuLRvWoYWmEBc8pnol7XKHYC4jMYctenIPDC+hIK12NvDMk2ZItb # oKaDIV1fMHSRlJTYuVD5C4lh8zYGNRiER9vcG9H9stQcxWv2XFJRXRLbJbqvUAV6 # bMURHXLvjflSxIUXk8A8FdsaN8cIFRg/eKtFtvUeh17aj54WcmnGrnu3tz5q4i6t # AgMBAAGjggHdMIIB2TASBgkrBgEEAYI3FQEEBQIDAQABMCMGCSsGAQQBgjcVAgQW # BBQqp1L+ZMSavoKRPEY1Kc8Q/y8E7jAdBgNVHQ4EFgQUn6cVXQBeYl2D9OXSZacb # UzUZ6XIwXAYDVR0gBFUwUzBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYz # aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnku # aHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIA # QwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2 # VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwu # bWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEw # LTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYt # MjMuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCdVX38Kq3hLB9nATEkW+Geckv8qW/q # XBS2Pk5HZHixBpOXPTEztTnXwnE2P9pkbHzQdTltuw8x5MKP+2zRoZQYIu7pZmc6 # U03dmLq2HnjYNi6cqYJWAAOwBb6J6Gngugnue99qb74py27YP0h1AdkY3m2CDPVt # I1TkeFN1JFe53Z/zjj3G82jfZfakVqr3lbYoVSfQJL1AoL8ZthISEV09J+BAljis # 9/kpicO8F7BUhUKz/AyeixmJ5/ALaoHCgRlCGVJ1ijbCHcNhcy4sa3tuPywJeBTp # kbKpW99Jo3QMvOyRgNI95ko+ZjtPu4b6MhrZlvSP9pEB9s7GdP32THJvEKt1MMU0 # sHrYUP4KWN1APMdUbZ1jdEgssU5HLcEUBHG/ZPkkvnNtyo4JvbMBV0lUZNlz138e # W0QBjloZkWsNn6Qo3GcZKCS6OEuabvshVGtqRRFHqfG3rsjoiV5PndLQTHa1V1QJ # sWkBRH58oWFsc/4Ku+xBZj1p/cvBQUl+fpO+y/g75LcVv7TOPqUxUYS8vwLBgqJ7 # Fx0ViY1w/ue10CgaiQuPNtq6TPmb/wrpNPgkNWcr4A245oyZ1uEi6vAnQj0llOZ0 # dFtq0Z4+7X6gMTN9vMvpe784cETRkPHIqzqKOghif9lwY1NNje6CbaUFEMFxBmoQ # tB1VM1izoXBm8qGCAtcwggJAAgEBMIIBAKGB2KSB1TCB0jELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxh # bmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjoy # QUQ0LTRCOTItRkEwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy # dmljZaIjCgEBMAcGBSsOAwIaAxUA7WSxvqQDbA7vyy69Tn0wP5BGxyuggYMwgYCk # fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF # AOi2szAwIhgPMjAyMzA5MjEyMDE4NTZaGA8yMDIzMDkyMjIwMTg1NlowdzA9Bgor # BgEEAYRZCgQBMS8wLTAKAgUA6LazMAIBADAKAgEAAgIg4gIB/zAHAgEAAgIR9jAK # AgUA6LgEsAIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB # AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAAduu1j9J/tgbUkz # kLxj7ODM9OtgbQ8piql7to7euorbjou4fksrv4qe2tWOzAFtw5UjvPA0P5VP5bmA # 4PxX8t6LWdkYDSo8LHW9FCpumN/iLSitxmQUOMjePnXRXpQPMG5MsuPR+Nl0kxJt # x7ugel7Cdr8X7yPd6UwVMmf+oJhuMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp # bWUtU3RhbXAgUENBIDIwMTACEzMAAAGxypBD7gvwA6sAAQAAAbEwDQYJYIZIAWUD # BAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0B # CQQxIgQg5gCAGIwshh9Crw0I34j/9rn44i7FKEi/+0KYeXcYFZUwgfoGCyqGSIb3 # DQEJEAIvMYHqMIHnMIHkMIG9BCCD7Q2LFFvfqeDoy9gpu35t6dYerrDO0cMTlOIo # mzTPbDCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u # MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp # b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB # scqQQ+4L8AOrAAEAAAGxMCIEIORiYXHs9mbD/bRiX2DjxNTbd/qyiRl/l5vc9ou3 # Xm7eMA0GCSqGSIb3DQEBCwUABIICABkhEtPJ9Ny65ROEi7zh/wEoBKLFioTfBtaW # TfhW0BePLo4dUM1pZs7dkwWwKdt4ldWh45yGsEO+ytvIr4Bh+RUpEjU5bfQEMQoX # 2//+06q1nXNT8biKtg4BztitmmaoJxzswbsBGjTq23HoOxfG524TSpgRsd3OKyx+ # fpxzCq6zLU0TDnbL4dAsd0Qv7dagav1GG/T1WoHNJXLWmwDRMPa119mo2aR7aB2O # cXYiQV8GTwWCApDEmwJkERH+MdIzx0cNZ1DlXPiH9SNi2pls2vZetCOFOEyRaP/i # Ss1R88uDqhyeJeAa2d1HxRJ8gtAah7lWTNWBG5ymbDMD2SkQAoqDdUWB3pK3IYHl # 4trcRcS6x+M7qdBA5pbXYVeQL6ua7MfLPNIU3GQSCteG1xkQxChzOOFgCYYxoUEj # IDe+xUurhJy9sPqjcx2m6IAexL2VXrT0fo3RQEg6CI0oqxLD5aQ5wCHRBJZsa4xE # kXmTHSK6s/T47Aa674STReyvyYcU9w7GDvyVprNyHYOuFSmMEK23fUT6DWa4ce4r # GjQM6kghas59SRlnzkSzzcAqgr2fJrHezyaXEa8vECqctPRC8nT3Eb3YbrlVOrM4 # mTrMMQCQSCNCOu/q3bD5mXYAhxFjdNBqwRqzxl/OEr1aSLpYsll4PpytIkd+OBsC # ym5J/lAj # SIG # End signature block |