AzStackHciStandaloneObservability/package/scripts/ExtensionHelper.psm1
##------------------------------------------------------------------ ## <copyright file="ExtensionHelper.psm1" company="Microsoft"> ## Copyright (C) Microsoft. All rights reserved. ## </copyright> ##------------------------------------------------------------------ #region Constants $global:systemDriveLetter = $env:SystemDrive.split(':')[0] $global:extensionRootLocation = Split-Path -Parent $PSScriptRoot $global:packageBinPath = Join-Path -Path $global:extensionRootLocation -ChildPath "bin" $global:ObsArtifactsPaths = @{ FDA = Join-Path -Path $global:packageBinPath -ChildPath "FDA\content\FleetDiagnosticsAgent" GMA = Join-Path -Path $global:packageBinPath -ChildPath "GMA" LogCollectionConfigurations = Join-Path -Path $global:packageBinPath -ChildPath "Configs" ObservabilityAgent = Join-Path -Path $global:packageBinPath -ChildPath "ObsAgent\lib" ObservabilityDeployment = Join-Path -Path $global:packageBinPath -ChildPath "ObsDep" MAWatchdog = Join-Path -Path $global:packageBinPath -ChildPath "MAWatchdog" SBCClient = Join-Path -Path $global:packageBinPath -ChildPath "SBRPClient" UtcExporter = Join-Path -Path $global:packageBinPath -ChildPath "UtcExporter" } $global:DeviceType = $null #endregion Constants #region Imports Import-Module (Join-Path -Path $global:ObsArtifactsPaths.GMA -ChildPath 'GMATenantJsonHelper.psm1') ` -DisableNameChecking ` -Verbose:$false #endregion Imports #region Functions #region Pre-installation validation functions function Assert-NoObsGMAProcessIsRunning { param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name ## Step 1: Check if MAWatchdog is running? If yes, then stop and unregister the service. if (Get-Service $MiscConstants.ObsServiceDetails.WatchdogAgent.Name -ErrorAction SilentlyContinue) { ## Unregister watchdog agent service Write-Log "$functionName : Found already running watchdog service. Trying to stop and unregister the service." ` -LogFile $LogFile Stop-ServiceForObservability ` -ServiceName $MiscConstants.ObsServiceDetails.WatchdogAgent.Name ` -LogFile $LogFile $sleepSeconds = 30 Write-Log ` -Message "$functionName : Letting the process sleep for $sleepSeconds second(s), so that any child processes of the service can shutdown gracefully." ` -LogFile $logFile Start-Sleep -Seconds $sleepSeconds Unregister-ServiceForObservability ` -ServiceName $MiscConstants.ObsServiceDetails.WatchdogAgent.Name ` -LogFile $LogFile } else { Write-Log "$functionName : No registered watchdog service found." ` -LogFile $LogFile } ## Step 2: Now check if MA host processes are still running or not. $runningMAHostProcesses = @() $runningMAHostProcesses += Get-WmiObject win32_process | Where-Object {$_.name -like $MiscConstants.GMAHostProcessNameRegex} Write-Log "$functionName : Count of already running MonAgentHost process = $($runningMAHostProcesses.Count)." ` -LogFile $LogFile foreach ($hostProcess in $runningMAHostProcesses) { ## Step 3: If yes, check for command line value and validate it is not running as AMA and then check if the GMA is running in multi-tenant mode. if (($hostProcess.CommandLine -notmatch $MiscConstants.AMAModeCmdParam) -and ($hostProcess.CommandLine -match $MiscConstants.GMAMultiTenantModeCmdParam)) { ## Step 4: If yes, then stop that MA host process forcefully and the child processes will shutdown by themselves. $procId = $hostProcess.ProcessId Stop-Process -Id $procId -Force Write-Log "$functionName : Stopped the process ($($hostProcess.Name) with id: $procId) running as multi-tenant service with these cmd params: $($hostProcess.CommandLine)." ` -LogFile $LogFile $sleepSeconds = 60 Write-Log ` -Message "$functionName : Letting the process sleep for $sleepSeconds second(s), so that child GMA processes can shutdown gracefully." ` -LogFile $logFile Start-Sleep -Seconds $sleepSeconds break } } return $true } function Assert-SufficientDiskSpaceAvailableForGMACache { param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name $availableDiskspaceOnSysDrive = ((Get-Volume -DriveLetter $global:systemDriveLetter).SizeRemaining) / 1GB Write-Log "$functionName : Available diskspace on $($global:systemDriveLetter) is $availableDiskspaceOnSysDrive GB." ` -LogFile $LogFile if ($availableDiskspaceOnSysDrive -lt $MiscConstants.AvailableDiskSpaceLimitInGB) { return $ErrorConstants.InsufficientDiskSpaceForGMACache.Name } return $true } function Invoke-PreInstallationValidation { param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name $validationFunctionNames = ( $MiscConstants.ValidationFunctionNames.AssertNoObsGMAProcessIsRunning, $MiscConstants.ValidationFunctionNames.AssertSufficientDiskSpaceAvailableForGMACache ) Write-Log ` -Message "$functionName : Performing pre-installation validation." ` -LogFile $logFile foreach($validationFunction in $validationFunctionNames) { $validationResult = (Invoke-Expression "$validationFunction -LogFile `'$logFile`'") if ($validationResult -ne $true) { Write-Log ` -Message "$validationFunction : $($ErrorConstants.$validationResult.Message)" ` -LogFile $LogFile ` -Level $MiscConstants.Level.Error throw $validationResult } Write-Log ` -Message "$validationFunction : $validationResult" ` -LogFile $LogFile ` } Write-Log ` -Message "$functionName : Pre-installation validation completed successfully." ` -LogFile $logFile } #endregion Pre-installation validation functions #region GCS functions function Get-CloudName { Param ( [Parameter(Mandatory)] [System.String] $ExistingCloudName, [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "$functionName : ExistingCloudName = $ExistingCloudName" ` -LogFile $LogFile $publicSettings = Get-HandlerConfigSettings -LogFile $LogFile ## Check if any cloud value is passed through Config settings, if yes than use that if (-not ([System.String]::IsNullOrEmpty($publicSettings.cloudName)) -and ` -not ([System.String]::IsNullOrWhiteSpace($publicSettings.cloudName))) { Write-Log ` -Message "$functionName : CloudName from publicSetting = $($publicSettings.cloudName)" ` -LogFile $LogFile return $publicSettings.cloudName } Write-Log ` -Message "$functionName : Exiting. CloudName: $cloudName" ` -LogFile $LogFile return $ExistingCloudName } function Get-GcsEnvironmentName { Param ( [Parameter(Mandatory)] [System.String] $CloudName, [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "$functionName : CloudName = $CloudName" ` -LogFile $LogFile ## Default environment value. $gcsEnvironmentName = $MiscConstants.GCSEnvironment.Prod ## Check whether cloud name is Canary or PPE or reg key created for CI exists or not, if yes then change the GCSEnvironment to point to PPE instead. if ($CloudName -in $MiscConstants.CloudNames.AzureCanary -or ` $CloudName -in $MiscConstants.CloudNames.AzurePPE -or ` (Test-RegKeyExists -Path $MiscConstants.CIRegKey.Path -Name $MiscConstants.CIRegKey.Name)) { $gcsEnvironmentName = $MiscConstants.GCSEnvironment.Ppe } elseif ($CloudName -in $MiscConstants.CloudNames.AzureUSGovernmentCloud) { $gcsEnvironmentName = $MiscConstants.GCSEnvironment.Fairfax } elseif ($CloudName -in $MiscConstants.CloudNames.AzureChinaCloud) { $gcsEnvironmentName = $MiscConstants.GCSEnvironment.Mooncake } elseif (Get-IsArcAEnvironment) { $gcsEnvironmentName = $MiscConstants.GCSEnvironment.ArcAPpe } Write-Log ` -Message "$functionName : GcsEnvironmentName based on CloudName ($CloudName) = $gcsEnvironmentName" ` -LogFile $LogFile return $gcsEnvironmentName } function Get-GcsRegionName { Param ( [Parameter(Mandatory)] [System.String] $RegistrationRegion, [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name $gcsRegionName = $RegistrationRegion Write-Log ` -Message "$functionName : Existing RegistrationRegion = $gcsRegionName" ` -LogFile $LogFile ## Check if any region value is passed through Config settings, if yes than use that $publicSettings = Get-HandlerConfigSettings -LogFile $LogFile if (-not ([System.String]::IsNullOrEmpty($publicSettings.region)) -and ` -not ([System.String]::IsNullOrWhiteSpace($publicSettings.region))) { Write-Log ` -Message "$functionName : RegionName from publicSetting = $($publicSettings.region)" ` -LogFile $LogFile $gcsRegionName = $publicSettings.region } Write-Log ` -Message "$functionName : Exiting. GCSRegionName: $gcsRegionName" ` -LogFile $LogFile return $gcsRegionName } function Wait-ForGcsConfigSync() { [CmdletBinding()] Param ( [Parameter(Mandatory)] [System.String] $LogFile, [Parameter(Mandatory = $false)] [int] $TimeInSeconds = 60 ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "$functionName : Entering. TimeOut: $TimeInSeconds" ` -LogFile $LogFile Write-Host "Going to wait for GCSConfig sync $TimeInSeconds" Start-Sleep -Seconds $TimeInSeconds $cacheDir = Get-CacheDirectories $gcsConfigFiles = Get-ChildItem -Path $cacheDir.DiagnosticsCache -Filter GcsConfig -Recurse if($gcsConfigFiles.Count -eq 0) { Write-Log ` -Message "$functionName : $($ErrorConstants.GcsConfigFilesNotFound.Message)" ` -LogFile $LogFile ` -Level $MiscConstants.Level.Error } Write-Log ` -Message "$functionName : Exiting. GCSCongfile count: $($gcsConfigFiles.Count)" ` -LogFile $LogFile } #endregion GCS functions #region Handler/Extension functions ## Get sequence number from env variable provided by Agent. function Get-ConfigSequenceNumber { if ($null -eq $env:ConfigSequenceNumber) { 0 } else { $env:ConfigSequenceNumber } } function Get-GmaPackageContentPath { $global:ObsArtifactsPaths.GMA } function Get-HandlerConfigSettings { <# Sample config json file: ------------------------------------------------------------ { "runtimeSettings": [ { "handlerSettings": { "publicSettings": { "region": "eastus", "cloudName": "AzureCanary", "deviceType": "AzureEdge" } } } ] } ----------------------------------------------------------- Or If you don't want to pass any values, it can be empty as follows: { "runtimeSettings": [ { "handlerSettings":{ "publicSettings":{} } } ] } #> param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name $handlerEnvInfo = Get-HandlerEnvInfo -LogFile $LogFile if (-not (Test-Path $handlerEnvInfo.configFolder -PathType Container)) { Write-Log ` -Message "$functionName : $($ErrorConstants.ConfigFolderDoesNotExist.Message)" ` -LogFile $LogFile ` -Level $MiscConstants.Level.Error throw $ErrorConstants.ConfigFolderDoesNotExist.Name } $configFile = Get-ChildItem -Path $handlerEnvInfo.configFolder | Sort-Object CreationTime -Descending | Select-Object -First 1 # Parse config file to read parameters $configJson = Get-Content -Path $configFile.FullName -Raw | ConvertFrom-Json return $configJson.runtimeSettings[0].handlerSettings.publicSettings } function Get-HandlerEnvInfo { Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) <# Sample HandlerEnvironment.json content: [ { "handlerEnvironment": { "configFolder": "C:\\Packages\\Plugins\\Microsoft.AzureStack.Observability.Observability\\0.0.0.4\\RuntimeSettings", "deploymentid": "", "heartbeatFile": "C:\\Packages\\Plugins\\Microsoft.AzureStack.Observability.Observability\\0.0.0.4\\status\\HeartBeat.Json", "hostResolverAddress": "", "instance": "", "logFolder": "C:\\ProgramData\\GuestConfig\\extension_logs\\Microsoft.AzureStack.Observability.Observability", "rolename": "", "statusFolder": "C:\\Packages\\Plugins\\Microsoft.AzureStack.Observability.Observability\\0.0.0.4\\status" }, "name": "Microsoft.RecoveryServices.Test.AzureSiteRecovery", "version": "1" } ] #> $envFile = Join-path -Path $global:extensionRootLocation -ChildPath "HandlerEnvironment.json" if (-not (Test-Path $envFile -PathType Leaf)) { throw $ErrorConstants.HandlerEnvJsonDoesNotExist.Name } # Read handler config $envJson = Get-Content -Path $envFile -Raw | ConvertFrom-Json if ($envJson -is [System.Array]) { $envJson = $envJson[0] } return $envJson.handlerEnvironment } function Get-HandlerHeartBeatFile { Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $handlerEnvInfo = Get-HandlerEnvInfo -LogFile $LogFile return $handlerEnvInfo.heartbeatFile } function Get-HandlerLogFile { Join-Path $(Get-LogFolderPath) -ChildPath $MiscConstants.HandlerLogFileName } function Get-LogFolderPath { Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $handlerEnvInfo = Get-HandlerEnvInfo -LogFile $LogFile if (-not (Test-Path $handlerEnvInfo.logFolder -PathType Container)) { throw $ErrorConstants.LogFolderDoesNotExist.Name } return $handlerEnvInfo.logFolder } function Get-StatusFolderPath { Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $handlerEnvInfo = Get-HandlerEnvInfo -LogFile $LogFile if (-not (Test-Path $handlerEnvInfo.statusFolder -PathType Container)) { throw $ErrorConstants.StatusFolderDoesNotExist.Name } return $handlerEnvInfo.statusFolder } function Get-StatusFilePath { $configSeqNum = Get-ConfigSequenceNumber $statusFolder = Get-StatusFolderPath return "$statusFolder\$configSeqNum.status" } #endregion Handler/Extension functions #region Misc functions function Get-CacheDirectories { Param () $gmaCacheLocation = Join-Path -Path $env:SystemDrive -ChildPath "GMACache" return [ordered] @{ GMACache = $gmaCacheLocation DiagnosticsCache = Join-Path -Path $gmaCacheLocation -ChildPath "DiagnosticsCache" HealthCache = Join-Path -Path $gmaCacheLocation -ChildPath "HealthCache" JsonDropLocation = Join-Path -Path $gmaCacheLocation -ChildPath "JsonDropLocation" MonAgentHostCache = Join-Path -Path $gmaCacheLocation -ChildPath "MonAgentHostCache" TelemetryCache = Join-Path -Path $gmaCacheLocation -ChildPath "TelemetryCache" ObservabilityVolume = Join-Path -Path $env:SystemDrive -ChildPath "Observability" } } function New-CacheDirectories { Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "$functionName : Creating cache directories." ` -LogFile $LogFile $cacheDirectories = Get-CacheDirectories foreach ($directory in $cacheDirectories.Values) { New-Directory ` -Path $directory ` -LogFile $logFile } Write-Log "$functionName : Created cache directories." ` -LogFile $LogFile return $cacheDirectories } function New-Directory { param ( [Parameter(Mandatory = $true)] [System.String] $Path, [Parameter(Mandatory = $false)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "$functionName : Directory to create is '$Path'." ` -LogFile $LogFile if (Test-Path $Path -PathType Container) { Write-Log ` -Message "$functionName : Directory '$Path' exists already." ` -LogFile $LogFile } else { New-Item ` -Path $Path ` -ItemType "Directory" ` -Force ` -Verbose:$False ` | Out-Null Write-Log ` -Message "$functionName : Directory '$Path' created." ` -LogFile $LogFile } } function Get-UtcExporterPackageContentPath { $global:ObsArtifactsPaths.UtcExporter } function Get-FDAPackageContentPath { $global:ObsArtifactsPaths.FDA } function Get-ObservabilityDeploymentPackagePath { $global:ObsArtifactsPaths.ObservabilityDeployment } function Get-WatchdogPackageContentPath { $global:ObsArtifactsPaths.MAWatchdog } function Get-VCRuntimePackageContentPath { "$($global:ObsArtifactsPaths.ObservabilityDeployment)\content\VS17" } function Get-WatchdogStatusFile { param ( [Parameter(Mandatory = $true)] [System.String] $LogFile ) $watchdogStatusDirectory = Join-Path -Path $(Get-LogFolderPath) -ChildPath "WatchdogStatus" New-Directory -Path $watchdogStatusDirectory -LogFile $LogFile return Join-Path -Path $watchdogStatusDirectory -ChildPath $MiscConstants.WatchdogStatusFileName } function Set-Status { Param ( [Parameter(Mandatory)] [System.String] $Name, [Parameter(Mandatory)] [System.String] $Operation, [Parameter(Mandatory)] [System.String] $Message, [Parameter(Mandatory)] [ValidateSet("transitioning", "error", "success", "warning")] [System.String] $Status, [Parameter(Mandatory)] [System.Int16] $Code ) & "$PSScriptRoot\ReportStatus.ps1" ` -Name $Name ` -Operation $Operation ` -Status $Status ` -Code $Code ` -Message $Message } function Get-IsArcAEnvironment { return (Test-RegKeyExists -Path $MiscConstants.ArcARegKey.Path -Name $MiscConstants.ArcARegKey.Name -GetValueIfExists) -eq $true } function Set-StandaloneScenarioRegistry { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] [System.String] $LogFile ) New-RegKey ` -Path $MiscConstants.GMAScenarioRegKey.Path ` -Name $MiscConstants.GMAScenarioRegKey.Name ` -PropertyType $MiscConstants.GMAScenarioRegKey.PropertyType ` -Value $MiscConstants.GMAScenarioRegKey.OneP ` -CreatePathOnly ` -LogFile $LogFile New-RegKey ` -Path $MiscConstants.GMAScenarioRegKey.Path ` -Name $MiscConstants.GMAScenarioRegKey.Name ` -PropertyType $MiscConstants.GMAScenarioRegKey.PropertyType ` -Value $MiscConstants.GMAScenarioRegKey.OneP ` -LogFile $LogFile } #endregion Misc functions #region UTC setup functions Function Initialize-UTCSetup { [CmdletBinding()] Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name try { Write-Log ` -Message "$functionName : Initializing UTC setup." ` -LogFile $logFile #region Stop diagtrack service Stop-ServiceForObservability ` -ServiceName $MiscConstants.ObsServiceDetails.DiagTrack.Name ` -LogFile $logFile #endregion Stop diagtrack service ## Create the UTC exporter destination folder (if not present) and copy the UtcGenevaExporter dll in it. Write-Log ` -Message "$functionName : Create folder for UTCExporterdll and place the respective binary in it." ` -LogFile $logFile $utcExporterDllName = $MiscConstants.UtcxporterDllName $utcExporterSourcePath = Join-Path -Path (Get-UtcExporterPackageContentPath) -ChildPath $utcExporterDllName $utcExporterDestinationDirectory = $MiscConstants.UtcExporterDestinationDirectory New-Directory ` -Path $utcExporterDestinationDirectory ` -LogFile $logFile Copy-Item ` -Path $utcExporterSourcePath ` -Destination $utcExporterDestinationDirectory ` -Force ` | Out-Null $utcExporterDestinationPath = Join-Path -Path $utcExporterDestinationDirectory -ChildPath $utcExporterDllName if (Test-Path $utcExporterDestinationPath) { Write-Log ` -Message "$functionName : Successfully copied '$utcExporterDllName' to '$utcExporterDestinationPath'." ` -LogFile $logFile } else { Write-Log ` -Message "$functionName : Failed to copy '$utcExporterDllName' to '$utcExporterDestinationPath'." ` -LogFile $logFile ` -Level $MiscConstans.Status.Error throw $ErrorConstants.CannotCopyUtcExporterDll.Name } #region Create reg keys New-RegKey ` -Path $MiscConstants.DiagTrackExportersRegKeyPath ` -LogFile $logFile ` -CreatePathOnly New-RegKey ` -Path $MiscConstants.GenevaExporterRegKey.Path ` -LogFile $logFile ` -CreatePathOnly New-RegKey ` -Path $MiscConstants.DiagTrackRegKey.Path ` -Name $MiscConstants.DiagTrackRegKey.Name ` -PropertyType $MiscConstants.DiagTrackRegKey.PropertyType ` -Value $MiscConstants.DiagTrackRegKey.Value ` -LogFile $logFile New-RegKey ` -Path $MiscConstants.GenevaExporterRegKey.Path ` -Name $MiscConstants.GenevaExporterRegKey.Name ` -PropertyType $MiscConstants.GenevaExporterRegKey.PropertyType ` -Value $utcExporterDestinationPath ` -LogFile $logFile New-RegKey ` -Path $MiscConstants.TestHooksRegKey.Path ` -Name $MiscConstants.TestHooksRegKey.Name ` -PropertyType $MiscConstants.TestHooksRegKey.PropertyType ` -Value $MiscConstants.TestHooksRegKey.Value ` -LogFile $logFile New-RegKey ` -Path $MiscConstants.GenevaExporterRegKey.Path ` -Name $MiscConstants.GenevaNamespaceRegKey.Name ` -PropertyType $MiscConstants.GenevaNamespaceRegKey.PropertyType ` -Value $MiscConstants.GenevaNamespaceRegKey.Value ` -LogFile $logFile #endregion Create reg keys #region Start diagtrack service Start-ServiceForObservability ` -ServiceName $MiscConstants.ObsServiceDetails.DiagTrack.Name ` -LogFile $logFile #endregion Start diagtrack service Write-Log ` -Message "$functionName : Successfully initialized UTC setup." ` -LogFile $logFile } finally { if ((Get-Service $MiscConstants.ObsServiceDetails.DiagTrack.Name).Status -eq "Stopped") { Write-Log ` -Message "$functionName : Starting $($MiscConstants.ObsServiceDetails.DiagTrack.Name) service after it was stopped." ` -LogFile $LogFile Start-Service ` -Name $MiscConstants.ObsServiceDetails.DiagTrack.Name ` -ErrorAction SilentlyContinue ` -Verbose:$false ` | Out-Null } } } Function Clear-UTCSetup { [CmdletBinding()] Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name try { Write-Log ` -Message "$functionName : Cleaning up UTC related artifacts." ` -LogFile $logFile #region Stop diagtrack service Stop-ServiceForObservability ` -ServiceName $MiscConstants.ObsServiceDetails.DiagTrack.Name ` -LogFile $LogFile #endregion Stop diagtrack service #region Remove UtcExporter dll Write-Log ` -Message "$functionName : Removing UTCExporterdll file and its folder." ` -LogFile $logFile $utcExporterDestinationPath = Join-Path -Path $MiscConstants.UtcExporterDestinationDirectory -ChildPath $MiscConstants.UtcxporterDllName if (Test-Path -Path $utcExporterDestinationPath) { Remove-Item ` -Path $utcExporterDestinationPath ` -Force ` -Verbose:$false ` | Out-Null Write-Log ` -Message "$functionName : Removed file '$utcExporterDestinationPath'." ` -LogFile $logFile if ((Get-ChildItem -Path $MiscConstants.UtcExporterDestinationDirectory | Measure-Object).Count -eq 0) { Remove-Item ` -Path $MiscConstants.UtcExporterDestinationDirectory ` -Force ` -Verbose:$false ` | Out-Null Write-Log ` -Message "$functionName : Removed directory '$($MiscConstants.UtcExporterDestinationDirectory)'." ` -LogFile $logFile } Write-Log ` -Message "$functionName : Removed UTCExporterdll file '$utcExporterDestinationPath' and its folder path '$($MiscConstants.UtcExporterDestinationDirectory)'." ` -LogFile $logFile } else { Write-Log ` -Message "$functionName : UTCExporter dll does not exists at path '$utcExporterDestinationPath'. Nothing to remove." ` -LogFile $logFile } #endregion Remove UtcExporter dll #region Remove reg keys Remove-RegKey ` -Path $MiscConstants.DiagTrackRegKey.Path ` -Name $MiscConstants.DiagTrackRegKey.Name ` -LogFile $logFile Remove-RegKey ` -Path $MiscConstants.TestHooksRegKey.Path ` -Name $MiscConstants.TestHooksRegKey.Name ` -LogFile $logFile Remove-RegKey ` -Path $MiscConstants.GenevaExporterRegKey.Path ` -Name $MiscConstants.GenevaExporterRegKey.Name ` -LogFile $logFile Remove-RegKey ` -Path $MiscConstants.GenevaExporterRegKey.Path ` -Name $MiscConstants.GenevaNamespaceRegKey.Name ` -LogFile $logFile Remove-RegKey ` -Path $MiscConstants.GenevaExporterRegKey.Path ` -LogFile $logFile ` -RemovePathOnly #endregion Remove reg keys #region Start diagtrack service Start-ServiceForObservability ` -ServiceName $MiscConstants.ObsServiceDetails.DiagTrack.Name ` -LogFile $LogFile #endregion Start diagtrack service Write-Log ` -Message "$functionName : Cleaned up artifacts related to UTC setup." ` -Logfile $logFile } finally { if ((Get-Service $MiscConstants.ObsServiceDetails.DiagTrack.Name).Status -eq "Stopped") { Write-Log ` -Message "$functionName : Starting $($MiscConstants.ObsServiceDetails.DiagTrack.Name) service after it was stopped." ` -LogFile $LogFile Start-Service ` -Name $MiscConstants.ObsServiceDetails.DiagTrack.Name ` -ErrorAction SilentlyContinue ` -Verbose:$false ` | Out-Null } } } #endregion UTC setup functions #region VCRuntime setup function function Install-VCRuntime { [CmdletBinding()] Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name $vcRedistFilePath = Join-Path -Path (Get-VCRuntimePackageContentPath) -ChildPath $MiscConstants.VCRuntimeExeName Write-Log -Message "Installing VC Runtime. $vcRedistFilePath /install /quiet /norestart" -LogFile $LogFile $vcInstall = Start-Process -File $vcRedistFilePath -ArgumentList "/install /quiet /norestart" -Wait -NoNewWindow -PassThru if ($vcInstall.ExitCode -ne 0) { Write-Log ` -Message "$functionName : $($ErrorConstants.VCRedistInstallFailed.Message)" ` -LogFile $LogFile ` -Level $MiscConstants.Level.Error throw $ErrorConstants.VCRedistInstallFailed.Name } Write-Log -Message "VC Runtime $vcRedistFilePath successfully installed." -LogFile $LogFile } #endregion VCRuntime setup function #region Registry functions function New-RegKey { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $Path, [Parameter(Mandatory = $false)] [System.String] $Name, [Parameter(Mandatory = $false)] [System.String] $PropertyType, [Parameter(Mandatory = $false)] [System.String] $Value, [Parameter(Mandatory = $false)] [System.String] $LogFile, [Parameter(Mandatory=$false)] [System.Management.Automation.SwitchParameter] $CreatePathOnly ) $functionName = $MyInvocation.MyCommand.Name if ($CreatePathOnly) { if (-not (Test-Path -Path $Path)) { New-Item ` -Path $Path ` -Force ` -Verbose:$false ` | Out-Null Write-Log ` -Message "$functionName : Created RegKey path ($Path)." ` -LogFile $LogFile } else { Write-Log ` -Message "$functionName : RegKey path ($Path) exists already." ` -LogFile $LogFile } } else { if (-not (Test-RegKeyExists -Path $Path -Name $Name)) { New-ItemProperty ` -Path $Path ` -Name $Name ` -PropertyType $PropertyType ` -Value $Value ` -Force ` | Out-Null Write-Log ` -Message "$functionName : Created registry key with path ($Path), name ($Name) and value ($Value)." ` -LogFile $LogFile } else { Write-Log ` -Message "$functionName : RegKey path ($Path) and name ($Name) exists already." ` -LogFile $LogFile } } } Function Remove-RegKey { [CmdletBinding()] Param ( [Parameter(Mandatory = $True)] [System.String] $Path, [Parameter(Mandatory = $False)] [System.String] $Name, [Parameter(Mandatory = $False)] [System.String] $LogFile, [Parameter(Mandatory=$False)] [System.Management.Automation.SwitchParameter] $RemovePathOnly ) $functionName = $MyInvocation.MyCommand.Name if ($RemovePathOnly) { if (Test-Path -Path $Path) { Remove-Item ` -Path $Path ` -Force ` -Verbose:$false ` | Out-Null Write-Log ` -Message "$functionName : Path ($Path) removed successfully." ` -LogFile $LogFile } else { Write-Log ` -Message "$functionName : Path ($Path) does not exists. Nothing to remove" ` -LogFile $LogFile } } else { if (Test-RegKeyExists -Path $Path -Name $Name) { Remove-ItemProperty ` -Path $Path ` -Name $Name ` -Force ` -Verbose:$false ` | Out-Null Write-Log ` -Message "$functionName : RegKey path ($Path) and name ($Name) removed successfully." ` -LogFile $LogFile } else { Write-Log ` -Message "$functionName : RegKey path ($Path) and name ($Name) does not exists. Nothing to remove" ` -LogFile $LogFile } } } #endregion Registry functions #region Scheduled task functions function Enable-ObsScheduledTask { [CmdletBinding()] param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "$functionName : Enabling ObsScheduledTask ($($MiscConstants.ObsScheduledTaskDetails.TaskName))." ` -LogFile $LogFile $taskObject = Get-ScheduledTask ` -TaskPath $MiscConstants.ObsScheduledTaskDetails.TaskPath ` -TaskName $MiscConstants.ObsScheduledTaskDetails.TaskName ` -ErrorAction $MiscConstants.ErrorActionPreference.SilentlyContinue if ($null -eq $taskObject) { Write-Log ` -Message "$functionName : No scheduled task with name ($($MiscConstants.ObsScheduledTaskDetails.TaskName)) was found to enable." ` -LogFile $LogFile } else { Enable-ScheduledTask ` -InputObject $taskObject ` -ErrorAction $MiscConstants.ErrorActionPreference.Stop ` -Verbose:$false ` | Out-Null Write-Log ` -Message "$functionName : Successfully enabled obs scheduled task with name $($taskObject.TaskName) at path $($taskObject.TaskPath)." ` -LogFile $LogFile } } function Disable-ObsScheduledTask { [CmdletBinding()] Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "$functionName : Disabling ObsScheduledTask ($($MiscConstants.ObsScheduledTaskDetails.TaskName))." ` -LogFile $LogFile $taskObject = Get-ScheduledTask ` -TaskPath $MiscConstants.ObsScheduledTaskDetails.TaskPath ` -TaskName $MiscConstants.ObsScheduledTaskDetails.TaskName ` -ErrorAction $MiscConstants.ErrorActionPreference.SilentlyContinue if ($null -eq $taskObject) { Write-Log ` -Message "$functionName : No scheduled task with name $($MiscConstants.ObsScheduledTaskDetails.TaskName) was found to disable." ` -LogFile $LogFile } else { Disable-ScheduledTask ` -InputObject $taskObject ` -ErrorAction $MiscConstants.ErrorActionPreference.Stop ` -Verbose:$false ` | Out-Null Write-Log ` -Message "$functionName : Successfully disabled obs scheduled task with name $($taskObject.TaskName) at path $($taskObject.TaskPath)." ` -LogFile $LogFile } } function Remove-ObsScheduledTask { param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name $trimmedTaskPath = $MiscConstants.ObsScheduledTaskDetails.TaskPath.TrimEnd('\') $tasks = Get-ScheduledTask -TaskPath "$trimmedTaskPath\*" -ErrorAction $MiscConstants.ErrorActionPreference.SilentlyContinue if ($tasks) { foreach($task in $tasks) { if($task.TaskName -eq $MiscConstants.ObsScheduledTaskDetails.TaskName) { Unregister-ScheduledTask -TaskName $task.TaskName -TaskPath $task.TaskPath -Confirm:$false | Out-Null Write-Log ` -Message "$functionName : Successfully removed scheduled task $($task.TaskName) from path $($task.TaskPath)." ` -LogFile $LogFile } } } else { Write-Log ` -Message "$functionName : Either the path '$trimmedTaskPath' doesn`'t exists or no scheduled tasks found to delete." ` -LogFile $LogFile } } #endregion Scheduled task functions #region Windows service functions function Register-ServiceForObservability { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $ServiceName, [Parameter(Mandatory = $true)] [System.String] $ServiceDisplayName, [Parameter(Mandatory = $true)] [System.String] $ServiceBinaryFilePath, [Parameter(Mandatory = $false)] [System.String] $ServiceStartupType = 'Manual', [Parameter(Mandatory = $false)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name try { Write-Log ` -Message "$functionName : Starting registration of service '$ServiceName'." ` -LogFile $logFile Write-Log ` -Message "$functionName : Configuring service '$ServiceName' from path '$ServiceBinaryFilePath'" ` -LogFile $LogFile if (Get-Service $ServiceName -ErrorAction SilentlyContinue) { Write-Log ` -Message "$functionName : Service '$ServiceName' already registered." ` -LogFile $LogFile } else { New-Service ` -Name $ServiceName ` -BinaryPathName $ServiceBinaryFilePath ` -DisplayName $ServiceDisplayName ` -StartupType $ServiceStartupType ` -ErrorAction Stop ` -Verbose:$false ` | Out-Null } Write-Log ` -Message "$functionName : Registration of service '$ServiceName' with display name '$ServiceDisplayName' completed." ` -LogFile $logFile } catch { Write-Log ` -Message "$functionName : $($ErrorConstants.CannotRegisterService.Message) Service Name: '$ServiceName'. Exception: $_" ` -LogFile $LogFile ` -Level $MiscConstants.Level.Error throw $ErrorConstants.CannotRegisterService.Name } } function Start-ServiceForObservability { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $ServiceName, [Parameter(Mandatory = $false)] [System.String] $LogFile, [Parameter(Mandatory = $false)] [int] $Retries = $MiscConstants.Retries ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "$functionName : Starting service '$ServiceName'." ` -LogFile $logFile # Start MA Watchdog Agent Service $retryCount = $Retries $serviceStatus = (Get-Service $ServiceName).Status if ($serviceStatus -eq "Running") { Write-Log ` -Message "$functionName : Service '$ServiceName' running already." ` -LogFile $LogFile return } while(($serviceStatus -ne "Running") -and ($retryCount -gt 0)) { Start-Service $ServiceName ` -WarningAction SilentlyContinue ` -WarningVariable $startSvcWarn if ($null -ne $startSvcWarn) { Write-Log ` -Message "$functionName : $startSvcWarn" ` -Level $MiscConstants.Level.Warning ` -LogFile $LogFile } Write-Log ` -Message "$functionName : Waiting for service '$ServiceName' to start..." ` -LogFile $LogFile Start-Sleep -Seconds 5 $serviceStatus = (Get-Service $ServiceName).Status $retryCount-- } if ($serviceStatus -ne "Running") { Write-Log ` -Message "$functionName : $($ErrorConstants.CannotStartService.Message) Service Name: '$ServiceName'" ` -LogFile $LogFile ` -Level $MiscConstants.Level.Error throw $ErrorConstants.CannotStartService.Name } Write-Log ` -Message "$functionName : Successfully started service '$ServiceName'." ` -LogFile $LogFile } function Stop-ServiceForObservability { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $ServiceName, [Parameter(Mandatory = $false)] [System.String] $LogFile, [Parameter(Mandatory = $false)] [int] $Retries = $MiscConstants.Retries ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "$functionName : Stopping service '$ServiceName'." ` -LogFile $logFile # Stop MA Watchdog Agent Service $retryCount = $Retries $serviceStatus = (Get-Service $ServiceName).Status if ($serviceStatus -eq "Stopped") { Write-Log ` -Message "$functionName : Service '$ServiceName' stopped already." ` -LogFile $LogFile return } while (($serviceStatus -ne "Stopped") -and ($retryCount -gt 0)) { Stop-Service $ServiceName ` -WarningAction SilentlyContinue ` -WarningVariable $stopSvcWarn if ($null -ne $stopSvcWarn) { Write-Log ` -Message "$functionName : $stopSvcWarn" ` -Level $MiscConstants.Level.Warning ` -LogFile $LogFile } Write-Log ` -Message "$functionName : Waiting for service '$ServiceName' to stop..." ` -LogFile $LogFile Start-Sleep -Seconds 5 $serviceStatus = (Get-Service $ServiceName).Status $retryCount-- } if ($serviceStatus -ne "Stopped") { Write-Log ` -Message "$functionName : $($ErrorConstants.CannotStopService.Message) Service Name: '$ServiceName'" ` -LogFile $LogFile ` -Level $MiscConstants.Level.Error throw $ErrorConstants.CannotStopService.Name } Write-Log ` -Message "$functionName : Successfully stopped service '$ServiceName'." ` -LogFile $LogFile } Function Unregister-ServiceForObservability { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] [System.String] $ServiceName, [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "$functionName : Unregistering service '$ServiceName'." ` -LogFile $LogFile if (Get-Service $ServiceName -ErrorAction SilentlyContinue) { Stop-ServiceForObservability -ServiceName $ServiceName -LogFile $LogFile } Write-Log ` -Message "$functionName : $(sc.exe delete $ServiceName -Verbose)" ` -LogFile $LogFile Write-Log ` -Message "$functionName : Successfully unregistered service '$ServiceName'." ` -LogFile $LogFile } #endregion #region Diag functions Function Confirm-IsDeviceTypeValid { ## Internal function not to export. [CmdletBinding()] Param ( [Parameter(Mandatory = $True)] [System.String] $DeviceType, [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name if ($DeviceType -in $MiscConstants.DeviceTypes.Values) { Write-Log ` -Message "$functionName : Confirmed deviceType '$DeviceType' is valid." ` -LogFile $LogFile } else { throw $ErrorConstants.InvalidDeviceTypeValue.Name } } Function Set-DeviceType { [CmdletBinding()] Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name $deviceTypeFromRegKey = $null $deviceTypeFromPublicSettings = $null ## Check for device type value from registry key $deviceTypeFromRegKey = Test-RegKeyExists ` -Path $MiscConstants.DeviceTypeRegKey.Path ` -Name $MiscConstants.DeviceTypeRegKey.Name ` -LogFile $LogFile ` -GetValueIfExists $publicSettings = Get-HandlerConfigSettings -LogFile $LogFile ## Check if deviceType value exists in Config settings. if ($null -ne $publicSettings -and ` -not ([System.String]::IsNullOrEmpty($publicSettings.deviceType)) -and ` -not ([System.String]::IsNullOrWhiteSpace($publicSettings.deviceType))) { $deviceTypeFromPublicSettings = $publicSettings.deviceType } ## Case 1: Value NOT present either in public settings or in reg key. if ([System.String]::IsNullOrEmpty($deviceTypeFromPublicSettings) -and ` [System.String]::IsNullOrEmpty($deviceTypeFromRegKey)) { throw $ErrorConstants.DeviceTypeValueNotFound.Name } ## Case 2: Value present in public settings and not in reg key. elseif (-not ([System.String]::IsNullOrEmpty($deviceTypeFromPublicSettings)) -and ` [System.String]::IsNullOrEmpty($deviceTypeFromRegKey)) { $global:DeviceType = $deviceTypeFromPublicSettings New-RegKey ` -Path $MiscConstants.DeviceTypeRegKey.Path ` -LogFile $LogFile ` -CreatePathOnly New-RegKey ` -Path $MiscConstants.DeviceTypeRegKey.Path ` -Name $MiscConstants.DeviceTypeRegKey.Name ` -PropertyType $MiscConstants.DeviceTypeRegKey.PropertyType ` -Value $global:DeviceType ` -LogFile $logFile Write-Log ` -Message "$functionName : Using deviceType value from public settings = $global:DeviceType" ` -LogFile $LogFile } ## Case 3: Value present in reg key and not in public settings. elseif (-not ([System.String]::IsNullOrEmpty($deviceTypeFromRegKey)) -and ` [System.String]::IsNullOrEmpty($deviceTypeFromPublicSettings)) { $global:DeviceType = $deviceTypeFromRegKey Write-Log ` -Message "$functionName : Using deviceType value from registry key = $global:DeviceType" ` -LogFile $LogFile } ## Case 4: Value present in both (i.e. public settings and registry key). else { ## Case 4.1: If value is same, use any. if ($deviceTypeFromRegKey -ieq $deviceTypeFromPublicSettings) { $global:DeviceType = $deviceTypeFromRegKey Write-Log ` -Message "$functionName : Device type value from registry key is same as public settings = $global:DeviceType" ` -LogFile $LogFile } else { ## Case 4.2: If both values are different, than there are three more cases. if ( ## Case 4.2.1: If settings has HCI and reg key has EnvValidatorStandAlone, then HCI will be used. ( $deviceTypeFromPublicSettings -ieq $MiscConstants.DeviceTypes.HCI -and ` $deviceTypeFromRegKey -ieq $MiscConstants.DeviceTypes.EnvValidatorStandAlone ) -or ` ## Case 4.2.2: If settigs has AzureEdge and reg key has either HCI or EnvValidatorStandAlone, then AzureEdge will be used. ( $deviceTypeFromPublicSettings -ieq $MiscConstants.DeviceTypes.AzureEdge -and ` ( $deviceTypeFromRegKey -ieq $MiscConstants.DeviceTypes.HCI -or ` $deviceTypeFromRegKey -ieq $MiscConstants.DeviceTypes.EnvValidatorStandAlone ) ) ) { $global:DeviceType = $deviceTypeFromPublicSettings Write-Log ` -Message "$functionName : Device type value from public settings '$($global:DeviceType)' is selected over registry key '$deviceTypeFromRegKey'." ` -LogFile $LogFile } else { ## Case 4.2.3: If not above two, then reg key value will be used over settings. $global:DeviceType = $deviceTypeFromRegKey Write-Log ` -Message "$functionName : Device type value from registry key '$($global:DeviceType)' is selected over public settings '$deviceTypeFromPublicSettings'." ` -LogFile $LogFile } } } Confirm-IsDeviceTypeValid ` -DeviceType $global:DeviceType ` -LogFile $LogFile } Function Move-LogCollectionConfigurations { [CmdletBinding()] Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "$functionName : Copying device type based log collection config files to their destinations." ` -LogFile $LogFile $sourcePaths = @{ DiagLogRoleConfigJson = Join-Path -Path $global:ObsArtifactsPaths.LogCollectionConfigurations -ChildPath "$($global:DeviceType)\$($MiscConstants.LogCollectionConfigs.DiagLogRoleConfigJson)" } $destinationPaths = @{ DiagLogRoleConfigJson = Join-Path -Path $global:ObsArtifactsPaths.ObservabilityAgent -ChildPath "Scripts\$($MiscConstants.LogCollectionConfigs.DiagLogRoleConfigJson)" } foreach ($key in $sourcePaths.Keys) { Copy-Item $sourcePaths[$key] -Destination $destinationPaths[$key] -Force Write-Log ` -Message "$functionName : Successfully copied config file '$($sourcePaths[$key])' to '$($destinationPaths[$key])'." ` -LogFile $LogFile } Write-Log ` -Message "$functionName : Successfully copied device type based log collection config files to their destinations." ` -LogFile $LogFile } #endregion Diag functions #region Telemetry functions Function Confirm-IsTelemetryEnabled { <# Turn off telemetry by default for EnvValidatorStandAlone, we do not know whether user has consented for Telemetry or not and until we have a way to get consent value for EnvValidatorStandAlone, disable telemetry by default.#> if ($global:DeviceType -eq $MiscConstants.DeviceTypes.EnvValidatorStandAlone) { return $false } ## Default return $true } #endregion Telemetry functions #region logman Function Initialize-LogmanTraceSession { Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "[$functionName] Entering." ` -LogFile $LogFile $logmanCreateResult = $null if (Get-Command logman -ErrorAction SilentlyContinue) { $sessionsExistsResult = logman query $MiscConstants.Logman.TraceName if ($sessionsExistsResult[1] -eq "Error:" -and $sessionsExistsResult[2] -eq "Data Collector Set was not found.") { <# Reference: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/logman-create-trace --v: This flag removes the versioning added by default in the etl files. The version is removed because we need only one file to be present. -ow: This flag overwrites the existing file, when the current session is stopped and a new one is started.There is another -a (i.e. append) flag but after adding that, it fails to start the session and so for time being we are using this flag. As we don't expect the customers to be disabling the mandatory extensions oftenly. #> $logmanCreateResult += logman create trace $MiscConstants.Logman.TraceName -f bincirc -o $MiscConstants.Logman.OutputFilePath -max $MiscConstants.Logman.MaxLogFileSizeInMB --v -ow foreach ($guid in $MiscConstants.Logman.ComponentProviderGuids.Values) { $logmanCreateResult += logman update trace $MiscConstants.Logman.TraceName -p "{$guid}" } Write-Log ` -Message "[$functionName] Successfully created logman trace session for Obs components with Output file path of $($MiscConstants.Logman.OutputFilePath) and max log file size of $($MiscConstants.Logman.MaxLogFileSizeInMB) MB. Results = $($logmanCreateResult | Out-String)" ` -LogFile $LogFile } else { Write-Log ` -Message "[$functionName] Logman trace session for Obs components exists already. Result = $($sessionsExistsResult | Out-String)" ` -LogFile $LogFile } } else { Write-Log ` -Message "[$functionName] Logman command is not available in the OS." ` -LogFile $LogFile } Write-Log ` -Message "[$functionName] Exiting." ` -LogFile $LogFile } Function Start-LogmanTraceSession { Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "[$functionName] Entering." ` -LogFile $LogFile if (Get-Command logman -ErrorAction SilentlyContinue) { if (-not $(Get-EtwTraceSession $MiscConstants.Logman.TraceName -ErrorAction SilentlyContinue)) { $logmanStartResult = logman start $MiscConstants.Logman.TraceName Write-Log ` -Message "[$functionName] Successfully started logman trace session for Obs components. Result = $($logmanStartResult | Out-String)" ` -LogFile $LogFile $logmanQueryResult = logman query $MiscConstants.Logman.TraceName Write-Log ` -Message "[$functionName] Logman query result = $($logmanQueryResult | Out-String)" ` -LogFile $LogFile } else { Write-Log ` -Message "[$functionName] Logman trace session for Obs components is running already." ` -LogFile $LogFile } } else { Write-Log ` -Message "[$functionName] Logman command is not available in the OS." ` -LogFile $LogFile } Write-Log ` -Message "[$functionName] Exiting." ` -LogFile $LogFile } Function Stop-LogmanTraceSession { Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "[$functionName] Entering." ` -LogFile $LogFile if (Get-Command logman -ErrorAction SilentlyContinue) { if (Get-EtwTraceSession $MiscConstants.Logman.TraceName -ErrorAction SilentlyContinue) { $logmanStopResult = logman stop $MiscConstants.Logman.TraceName Write-Log ` -Message "[$functionName] Logman trace session for Obs components stopped successfully. Result = $($logmanStopResult | Out-String)" ` -LogFile $LogFile $logmanQueryResult = logman query $MiscConstants.Logman.TraceName Write-Log ` -Message "[$functionName] Logman query result = $($logmanQueryResult | Out-String)" ` -LogFile $LogFile } else { Write-Log ` -Message "[$functionName] Logman trace session for Obs components is stopped already." ` -LogFile $LogFile } } else { Write-Log ` -Message "[$functionName] Logman command is not available in the OS." ` -LogFile $LogFile } Write-Log ` -Message "[$functionName] Exiting." ` -LogFile $LogFile } Function Remove-LogmanTraceSession { Param ( [Parameter(Mandatory = $False)] [System.String] $LogFile ) $functionName = $MyInvocation.MyCommand.Name Write-Log ` -Message "[$functionName] Entering." ` -LogFile $LogFile if (Get-Command logman -ErrorAction SilentlyContinue) { $sessionsExistsResult = logman query $MiscConstants.Logman.TraceName <# Checking the length because if the session exists, it will give an output in array format (as shown below), so we just save it in a variable and count the length of the result. If the session is present it will have this below output. ``` PS C:\sapanc00\FDA\Microsoft.FleetDiagnosticsAgent.Core.2.4.20230613.720> logman query sapancTest Name: sapancTest Status: Stopped Root Path: C:\ Segment: Off Schedules: On Segment Max Size: 100 MB Run as: SYSTEM Name: sapancTest\sapancTest Type: Trace Append: Off Circular: On Overwrite: On Buffer Size: 8 Buffers Lost: 0 Buffers Written: 0 Buffer Flush Timer: 0 Clock Type: Performance File Mode: File The command completed successfully. ``` But if the session is not present, then output should be as below, where the length of array is just 3. ``` PS C:\sapanc00\FDA\Microsoft.FleetDiagnosticsAgent.Core.2.4.20230613.720> logman query sapancTest Error: Data Collector Set was not found. ``` #> if ($sessionsExistsResult.Length -gt 10) { $logmanDeleteResult = logman delete $MiscConstants.Logman.TraceName Write-Log ` -Message "[$functionName] Successfully deleted logman trace session for Obs components. Result = $($logmanDeleteResult | Out-String)" ` -LogFile $LogFile } else { Write-Log ` -Message "[$functionName] Logman trace session for Obs components does not exist. SessionExistsResult = $($sessionsExistsResult | Out-String)" ` -LogFile $LogFile } } else { Write-Log ` -Message "[$functionName] Logman command is not available in the OS." ` -LogFile $LogFile } Write-Log ` -Message "[$functionName] Exiting." ` -LogFile $LogFile } #endregion logman #endregion Functions #region Exports Export-ModuleMember -Function Get-GmaPackageContentPath # Pre-installation validation functions Export-ModuleMember -Function Invoke-PreInstallationValidation ## GCS functions Export-ModuleMember -Function Get-CloudName Export-ModuleMember -Function Get-GcsEnvironmentName Export-ModuleMember -Function Get-GcsRegionName Export-ModuleMember -Function Wait-ForGcsConfigSync ## Handler/Extension functions Export-ModuleMember -Function Get-ConfigSequenceNumber Export-ModuleMember -Function Get-HandlerConfigSettings Export-ModuleMember -Function Get-HandlerEnvInfo Export-ModuleMember -Function Get-HandlerHeartBeatFile Export-ModuleMember -Function Get-HandlerLogFile Export-ModuleMember -Function Get-LogFolderPath Export-ModuleMember -Function Get-StatusFolderPath Export-ModuleMember -Function Get-StatusFilePath ## Misc functions Export-ModuleMember -Function Get-CacheDirectories Export-ModuleMember -Function New-CacheDirectories Export-ModuleMember -Function New-Directory Export-ModuleMember -Function Get-FDAPackageContentPath Export-ModuleMember -Function Get-ObservabilityDeploymentPackagePath Export-ModuleMember -Function Get-UtcExporterPackageContentPath Export-ModuleMember -Function Get-VCRuntimePackageContentPath Export-ModuleMember -Function Get-WatchdogPackageContentPath Export-ModuleMember -Function Get-WatchdogStatusFile Export-ModuleMember -Function Set-Status Export-ModuleMember -Function Set-StandaloneScenarioRegistry Export-ModuleMember -Function Get-IsArcAEnvironment ## UTC setup functions Export-ModuleMember -Function Initialize-UTCSetup Export-ModuleMember -Function Clear-UTCSetup ## Registry functions Export-ModuleMember -Function New-RegKey Export-ModuleMember -Function Remove-RegKey # VCRuntime setup function Export-ModuleMember -Function Install-VCRuntime ## Scheduled task functions Export-ModuleMember -Function Enable-ObsScheduledTask Export-ModuleMember -Function Disable-ObsScheduledTask Export-ModuleMember -Function Remove-ObsScheduledTask ## Windows service functions Export-ModuleMember -Function Register-ServiceForObservability Export-ModuleMember -Function Start-ServiceForObservability Export-ModuleMember -Function Stop-ServiceForObservability Export-ModuleMember -Function Unregister-ServiceForObservability ## Diag functions Export-ModuleMember -Function Set-DeviceType Export-ModuleMember -Function Move-LogCollectionConfigurations ## Telemetry functions Export-ModuleMember -Function Confirm-IsTelemetryEnabled ## logman functions Export-ModuleMember -Function Initialize-LogmanTraceSession Export-ModuleMember -Function Start-LogmanTraceSession Export-ModuleMember -Function Stop-LogmanTraceSession Export-ModuleMember -Function Remove-LogmanTraceSession #endregion Exports # SIG # Begin signature block # MIIn0AYJKoZIhvcNAQcCoIInwTCCJ70CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDO2MjzI/6c2kXS # +w0gxlokMhJ1tOONKQgSDExCv3dV5KCCDYUwggYDMIID66ADAgECAhMzAAADTU6R # phoosHiPAAAAAANNMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjMwMzE2MTg0MzI4WhcNMjQwMzE0MTg0MzI4WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDUKPcKGVa6cboGQU03ONbUKyl4WpH6Q2Xo9cP3RhXTOa6C6THltd2RfnjlUQG+ # Mwoy93iGmGKEMF/jyO2XdiwMP427j90C/PMY/d5vY31sx+udtbif7GCJ7jJ1vLzd # j28zV4r0FGG6yEv+tUNelTIsFmmSb0FUiJtU4r5sfCThvg8dI/F9Hh6xMZoVti+k # bVla+hlG8bf4s00VTw4uAZhjGTFCYFRytKJ3/mteg2qnwvHDOgV7QSdV5dWdd0+x # zcuG0qgd3oCCAjH8ZmjmowkHUe4dUmbcZfXsgWlOfc6DG7JS+DeJak1DvabamYqH # g1AUeZ0+skpkwrKwXTFwBRltAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUId2Img2Sp05U6XI04jli2KohL+8w # VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh # dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzUwMDUxNzAfBgNVHSMEGDAW # gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw # MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx # XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB # ACMET8WuzLrDwexuTUZe9v2xrW8WGUPRQVmyJ1b/BzKYBZ5aU4Qvh5LzZe9jOExD # YUlKb/Y73lqIIfUcEO/6W3b+7t1P9m9M1xPrZv5cfnSCguooPDq4rQe/iCdNDwHT # 6XYW6yetxTJMOo4tUDbSS0YiZr7Mab2wkjgNFa0jRFheS9daTS1oJ/z5bNlGinxq # 2v8azSP/GcH/t8eTrHQfcax3WbPELoGHIbryrSUaOCphsnCNUqUN5FbEMlat5MuY # 94rGMJnq1IEd6S8ngK6C8E9SWpGEO3NDa0NlAViorpGfI0NYIbdynyOB846aWAjN # fgThIcdzdWFvAl/6ktWXLETn8u/lYQyWGmul3yz+w06puIPD9p4KPiWBkCesKDHv # XLrT3BbLZ8dKqSOV8DtzLFAfc9qAsNiG8EoathluJBsbyFbpebadKlErFidAX8KE # usk8htHqiSkNxydamL/tKfx3V/vDAoQE59ysv4r3pE+zdyfMairvkFNNw7cPn1kH # Gcww9dFSY2QwAxhMzmoM0G+M+YvBnBu5wjfxNrMRilRbxM6Cj9hKFh0YTwba6M7z # ntHHpX3d+nabjFm/TnMRROOgIXJzYbzKKaO2g1kWeyG2QtvIR147zlrbQD4X10Ab # rRg9CpwW7xYxywezj+iNAc+QmFzR94dzJkEPUSCJPsTFMIIHejCCBWKgAwIBAgIK # YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm # aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw # OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD # VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG # 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la # UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc # 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D # dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+ # lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk # kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6 # A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd # X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL # 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd # sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3 # T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS # 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI # bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL # BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD # uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv # c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF # BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h # cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA # YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn # 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7 # v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b # pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/ # KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy # CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp # mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi # hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb # BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS # oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL # gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX # cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCGaEwghmdAgEBMIGVMH4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p # Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAANNTpGmGiiweI8AAAAA # A00wDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIM8u # Bz0x2/Fp30mj74ujwSzX2ZrDzQL6pzVsI5aK4/fjMEIGCisGAQQBgjcCAQwxNDAy # oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20wDQYJKoZIhvcNAQEBBQAEggEANMOB3tDhSxRamASgdDp0auJ4P+V77RYDKBHn # 1+0NvMEe+KFTgRGBL7S3su6SdtbzuTKUsoIjA4FDiMnqu6P+/E/MJmk4qs8r4WyG # nNQb6PBR4Rib0eK45N1Z5c3KffnmgAwYXcxR9Yap0PCe8pMgMIHDObOcKi0NPPJa # m7qTUDxeMrVKczUA2QMAMDX9/Bv9H9YRtumewBV3pEAPOGnvHm/ncLeaRdZ/OmPg # LCpCFuRy2rgXP6J3U6vy1yYMixkcCBIBXQDbb3OvnyhCmC6FmvrhRYySaVlg6gJY # payEHBEG+iFuqu3tPdRYu6VUt7V1NY1ZpjRr7yUdwKCMZJx1z6GCFyswghcnBgor # BgEEAYI3AwMBMYIXFzCCFxMGCSqGSIb3DQEHAqCCFwQwghcAAgEDMQ8wDQYJYIZI # AWUDBAIBBQAwggFYBgsqhkiG9w0BCRABBKCCAUcEggFDMIIBPwIBAQYKKwYBBAGE # WQoDATAxMA0GCWCGSAFlAwQCAQUABCC8JZ0Z8Oytd16deciEUcKy98VFDLw2useE # JPMv7l3a3wIGZKx01EHbGBIyMDIzMDcxMzE5MjUxOS4wOVowBIACAfSggdikgdUw # gdIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsT # JE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEmMCQGA1UECxMd # VGhhbGVzIFRTUyBFU046MTc5RS00QkIwLTgyNDYxJTAjBgNVBAMTHE1pY3Jvc29m # dCBUaW1lLVN0YW1wIFNlcnZpY2WgghF7MIIHJzCCBQ+gAwIBAgITMwAAAbWtGt/X # hXBtEwABAAABtTANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UE # CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z # b2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQ # Q0EgMjAxMDAeFw0yMjA5MjAyMDIyMTFaFw0yMzEyMTQyMDIyMTFaMIHSMQswCQYD # VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe # MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3Nv # ZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBU # U1MgRVNOOjE3OUUtNEJCMC04MjQ2MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1T # dGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlwsK # uGVegsKNiYXFwU+CSHnt2a7PfWw2yPwiW+YRlEJsH3ibFIiPfk/yblMp8JGantu+ # 7Di/+3e5wWN/nbJUIMUjEWJnc8JMjoPmHCWsMtJOuR/1Ru4aa1RrxQtIelq098TB # l4k7NsEE87l7qKFmy8iwGNQjkwr0bMu4BJwy7BUXiXHegOSU992rfQ4xNZoxznv4 # 2TLQsc9NmcBq5WslkqVATcc8PSfgBLEpdG1Dp2wqNw4JrJFwJNA1bfzTScYABc5s # mRZBgsP4JiK/8CVrlocheEyQonjm3rFttrojAreSUnixALu9pDrsBI4DUPGG34oI # bieI1oqFl/xk7A+7uM8k4o8ifMVWNTaczbPldDYtn6hBre7r25RED4uecCxP8Dxy # 34YPUElWllPP3LAXp5cMwRjx+EWzjEtILEKXuAcfxrXCTwyYhm5XNzCCZYh4/gF2 # U2y/bYfekKpaoFYwkoZeT6ZxoQbX5Kftgj+tZkFV21UvZIkJ6b34a/44dtrsK6di # TmVnNTM9J6P6Ehlk2sfcUwbHIGL8mYqdKOiyd4RxOCmSvcFNkZEgrk548mHCbDbT # yO9xSzN1EkWxbp8n/LHVnZ9fp5hILGntkMzaD5aXRCQyHSIhsPtR7Q/rKoHyjFqg # tGO9ftnxYvxzNrbKeMCzwmcqwMrX6Hcxe0SeKZ8CAwEAAaOCAUkwggFFMB0GA1Ud # DgQWBBRsUIbZgoZVXVXVWQX0Ok1VO2bHUzAfBgNVHSMEGDAWgBSfpxVdAF5iXYP0 # 5dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29m # dC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIw # MjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUt # U3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB # /wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOC # AgEAkFGOpyjKV2s2sA+wTqDwDdhp0mFrPtiU4rN3OonTWqb85M6WH19c/P517xuj # LCih/HllP5xKWmXnAIRV1/NQDkJBLSdLTb/NQtcT1FWGQ7CMTnrn9tLZxqIFtKVy # lvQNyh31C/qkC8QmNpyzakO0G38uOGgOkJ9Eq4nA+7QwVfobDlggWuEpzdFnRdyX # L32gOqSvrLjFKpv4KEVqaBTiaxCWZDlIhG3YgUza7cnG5Z2SA/feMq/IiV06AzUa # dZw6XgcTrqXmEmE0tMmdl44MMFC3wGU9AVeFCWKdD9WOnYA2zHg+XF2LQVto0VYt # FLd6c6DQFcmB38GvPCKVYSn8r10EoXuRN+gQ7hLcim12esOnW4F4bHCmHWTVWeAG # gPiSItHHRfGKLEUZmotVOdFPR8wiuADT/fHSXBkkdpL12tvgEGELeTznzFulZ16b # /Nv6dtbgSRZreesJBNKpTjdYju/GqnlAkpflL6J0wxk957/UVYnmjjRY61jX90QG # QmBzm9vs/+2bj02Xx/bXXy8vq57jmNXQ2ufOaJm3nAcD2qOaSyXEOj9mqhMt4tdv # MjHhiNPldfj0Q7Kq1HgdRBrKWkzCQNi4ts8HRJBipNaVpWfU7BcRn8BeYzdLoIzw # RLDtatz6aBho3oD/bXHrZagxprM5MsMB/rVfb5Xn1YS7/uEwggdxMIIFWaADAgEC # AhMzAAAAFcXna54Cm0mZAAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQg # Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIyMjVa # Fw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n # dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y # YXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIC # IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7V # gtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeF # RiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3X # D9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoP # z130/o5Tz9bshVZN7928jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+ # tVSP3PoFVZhtaDuaRr3tpK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I5Jas # AUq7vnGpF1tnYN74kpEeHT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2ci/b # fV+AutuqfjbsNkz2K26oElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/TNuv # XsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy16cg # 8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y1BzF # a/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6HXtqP # nhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEw # IwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSf # pxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBB # MD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0Rv # Y3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGC # NxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w # HwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmg # R4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWlj # Um9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEF # BQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29D # ZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1VffwqreEs # H2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHk # wo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinL # btg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCg # vxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsId # w2FzLixre24/LAl4FOmRsqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2 # zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23K # jgm9swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep8beu # yOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+DvktxW/ # tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjm # jJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/2XBj # U02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIC1zCCAkACAQEwggEAoYHYpIHVMIHS # MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk # bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRN # aWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRo # YWxlcyBUU1MgRVNOOjE3OUUtNEJCMC04MjQ2MSUwIwYDVQQDExxNaWNyb3NvZnQg # VGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQCNMJ9r11RZj0PWu3uk # +aQHF3IsVaCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n # dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y # YXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0G # CSqGSIb3DQEBBQUAAgUA6Fo+4jAiGA8yMDIzMDcxMzE3MTQxMFoYDzIwMjMwNzE0 # MTcxNDEwWjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDoWj7iAgEAMAoCAQACAgMN # AgH/MAcCAQACAhHuMAoCBQDoW5BiAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisG # AQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQEFBQAD # gYEAqU5k4Y6YWESiEytdd7O7VE9sx3nOPJRpQctDD6tZw8qwgC1FayGsotCipPcJ # 0MJNC9fVeYUPBXUmpdhyufZcKbBFBFV9Jh//5ERWZtMQjphfBLwQrzX7Lzvcq7WF # nDrxUd3GJGw1xiRAo13jtnIJ9P0Rc6rIirA6L5Ur9hR1vYAxggQNMIIECQIBATCB # kzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAbWtGt/XhXBtEwAB # AAABtTANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJ # EAEEMC8GCSqGSIb3DQEJBDEiBCA4ExdHS55bJeTM081te0xtloYkFZIfa66KL6nY # MYoAHjCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EICfKDTUtaGcWifYc3OVn # Ipp7Ykn0S8JclVzrlAgF8ciDMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAg # UENBIDIwMTACEzMAAAG1rRrf14VwbRMAAQAAAbUwIgQgYiBHDTBVXlJUkrdx1s45 # OGpfG8Wn7hzY8xOJ8jeOMKUwDQYJKoZIhvcNAQELBQAEggIAhz7c1SZyHn0U5ByB # IBCOVIqOq05IloltNyR03Dn/HOIbiLj8VGqDgVWP4yHPBw+tXgEAr9gXAI6/e4sO # xRoKOs3cXqicFq6gEnFnT/E1VZoaxZXRRhQV7pwyQ5uRaIg13htIxInuhpBDK995 # DOuxcJXuK0yiY3iJOItrdDRMceMG2v28SRgBN6r3KYcAnd0eFBL1J2eoLXppZ4xp # 09T81eFBzDECX3zJHf8r5Iz9AqJg1ydsk+REPgAC6+q2TqUvBvvou0dHeoJr24y8 # zPOjUMDxDJ2s3qt9T84MoLg14rxEXTzmzVYPQz0fwH1bS4hhnMu/kzODmkf6xOER # xNPOm4+EmWAukMs4bmYq5hD1DCmTOmYcZdSseqRHwORf2WE7uoX05NZ149W+xGFs # sg4Fe2W7DmDFI27grajwgriTD9+aUUOj4spsvgkpWQeJn/4L6JmAmH9mymM95JEp # XkJZmrXqace6+JcGqNFr2bfw2l+Ra22ebUKFWVPEtOps0UJvwPxjZkv/GuTyWEgC # d5GY73wzdtSPUR9Ira/EgpaVFT4qsxTm3bx35hTxf9+83PFs+fRDAag1WGIJYGO+ # abvOcjXB5CmoPj3RkuC4coOlfW6hppdLkscLEZt392Y6d/7acag8dACC44UfZ+P1 # sVo7z6dyT81lEj1+973mVBpH5pg= # SIG # End signature block |