Obs/bin/GMA/Monitoring/Agent/Extensions/MetricsExtension/mdmDataCollection.ps1
<# .SYNOPSIS Powershell script to collect data about Geneva Metrics (AKA MDM, AKA Geneva Hot Path) data publication. .DESCRIPTION This script performs several operations for troubleshooting issues related to MetricsExtension such as: - Collection of metric traffic. - Collectio of information about the environment such as OS, processes running. - Collection of certificates. - Collection of logs. - Test connection to Frontends where we emit the metrics. .EXAMPLE ./mdmDataCollection.ps1 -SkipAdminCheck -MetricCollectionDurationSec 60 -Table2CsvPath "C:/table2csv.exe" .EXAMPLE ./mdmDataCollection.ps1 -SkipCollectionTsfLogs -SkipCollectionCertificates .EXAMPLE ./mdmDataCollection.ps1 -LogicalDisks "C: D:" .EXAMPLE ./mdmDataCollection.ps1 -MetricCollectionSizeMaxMB 100 -MetricCollectionDurationSec 60 -TimeOutSecondsSearchFiles -1 .EXAMPLE ./mdmDataCollection.ps1 -OutputDirectory "C:\dev" #> param ( # If this switch is specified, the output of all commands will be showed in the output. [Parameter(Mandatory=$false)] [switch]$DebugMdmDataCollection = $false, # The arguments passed for the execution of table2csv.exe. # Default value: "-tail 150000" [Parameter(Mandatory=$false)] [string]$Table2CsvParameters = "-tail 150000", # It specifies the time we will be spent collecting the traffic of metrics in seconds. # Default value: 190 [Parameter(Mandatory=$false)] [int]$MetricCollectionDurationSec = 190, # It specifies the maximum size in MB that will be stored from the collection of the metrics. # Default value: 500 [Parameter(Mandatory=$false)] [int]$MetricCollectionSizeMaxMB = 500, # If this switch is specified, the check of admin permissions will be skipped [Parameter(Mandatory=$false)] [switch]$SkipAdminCheck = $false, # It specifies the path for cpprestutil.exe [Parameter(Mandatory=$false)] [string]$CppRestUtilPathParam = $null, # It specifies the path for table2csv.exe [Parameter(Mandatory=$false)] [string]$Table2CsvPathParam = $null, # The script needs to search files in the environment, this operation can be really long if your disk is not indexed. # This parameter allows you to set a TimeOut in the search. If you don't want to have TimeOut, pass the value -1. # Default value: 3600 [Parameter(Mandatory=$false)] [int]$TimeOutSecondsSearchFiles = 3600, # It specifies the disks where we are going to search the files in the script. # Example for only searching in C: and D:, "C: D:". Use a whitespace as separator. [Parameter(Mandatory=$false)] [string]$LogicalDisksParam = $null, # If this switch is specified, the collection of tsf logs will be skipped. [Parameter(Mandatory=$false)] [switch]$SkipCollectionTsfLogs = $false, # If this switch is specified, the collection of certificates will be skipped. [Parameter(Mandatory=$false)] [switch]$SkipCollectionCertificates = $false, # It specifies in which directory the output is going to be stored. [Parameter(Mandatory=$false)] [string]$OutputDirectory = "..", # This is only used for tests purposes, please don't use it [Parameter(Mandatory=$false)] [switch]$ImportFunctions = $false ) $ScriptVersion = "Windows-1.10" $MeFrontendUrls = @( "global.prod.microsoftmetrics.com" "global.metrics.nsatc.net" "azglobal.metrics.nsatc.net" ) $Ports = @( "80" "443" ) $MeStamps = @( "https://global.prod.microsoftmetrics.com" "https://azglobal-red.prod.microsoftmetrics.com" "https://azglobal-black.prod.microsoftmetrics.com" "https://global.metrics.nsatc.net" "https://azglobal-red.azglobal.metrics.nsatc.net" "https://azglobal-black.azglobal.metrics.nsatc.net" "https://global.metrics.azure.microsoft.scloud" "https://global.metrics.azure.eaglex.ic.gov" "https://13.90.249.229" "https://40.77.24.27" "https://[2a01:111:f100:2000::a83e:33d6]" "https://[2603:1030:7::155]" ) $StampPaths = @( "/public/lb-probe" "/public/monitoringAccount/MetricTeamInternalMetrics/acls" ) $ExcludedEnvironmentVariables = @( "_NT_SYMBOL_PATH" ) function Main { Set-UTF8-Encoding Confirm-Admin-Permissions $mdmDataCollectionOutput = Get-MdmDataCollectionOutput $compressedDataOutput = Get-CompressedDataOutput $mdmDataCollectionOutput Show-Starting-Message Get-Logical-Disks $logicalDisks = Get-Content -Path .\LogicalDisks.txt $metricsExtensionPath = Get-File-Version "MetricsExtension.Native.exe" ".\MetricsExtensionProcesses.txt" "MetricsExtensionVersions.txt" $cppRestUtil = Search-CppRestUtil $metricsExtensionPath Test-ME-Stamps $mdmDataCollectionOutput $cppRestUtil Get-Etw-Session-And-IfxMetrics-At-Start Get-OS-And-Processes-Information Get-Local-Time-Information Get-Difference-Time-Server-And-Agent $cppRestUtil Get-Certificates Get-HTTP-Proxy-Configuration Get-Environment-Variables Get-Open-Sockets-And-Owning-Processes Test-Frontend-Urls Get-Application-Event-Logs Get-Raw-And-Aggregated-Metrics $commandLineArguments = Get-Command-Line-Arguments Get-Cached-Config $commandLineArguments Copy-Autopilot-Logs Get-Autopilot-Ini $monAgentHostPath = Get-File-Version "MonAgentHost.exe" ".\MonAgentHostProcesses.txt" "MonAgentHostVersions.txt" Get-Tsf-Logs $logicalDisks $mdmDataCollectionOutput $monAgentHostPath Get-Etw-Session-And-IfxMetrics-At-End Compress-Output $compressedDataOutput $mdmDataCollectionOutput Show-Ending-Message } function Set-UTF8-Encoding { [void](chcp 65001) } function Confirm-Admin-Permissions { if ($SkipAdminCheck) { Write-Warning "Administrative permissions check skipped due to SkipAdminCheck being set." } elseif(-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole] "Administrator")) { $errorMessage = "ERROR: This script has to be run with administrative permissions.`n" $errorMessage += "If you believe you have received this message due to an error, you can`n" $errorMessage += "skip this check by passing the command line parameter SkipAdminCheck." Write-Error $errorMessage break } } function Get-MdmDataCollectionOutput { $folderSuffix = [DateTime]::UtcNow.ToString('yyyy_MM_dd_hh_mm_ss') $randomNumber = Get-Random $mdmDataCollectionOutput = "MdmDataCollectionOutput" + $folderSuffix + "_random_" + $randomNumber [void](Remove-Directory-If-It-Exists $mdmDataCollectionOutput) [void](mkdir $mdmDataCollectionOutput) [void](Set-Location $mdmDataCollectionOutput) return $mdmDataCollectionOutput } function Get-CompressedDataOutput([String]$mdmDataCollectionOutput) { $compressedDataOutput = $mdmDataCollectionOutput + ".zip" return $compressedDataOutput } function Remove-Directory-If-It-Exists([String]$directory) { if (Test-Path -Path $directory) { Write-Output "File $directory already exists deleting it before proceeding..." try { Invoke-Command "Remove-Item -LiteralPath $directory -Force -Recurse" } catch { Write-Error "Failed to delete the file ${directory}: $_. Aborting..." } } } function Show-Starting-Message { $date = Get-Date Write-Output "Begin - MDM Data Collection Script - $date" Write-Output "Script version $ScriptVersion" Write-Output "Collecting general information..." Write-Output "MdmDataCollection script version $ScriptVersion" > AboutCollectionScript.txt } function Get-Logical-Disks { Write-Output "Collecting information about logical disks" if (-Not [string]::IsNullOrEmpty($LogicalDisksParam)) { $LogicalDisksParam = $LogicalDisksParam.Replace(" ", "`n") $LogicalDisksParam >> LogicalDisks.txt } else { $logicalDisks = Get-WmiObject -Class Win32_LogicalDisk foreach ($logicalDisk in $logicalDisks) { $logicalDisk.DeviceID >> LogicalDisks.txt } } } function Get-File-Version([String]$processName, [String]$inputFile, [String]$outputFile) { Write-Host "Searching the process: $processName" wmic PROCESS WHERE "(Name='${processName}')" GET ExecutablePath /FORMAT:list | findstr "=" > $inputFile if ([String]::IsNullOrWhiteSpace((Get-content $inputFile))) { Write-Warning "The process $processName is not running" "The process $processName is not running" > $inputFile return } foreach ($process in Get-Content -Path $inputFile) { $executablePath = $process $prefix = "ExecutablePath=" if ($executablePath.StartsWith($prefix)) { $executablePath = $executablePath.Substring($prefix.Length) } Write-Output "$executablePath" >> $outputFile (Get-Item $executablePath).VersionInfo | format-list >> $outputFile } return $executablePath } function Search-CppRestUtil ([String]$metricsExtensionPath) { if ((-Not [string]::IsNullOrEmpty($CppRestUtilPathParam)) -and (Test-Path -Path $CppRestUtilPathParam)) { return $CppRestUtilPathParam } if (Test-Path -Path "..\CppRestUtil\CppRestUtil.exe") { return "..\CppRestUtil\CppRestUtil.exe" } if ($metricsExtensionPath.Contains("MetricsExtension\MetricsExtension.Native.exe")) { # MetricsExtension NuGet setup $possibleLocationCppRestUtil = $metricsExtensionPath.Replace("MetricsExtension\MetricsExtension.Native","CppRestUtil\CppRestUtil") if (Test-Path -Path $possibleLocationCppRestUtil) { return $possibleLocationCppRestUtil } # Monitoring Agent setup $possibleLocationCppRestUtil = $metricsExtensionPath.Replace("MetricsExtension.Native","CppRestUtil") if (Test-Path -Path $possibleLocationCppRestUtil) { return $possibleLocationCppRestUtil } } $warningMessage = "CppRestUtil was not found in the environment. Instead of CppRestUtil, internal Powershell tools will be used." $warningMessage += "Check more information in the following link: https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-health-standards/observability/mdm/geneva-metrics-mdm/docs/tsg/customer-side/actions/winhttp-escalation#powershell-way" Write-Warning $warningMessage return [string]::Empty } function Get-Etw-Session-And-IfxMetrics-At-Start { tasklist /M IfxMetrics.dll /FO CSV > ProcessLoadingIfxMetrics_At_Start.csv logman NativeMetricsExtension_Provider -ets > MetricsExtensionEtwSessionAtStart.txt logman -ets > EtwSessions.txt } function Get-OS-And-Processes-Information { Get-WmiObject -Class Win32_OperatingSystem | Select-Object Caption, SystemDrive, Version > OS.txt Get-WmiObject -Class Win32_Process | Export-Csv -Path "AllProcesses.csv" -NoTypeInformation } function Get-Local-Time-Information { Write-Output "Collecting time from ME client and server" Get-Date > DateTimeLocal.txt Get-TimeZone > TimeZoneInfo.txt } function Get-Difference-Time-Server-And-Agent([String]$cppRestUtil) { if ([string]::IsNullOrEmpty($cppRestUtil)) { Write-Warning "CppRestUtil.exe is not found. MdmDataCollection will not able to check if there is a difference of time between the server and the agent" return } $serverDate = Invoke-Expression "& '$cppRestUtil' https://global.prod.microsoftmetrics.com/public/lb-probe" | findstr /C:"Date" $serverDate > DateTimeServer.txt $serverDate = $serverDate.TrimStart("Date: ") $serverDate = Get-Date -Date "${serverDate}" $serverDateUtc = $serverDate.ToUniversalTime() $localDateUtc = [DateTime]::UtcNow $deltaMinutes = ($localDateUtc - $serverDateUtc).TotalMinutes if (($deltaMinutes -ge 1) -OR ($deltaMinutes -le -5)) { "ERROR: There is a difference of ${deltaMinutes} minutes between ME client time and server time." > TimeDifferenceError.txt Write-Error "ERROR: There is a difference of ${deltaMinutes} minutes between ME client time and server time." } } function Get-Certificates { if ($SkipCollectionCertificates) { Write-Warning "SkipCollectionCertificates has been set, skipping the collection of certificates." } else { certutil -silent -v -gmt -store "My" > Certificates_On_LocalMachine_My.txt certutil -user -v -gmt -silent -store "My" > Certificates_On_User_My.txt } } function Get-HTTP-Proxy-Configuration { netsh winhttp dump > WinHttp_Config.txt } function Get-Environment-Variables { Get-ChildItem env: | Where-Object -Value $ExcludedEnvironmentVariables -NotIn -Property Name > EnvironmentVariables.txt } function Test-ME-Stamps([String]$mdmDataCollectionOutput, [String]$cppRestUtil) { Write-Output "Testing several MetricsExtension global endpoints" foreach ($meStamp in $MeStamps) { foreach ($stampPath in $StampPaths) { Test-Connection-To-URL $cppRestUtil $meStamp$stampPath >> .\CppRestUtilResults.txt } } } function Get-Open-Sockets-And-Owning-Processes { Write-Output "Listing open sockets and owning processes" netstat -abno > ListeningSockets.txt } function Test-Frontend-Urls { foreach ($meFrontendUrl in $MeFrontendUrls) { foreach ($port in $Ports) { $solvedDNS = Resolve-DnsName -Name $meFrontendUrl Write-Output "Running IPv4 against ${meFrontendUrl}:${port}" 1>> GlobalStamp_TCPPing.txt Test-NetConnection $solvedDNS.IP4Address -port ${port} -InformationLevel "Detailed" 1>> GlobalStamp_TCPPing.txt 2>&1 Write-Output "Finished running IPv4 against ${meFrontendUrl}:${port}" 1>> GlobalStamp_TCPPing.txt Write-Output "Running IPv6 against ${meFrontendUrl}:${port}" 1>> GlobalStamp_TCPPing.txt Test-NetConnection $solvedDNS.IP6Address -port ${port} -InformationLevel "Detailed" 1>> GlobalStamp_TCPPing.txt 2>&1 Write-Output "Finished running IPv6 against ${meFrontendUrl}:${port}" 1>> GlobalStamp_TCPPing.txt } } } function Get-Application-Event-Logs { Write-Output "Collecting application event logs for Level Error and EventID 1000 happened within last one hour..." Write-Output "Collecting application event logs for Level Error and EventID 1000 happened within last one hour..." > ApplicationErrorLog.txt wevtutil qe Application /q:"*[System[Level=2 and EventID=1000 and TimeCreated[timediff(@SystemTime) <= 3600000]]]" /f:text /rd:true >> ApplicationErrorLog.txt } function Get-Raw-And-Aggregated-Metrics { Set-MdmInputOutputProviders-File Write-Output "Collecting raw and aggregated metrics, please wait..." Invoke-Command "logman start MdmDataCollection -max ${MetricCollectionSizeMaxMB} -pf mdmInputOutputProviders.txt -o mdmRaw.etl -ets" timeout ${MetricCollectionDurationSec} /nobreak Invoke-Command "logman stop MdmDataCollection -ets" Invoke-Command "Remove-Item mdmInputOutputProviders.txt" logman -ets | findstr /i IfxViewerSession > IfxConsumerSessions.txt foreach ($ifxConsumerSession in Get-Content -Path .\IfxConsumerSessions.txt) { Invoke-Command "logman stop $ifxConsumerSession -ets" } } function Set-MdmInputOutputProviders-File { $content = @( "{edc24920-e004-40f6-a8e1-0e6e48f39d84}" "{2f23a2a9-0de7-4cb4-a778-fbdf5c1e7372}" ) $pathMdmInputOutputProviders = (Get-Item -Path ".\" -Verbose).FullName | Join-Path -ChildPath 'mdmInputOutputProviders.txt' [IO.File]::WriteAllLines($pathMdmInputOutputProviders, $content) } function Search-Files-Job([Object[]]$fileNames, [Object[]]$logicalDisks, [String]$outputFile, [String]$currentPath) { $searchFilesFunc = $(Get-Command Search-Files).Definition $invokeCommandFunc = $(Get-Command Invoke-Command).Definition $scriptBlock = { param($fileNames, $logicalDisks, $outputFile, $currentPath) Set-Location $currentPath Invoke-Expression "function Search-Files {$using:searchFilesFunc}" Invoke-Expression "function Invoke-Command {$using:invokeCommandFunc}" Search-Files -fileNames $fileNames -logicalDisks $logicalDisks -outputFile $outputFile } $job = Start-Job -ArgumentList $fileNames, $logicalDisks, $outputFile, $currentPath -ScriptBlock $scriptBlock $job | Wait-Job -Timeout $TimeOutSecondsSearchFiles if ($job.State -ne "Completed") { Write-Warning "$fileNames were searched but they took more than $TimeOutSecondsSearchFiles seconds, aborting this search..." } } function Search-Files([Object[]]$fileNames, [Object[]]$logicalDisks, [String]$outputFile) { foreach($logicalDisk in $logicalDisks) { foreach($fileName in $fileNames) { try { Write-Output "cmd /c dir /s/b ${logicalDisk}\${fileName}" cmd /c "dir /s/b ${logicalDisk}\${fileName} > lastDir.txt 2>>dirFailures.txt" } catch { "ERROR: cmd /c dir /s/b ${logicalDisk}\${fileName} failed: $_" >> dirFailures.txt Write-Error "ERROR: cmd /c dir /s/b ${logicalDisk}\${fileName} failed: $_" } Invoke-Command "Get-Content .\lastDir.txt" Get-Content .\lastDir.txt >> $outputFile } } } function Get-Command-Line-Arguments { $errorMessage = "CommandLineArguments from MetricsExtension.Native.exe were not found." try { $commandLineArguments = (Get-WmiObject Win32_Process -Filter "Name='MetricsExtension.Native.exe'").CommandLine if (-Not [string]::IsNullOrEmpty($commandLineArguments)) { $commandLineArguments > CommandLineArgumentsME.txt return $commandLineArguments } } catch { $errorMessage += " Exception: $_" Write-Error $errorMessage } $errorMessage > CommandLineArgumentsME.txt return [string]::Empty } function Get-Cached-Config([String]$commandLineArguments) { $dataDirectories = Get-Data-Directories $commandLineArguments $counter = 1 foreach ($dataDirectory in $dataDirectories) { if (Test-Path -Path $dataDirectory) { Invoke-Command "New-Item -ItemType Directory -Path .\MetricsExtensionCachedConfig_$counter" Invoke-Command "Copy-Item -Path '$dataDirectory*' -Destination '.\MetricsExtensionCachedConfig_$counter' -Recurse -Force" $counter++ } } } function Get-Data-Directories([String]$commandLineArguments) { # As there could be several ME processes running at the same time, we will collect the data directories of all of them $dataDirectories = @() # Try to use the -DataDirectory parameter if (-Not [string]::IsNullOrEmpty($commandLineArguments)) { $commandLineArgumentsArray = $commandLineArguments.Split(" ") for ($i = 1; $i -lt $commandLineArgumentsArray.Count; $i++) { $arg = $commandLineArgumentsArray[$i] if ($arg -eq "-DataDirectory") { $i++ $dataDirectory = $commandLineArgumentsArray[$i] $dataDirectory = $dataDirectory.Replace('"', '') if ($dataDirectory[-1] -ne '\') { $dataDirectory += '\' } $dataDirectories += $dataDirectory } } } # Try to get the path from env var MONITORING_DATA_DIR if (Test-Path env:MONITORING_DATA_DIR) { $dataDirectories += $env:MONITORING_DATA_DIR + '\MetricsExtensionData\' } # Try to get the path from env var DiagnosticStore if (Test-Path env:DiagnosticStore) { $dataDirectories += $env:DiagnosticStore + '\MetricsExtensionData\' } # Get the path from TEMP dir $dataDirectories += $env:TEMP + '\MetricsExtensionData\' return $dataDirectories } function Copy-Autopilot-Logs { if (Test-Path -Path D:\Data\logs\local) { Write-Output "Copying autopilot logs..." Invoke-Command "mkdir .\GenevaMetricsExtensionLogs" Invoke-Command "Copy-Item -Path (Get-ChildItem D:\Data\logs\local\GenevaMetricsExtension_*.log) -Destination GenevaMetricsExtensionLogs" Invoke-Command "mkdir .\GenevaMetricsExtensionHostLogs" Invoke-Command "Copy-Item -Path (Get-ChildItem D:\Data\logs\local\GenevaMetricsExtensionHost_*.log) -Destination GenevaMetricsExtensionHostLogs" } else { Write-Warning "No autopilot logs were found. If this machine is not an Autopilot machine, this is not an issue." } } function Get-Autopilot-Ini { if (Test-Path -Path D:\app\autopilot.ini) { Write-Output "Attempting to collect autopilot.ini..." Write-Output "Attempting to collect autopilot.ini..." > CollectAutopilotLogs.txt Invoke-Command "xcopy /C D:\app\autopilot.ini >> CollectAutopilotLogs.txt" } else { Write-Warning "D:\app\autopilot.ini was not found. If this machine is not an Autopilot machine, this is not an issue." } } function Convert-Tsf-Logs-To-Csv([String]$table2csv) { $tsfCounter = 0 foreach ($tsfLog in Get-Content -Path .\TsfLogs.txt) { try { Write-Output "$table2csv $Table2CsvParameters $tsfLog" Write-Output "Waiting for Table2Csv to complete..." Write-Output "${table2csv} $Table2CsvParameters} ${tsfLog}" >> Table2CsvLogs.txt Invoke-Expression "${Table2Csv} ${Table2CsvParameters} '${tsfLog}'" >> Table2CsvLogs.txt } catch { "ERROR: Command {$table2csv $Table2CsvParameters '$tsfLog'} Failed: $_" >> Table2CsvLogs.txt Write-Error "ERROR: Command {$table2csv $Table2CsvParameters '$tsfLog'} Failed: $_" } $tsfCounter++ $csvFullPath = $tsfLog.Replace("tsf","csv") $tsfLogFileName = Split-Path $tsfLog -Leaf $csvLogFileName = $tsfLogFileName.Replace(".tsf", "_${tsfCounter}.csv") try { Write-Output "Copy-Item '${csvFullPath}' ${csvLogFileName}" Invoke-Command "Copy-Item '${csvFullPath}' .\${csvLogFileName} 2>> CsvCopyErrors.txt" } catch { "ERROR: Command {failed to copy ${csvFullPath} to .\${csvLogFileName}}: $_" >> CsvCopyErrors.txt Write-Error "ERROR: Command {failed to copy ${csvFullPath} to .\${csvLogFileName}}: $_" } } } function Get-Etw-Session-And-IfxMetrics-At-End { tasklist /M IfxMetrics.dll /FO CSV > ProcessLoadingIfxMetrics_At_End.csv logman NativeMetricsExtension_Provider -ets > MetricsExtensionEtwSessionAtEnd.txt } function Compress-Output([String]$compressedDataOutput, [String]$mdmDataCollectionOutput) { Write-Output "Compressing MDM Data Collection Output ..." try { Invoke-Command "Compress-Archive -Force -Path .\* -DestinationPath '$OutputDirectory\$compressedDataOutput'" Invoke-Command "Set-Location .." Invoke-Command "Remove-Item -r -Force $mdmDataCollectionOutput" Write-Output "Done -^> MDM Data ready at $OutputDirectory\$compressedDataOutput" } catch { Write-Error "ERROR: MDM Data Collection Output has not been compressed: $_" } } function Show-Ending-Message { $date = Get-Date Write-Output "End - MDM Data Collection Script - $date" } function Invoke-Command([String]$command) { $output = Invoke-Expression $command if ($DebugMdmDataCollection) { Write-Output $output } } function Test-Connection-To-URL([String]$cppRestUtil, [String]$url) { try { if ([String]::IsNullOrEmpty($cppRestUtil)) { [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } Write-Output "(New-Object System.IO.StreamReader ((([System.Net.WebRequest]::Create($url)).GetResponse()).GetResponseStream())).ReadToEnd()" (New-Object System.IO.StreamReader ((([System.Net.WebRequest]::Create($url)).GetResponse()).GetResponseStream())).ReadToEnd() } else { Write-Output "'$cppRestUtil' --json $url" Invoke-Expression "& '$cppRestUtil' --json $url" } } catch { "Request to $url failed." } Write-Output "" } function Search-Table2csv([String]$monAgentHostPath) { if ((-Not [string]::IsNullOrEmpty($Table2CsvPathParam)) -and (Test-Path -Path $Table2CsvPathParam)) { return $Table2CsvPathParam } if (-Not [string]::IsNullOrEmpty($monAgentHostPath) -And $monAgentHostPath.Contains("MonAgentHost.exe")) { $table2CsvPath = $monAgentHostPath.Replace("MonAgentHost.exe","table2csv.exe") if (Test-Path -Path $table2CsvPath) { return $table2CsvPath } } return [string]::Empty } function Get-Tsf-Logs([Object[]]$logicalDisks, [String]$mdmDataCollectionOutput, [String]$monAgentHostPath) { if ($SkipCollectionTsfLogs) { Write-Warning "SkipCollectionTsfLogs has been set, skipping the collection of tsf logs." } else { $fileNames = @( "MaMetricsExtensionEtw.tsf" "MAEventTable.tsf" "LocallyAggregatedMdmMetricsV1.tsf" ) $table2csv = Search-Table2csv $monAgentHostPath if ([string]::IsNullOrEmpty($table2csv)) { $warningMessage = "table2csv.exe was not found. Tsf logs will not be collected." $warningMessage += "Please take in account this scenario is useful only if you are using MonitoringAgent" Write-Warning $warningMessage } else { Search-Files-Job $fileNames $logicalDisks "TsfLogs.txt" "$PSScriptRoot\$mdmDataCollectionOutput" Convert-Tsf-Logs-To-Csv $table2csv } } } if (-Not $ImportFunctions) { Main } # SIG # Begin signature block # MIIoLAYJKoZIhvcNAQcCoIIoHTCCKBkCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA+SYwK6aSxmkQa # MrnYTFJMM31grDuHpogCjLtajE58raCCDXYwggX0MIID3KADAgECAhMzAAADTrU8 # 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 # /Xmfwb1tbWrJUnMTDXpQzTGCGgwwghoIAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAANOtTx6wYRv6ysAAAAAA04wDQYJYIZIAWUDBAIB # BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIIl89rgffZkiVAVH6Ph3t9JW # 4Wc+2aZVEFIhCmgb01ehMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A # cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB # BQAEggEAT9ugYDgnHWahUfz5Na8/9dytGClpzd98AxEO2LZfWbitL+7ERF4ssPz5 # sWeMqnno04zRsS6s2PptU10sfq9lI4MfexKuVN65wZswXdFd4c0VkLkQ9VQTPRmv # OeS7Vkt2inwdiODUBzUxS3mcW/zwxDcnXl7KAv67iucrr73VtV7RC+iDowHQ/th7 # TDibGfaq2CVuwMfwaUXaA9wmx2YdiFUtNq839iAHQIrHyvjiRq7FeWKdfN0CnFTq # 74+0CV7zc+HY/vNFyPJRWj9moLpZ/+VEGs8yWUt8y8S1ejh9lFFClyQWjfhLOq58 # To6VHNA+4zXdQmpBy/0RY0gdCn9L06GCF5YwgheSBgorBgEEAYI3AwMBMYIXgjCC # F34GCSqGSIb3DQEHAqCCF28wghdrAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFRBgsq # hkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl # AwQCAQUABCCVsg197dGV+2SAVuA2aivXeBwDP2Ux1BKAUrwGxm6VdgIGZQPuFOFx # GBIyMDIzMDkyMjA4MzA1OC4zMVowBIACAfSggdGkgc4wgcsxCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVy # aWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjpBMDAwLTA1 # RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCC # Ee0wggcgMIIFCKADAgECAhMzAAAB0HcIqu+jF8bdAAEAAAHQMA0GCSqGSIb3DQEB # CwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV # BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTIzMDUyNTE5MTIx # NFoXDTI0MDIwMTE5MTIxNFowgcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMx # JzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjpBMDAwLTA1RTAtRDk0NzElMCMGA1UE # AxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCCAiIwDQYJKoZIhvcNAQEB # BQADggIPADCCAgoCggIBAN8yV+ffl+8zRcBRKYjmqIbRTE+LbkeRLIGDOTfOlg7f # XV3U4QQXPRCkArbezV0kWuMHmAP5IzDnPoTDELgKtdT0ppDhY0eoeuFZ+2mCjcyQ # l7H1+uY70yV1R+NQbnqwhbphUXpiNf72tPUkN0IMdujmdmJqwyKAYprAZvYeoPv+ # SNFHrtG9WHtDidq0BW7jpl/kwu+JHTE3lw0bbTHAHCC21pgSTleVQtoEfk6dfPZ5 # agjH5KMM7sG3kG4AFZjxK+ZFB8HJPZymkTNOO39+zTGngHVwAdUPCUbBm6/1F9ze # d13GAWsoDwxYdskXT5pZRRggFHwXLaC4VUegd47N7sixvK9GtrH//zeBiqjxzln/ # X+7uSMtxOCKmLJnxcRGwsQQInmjHUEEtjoCOZuADMN02XYt56P6oht0Gv9JS8oQL # 5fDjGMUw5NRVYpZ6a3aSHCd1R8E1Hs3O7XP0vRa/tMBj+/6/qk2EB6iE8wIUlz5q # Tq4wPxMpLNYWPDloAOSYP2Ya4LzrK9IqQgjgxrLOhR2x5PSd+TxjR8+O13DZad6O # XrMse5hfBwNq7Y7UMy6iJ501WNMXftQSZhP6jEL84VdQY8MRC323OBtH2Dwcu1R8 # R5Y6w4QPnGBvmvDJ+8iyzsf9x0cVwiIhzPNCBiewvIQZ6mhkOQqFIxHl4IHopy/9 # AgMBAAGjggFJMIIBRTAdBgNVHQ4EFgQUM+EBhZLSgD6U60hN+Mm3KXSSdFEwHwYD # VR0jBBgwFoAUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXwYDVR0fBFgwVjBUoFKgUIZO # aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIw # VGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3JsMGwGCCsGAQUFBwEBBGAwXjBc # BggrBgEFBQcwAoZQaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0 # cy9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcnQwDAYD # VR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8EBAMC # B4AwDQYJKoZIhvcNAQELBQADggIBAJeH5yQKRloDTpI1b6rG1L2AdCnjHsb6B2KS # eAoi0Svyi2RciuZY9itqtFYGVj3WWoaKKUfIiVneI0FRto0SZooAYxnlhxLshlQo # 9qrWNTSazKX7yiDS30L9nbr5q3He+yEesVC5KDBMdlWnO/uTwJicFijF2EjW4aGo # fn3maou+0yzEQ3/WyjtT5vdTosKvLm7DBzPn6Pw6PQZRfdv6JmD4CzTFM3pPRBrw # E15z8vBzKpg0RoyRbZUAquaG9Yfw4INNxeA42ecAFAcF9cr98sBscUZLVc062vrb # +JocEYCSsIaXoGLw9/Czp+z7D6wT2veFf1WDSCxEygdG4xqJeysaYay5icufcDBO # C4xq3D1HxTm8m1ZKW7UIU7k/QsS9BCIxnXaxBKxACQ0NOz2tONU2OMhSChnpc8zG # Vw8gNyPHDxt95vjLjADEzZFGhZzGmTH7ogh/Yv5vuAse0HFcJYnlsxbtbBQLYuW1 # u6tTAG/RKCOkO1sSrD+4OBYF6sJP5m3Lc1z3ruIZpCPJhAfof+H1dzyyabafpWPJ # JHHazCdbeGvpDHrdT/Fj0cvoU2GsaIUQPtlEqufC+9e8xVBQgSQHsZQR43qF5jyA # cu3SMtXfLMOJADxHynlgaAYBW30wTCAAk1jWIe8f/y/OElJkU2Qfyy9HO07+LdO8 # quNvxnHCMIIHcTCCBVmgAwIBAgITMwAAABXF52ueAptJmQAAAAAAFTANBgkqhkiG # 9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO # BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEy # MDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw # MTAwHhcNMjEwOTMwMTgyMjI1WhcNMzAwOTMwMTgzMjI1WjB8MQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGlt # ZS1TdGFtcCBQQ0EgMjAxMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB # AOThpkzntHIhC3miy9ckeb0O1YLT/e6cBwfSqWxOdcjKNVf2AX9sSuDivbk+F2Az # /1xPx2b3lVNxWuJ+Slr+uDZnhUYjDLWNE893MsAQGOhgfWpSg0S3po5GawcU88V2 # 9YZQ3MFEyHFcUTE3oAo4bo3t1w/YJlN8OWECesSq/XJprx2rrPY2vjUmZNqYO7oa # ezOtgFt+jBAcnVL+tuhiJdxqD89d9P6OU8/W7IVWTe/dvI2k45GPsjksUZzpcGkN # yjYtcI4xyDUoveO0hyTD4MmPfrVUj9z6BVWYbWg7mka97aSueik3rMvrg0XnRm7K # MtXAhjBcTyziYrLNueKNiOSWrAFKu75xqRdbZ2De+JKRHh09/SDPc31BmkZ1zcRf # NN0Sidb9pSB9fvzZnkXftnIv231fgLrbqn427DZM9ituqBJR6L8FA6PRc6ZNN3SU # HDSCD/AQ8rdHGO2n6Jl8P0zbr17C89XYcz1DTsEzOUyOArxCaC4Q6oRRRuLRvWoY # WmEBc8pnol7XKHYC4jMYctenIPDC+hIK12NvDMk2ZItboKaDIV1fMHSRlJTYuVD5 # C4lh8zYGNRiER9vcG9H9stQcxWv2XFJRXRLbJbqvUAV6bMURHXLvjflSxIUXk8A8 # FdsaN8cIFRg/eKtFtvUeh17aj54WcmnGrnu3tz5q4i6tAgMBAAGjggHdMIIB2TAS # BgkrBgEEAYI3FQEEBQIDAQABMCMGCSsGAQQBgjcVAgQWBBQqp1L+ZMSavoKRPEY1 # Kc8Q/y8E7jAdBgNVHQ4EFgQUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXAYDVR0gBFUw # UzBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNy # b3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMBMGA1UdJQQMMAoG # CCsGAQUFBwMIMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIB # hjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fO # mhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9w # a2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggr # BgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNv # bS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MA0GCSqGSIb3 # DQEBCwUAA4ICAQCdVX38Kq3hLB9nATEkW+Geckv8qW/qXBS2Pk5HZHixBpOXPTEz # tTnXwnE2P9pkbHzQdTltuw8x5MKP+2zRoZQYIu7pZmc6U03dmLq2HnjYNi6cqYJW # AAOwBb6J6Gngugnue99qb74py27YP0h1AdkY3m2CDPVtI1TkeFN1JFe53Z/zjj3G # 82jfZfakVqr3lbYoVSfQJL1AoL8ZthISEV09J+BAljis9/kpicO8F7BUhUKz/Aye # ixmJ5/ALaoHCgRlCGVJ1ijbCHcNhcy4sa3tuPywJeBTpkbKpW99Jo3QMvOyRgNI9 # 5ko+ZjtPu4b6MhrZlvSP9pEB9s7GdP32THJvEKt1MMU0sHrYUP4KWN1APMdUbZ1j # dEgssU5HLcEUBHG/ZPkkvnNtyo4JvbMBV0lUZNlz138eW0QBjloZkWsNn6Qo3GcZ # KCS6OEuabvshVGtqRRFHqfG3rsjoiV5PndLQTHa1V1QJsWkBRH58oWFsc/4Ku+xB # Zj1p/cvBQUl+fpO+y/g75LcVv7TOPqUxUYS8vwLBgqJ7Fx0ViY1w/ue10CgaiQuP # Ntq6TPmb/wrpNPgkNWcr4A245oyZ1uEi6vAnQj0llOZ0dFtq0Z4+7X6gMTN9vMvp # e784cETRkPHIqzqKOghif9lwY1NNje6CbaUFEMFxBmoQtB1VM1izoXBm8qGCA1Aw # ggI4AgEBMIH5oYHRpIHOMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu # Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv # cmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScw # JQYDVQQLEx5uU2hpZWxkIFRTUyBFU046QTAwMC0wNUUwLUQ5NDcxJTAjBgNVBAMT # HE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoBATAHBgUrDgMCGgMVALy3 # yFPwopRf3WVTkWpE/0J+70yJoIGDMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAg # UENBIDIwMTAwDQYJKoZIhvcNAQELBQACBQDot6Y3MCIYDzIwMjMwOTIyMDUzNTUx # WhgPMjAyMzA5MjMwNTM1NTFaMHcwPQYKKwYBBAGEWQoEATEvMC0wCgIFAOi3pjcC # AQAwCgIBAAICHl8CAf8wBwIBAAICF6kwCgIFAOi497cCAQAwNgYKKwYBBAGEWQoE # AjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkq # hkiG9w0BAQsFAAOCAQEAG2ni8Y4S9DJ/Hpalo3b2NguKaBTCFlw1Dj2zbWelqQ9U # FcUwwepnVcu95src0jo1r0gKY9kkW8XE2E3Wl2YKaXhwguaFwe6rWscInUsVYrsA # Lhy5zjzLq3xO4W70brFH2nw2Ugo7np0kQfDz2xH6JMvKTbH94CoD5en30I6b93nh # THw82yMBnYgQFmSBC9JHha0hq2mwmgHf8oTWA/SqK+3KnQIIfb1c6BzukLxWhVwo # gRql0AbY3vMf1X6N0cInB8z6cfZCHzm58dSHKLYNeQ5TNkBFMsfhHp9XSJiEk2g1 # yvQrbV81vH1nIj7yDeb5qPfCj92U9GLhMkUfSBrP8zGCBA0wggQJAgEBMIGTMHwx # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1p # Y3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB0HcIqu+jF8bdAAEAAAHQ # MA0GCWCGSAFlAwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQw # LwYJKoZIhvcNAQkEMSIEIHM6VOi4AV+zrH3g1DXmxsGx1Ox/q+LpDS9185IsVqSc # MIH6BgsqhkiG9w0BCRACLzGB6jCB5zCB5DCBvQQgCJVABl+00/8x3UTZjD58Fdr3 # Dp+OZNnlYB6utNI/CdcwgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0Eg # MjAxMAITMwAAAdB3CKrvoxfG3QABAAAB0DAiBCCBT65rD7zPkTVk6H+SQwfbeNll # of5/Q3CQ4fvPhCakvDANBgkqhkiG9w0BAQsFAASCAgAQVTtsC1FvVcz4HUFTxTiP # BWy03IFQwHys+AAU1IfnqYyVfaNOdTdkt6Wxdx7hr0R8gRvH+dKmjK77e/2XMkKj # ol3oWIqcLzU2le9jvnVbuD014bsreDRZw+f9jIgDuDvM1MQsqT0LVbWou2b9xyDq # k8rbyz8UQjKGmfQgEUPm5ITjKa+eqD3b8PuRAkzl3slKTuCaSwZKlSqp5aVd7bDV # Ui8NtFItqFRSSfDwmMPZDwKRT0Omoo/6/v6D4wqEkv8NrLg82vjupyRxKpkNoYma # Ur7siOPH9Mju91fWWkPLqvon/FIoDFbG46I+6WwIbYccNN9l9JJ3ujNOwj+pyfVL # di+pcvapUBAhAQ96bV7CanYHFn109239mZFlhCinbEpome3Rf2DvdPym1dnAw6xZ # gxmI3TPSm4aSl3wrrvud2+VQZfTDHc/edZ26jIv5nUCbJ6HEXBTLCDxkWlS3JWUV # 4UN4JNhENobTWLBjcVUjTC13GHEe+uet4AAVzRUy969VBMs3rbIr0FQ8GGKRnhrn # zfoWhSUOM2hyhfNqqbIWAnHBbBhY+Lb/i7vjRmOtcOXcge8OnSaBBUJVF0uJcrJU # 6zfBHoELm9KHgJcZ6f9uYwxIKeo3l1cWSDmcNuCGkU7hobRILnwc0CmhiuDgnNh7 # Rn9YSBAoBau2dnz7Rj+xiw== # SIG # End signature block |