Files
SCCM-Tools/DesktopAnalyticsLogsCollector/DesktopAnalyticsLogsCollector.ps1
2025-11-24 08:36:36 +01:00

1259 lines
48 KiB
PowerShell

<# M365 Analytics Log Collector #>
#Requires -RunAsAdministrator
#----------------------------------------------------------------------------------------------------------
#
# Parameter Declarations
#
#----------------------------------------------------------------------------------------------------------
Param(
# File share to store logs, the maximum length is 130 since the script would create sub folders and files
[Parameter(Position=1)]
[string]$LogPath,
# LogMode == 0 log to console only
# LogMode == 1 log to file and console
# LogMode == 2 log to file only
[Parameter(Position=2)]
[Int16]$LogMode = 1,
# CollectNetTrace == 0 to disable collect Net Trace, otherwise enable collect Net Trace.
[Parameter(Position=3)]
[Int16]$CollectNetTrace = 0,
# CollectUTCTrace == 0 to disable collect UTC Trace, otherwise enable collect UTC Trace.
[Parameter(Position=4)]
[Int16]$CollectUTCTrace = 0
)
#----------------------------------------------------------------------------------------------------------
#
# Startup
#
#----------------------------------------------------------------------------------------------------------
# Make sure we are running x64 PS on 64-bit OS. If not then start a x64 process of PowerShell
$powerShellHome = $PSHOME.ToLower()
if ([System.Environment]::Is64BitOperatingSystem -eq $true)
{
if ([System.Environment]::Is64BitProcess -eq $false)
{
Write-Verbose "Launching x64 PowerShell"
$powerShellHome = $powerShellHome.Replace('syswow64','sysnative')
&"$powerShellHome\powershell.exe" -ExecutionPolicy AllSigned -NonInteractive -NoProfile $myInvocation.Line
exit $lastexistcode
}
}
#----------------------------------------------------------------------------------------------------------
#
# Parameter Intialization and Validation
#
#----------------------------------------------------------------------------------------------------------
# Parameter: $LogPath
if([String]::IsNullOrEmpty($LogPath) -or [String]::IsNullOrWhiteSpace($LogPath))
{
# Set to default value
$LogPath = "$Env:SystemDrive\M365AnalyticsLogs"
}
else
{
Write-Verbose "Validating path length no more than 130: $LogPath"
$LogPath = $LogPath.Trim().TrimEnd('\')
if($LogPath.Length -gt 130)
{
throw "Failed to validate the length of the given path: $LogPath"
}
# Validate parameter: $LogPath
Write-Verbose "Validating path format: $LogPath"
$validateResult = $false
if((Test-Path $LogPath -IsValid) -eq $true)
{
$testSplitArray = $LogPath.Split(':')
if($testSplitArray.Count -eq 1)
{
$validateResult = $true
}
elseif($testSplitArray.Count -eq 2)
{
$targetDrv = Get-PSDrive -Name $testSplitArray[0]
if($targetDrv -ne $null)
{
$fileDrv = Get-PSProvider -PSProvider FileSystem
if($fileDrv -ne $null)
{
if($fileDrv.Drives.Contains($targetDrv) -eq $true)
{
$validateResult = $true
}
}
}
}
}
if($validateResult -eq $false)
{
throw "Failed to validate the format of the given path: $LogPath"
}
}
Write-Verbose "Output Path = $LogPath"
# Parameter: $LogMode
Write-Verbose "Validating log mode(0|1|2): $LogMode"
if(($LogMode -ne 0) -and ($LogMode -ne 1) -and ($LogMode -ne 2))
{
throw "Failed to validate the given log mode: $LogMode"
}
Write-Verbose "Log Mode = $LogMode"
# Parameter: $CollectNetTrace
if($CollectNetTrace -eq 0)
{
Write-Verbose "Collect Net Trace = No"
}
else
{
Write-Verbose "Collect Net Trace = Yes"
}
# Parameter: $CollectUTCTrace
if($CollectUTCTrace -eq 0)
{
Write-Verbose "Collect UTC Trace = No"
}
else
{
Write-Verbose "Collect UTC Trace = Yes"
}
#----------------------------------------------------------------------------------------------------------
#
# Global Variables
#
#----------------------------------------------------------------------------------------------------------
# Temporary file to store providers
$global:tempProviderFile = [System.IO.Path]::GetTempFileName()
# Providers info
$global:providersText = @"
{43ac453b-97cd-4b51-4376-db7c9bb963ac} 0 255
{56DC463B-97E8-4B59-E836-AB7C9BB96301} 0 255
"@
# Script folder root
$global:scriptRoot = Split-Path -Path $MyInvocation.MyCommand.Path
# Set the exit code to the first exception exit code
$global:errorCode = [string]::Empty;
# Total error count while running the script
[int]$global:errorCount = 0;
# OS version
$global:osVersion = (Get-WmiObject Win32_OperatingSystem).Version
# OS name
$global:operatingSystemName = (Get-WmiObject Win32_OperatingSystem).Name
# OS Architecture
$global:osArchitecture = $ENV:Processor_Architecture
# Global utc trace name
$global:timeStart=Get-Date
$global:timeStartString=$global:timeStart.ToString("yy_MM_dd_HH_mm_ss")
$global:utcTraceName = "utctrace" + $global:timeStartString
#----------------------------------------------------------------------------------------------------------------
#
# Main
#
#----------------------------------------------------------------------------------------------------------------
$main = {
Try
{
# Initialize provider file
InitializeProviderFile
# Quit if System variable WINDIR is not set
Try
{
$global:windir=[System.Environment]::ExpandEnvironmentVariables("%WINDIR%")
}
Catch
{
$exceptionDetails = "Exception: " + $_.Exception.Message + "HResult: " + $_.Exception.HResult
Write-Error "Failure finding system variable WINDIR. $exceptionDetails Error 23"
[System.Environment]::Exit(23)
}
# Get Sqm Machine Id
Get-SqmID
# Get ConfigMgr Client Version
Get-CmClientVersion
# Create the log file if logMode requires logging to file.
CreateLogFile
Log "Starting M365AnalyticsLogsCollector"
Log "UTC DateTime: $global:utcDate"
Log "OS: $global:osVersion"
Log "Architecture: $global:osArchitecture"
Log "Machine Sqm Id: $global:sClientId"
Log "Configuration Manager Client Version: $global:smsClientVersion"
# Sets VerboseMode to enable appraiser logging value to the registry
SetAppraiserVerboseMode
# Sets RequestAllAppraiserVersions key
if($global:osBuildNumber -lt 10240)
{
SetRequestAllAppraiserVersions
}
if($CollectNetTrace -ne 0)
{
# Start Netsh trace
StartNetworkTrace
}
if($CollectUTCTrace -ne 0)
{
#Start UTC trace
StartUTCTrace
}
# restart Diagtrack service
RestartDiagtrack
# Run Connectivity Tool
RunConnectivityDiagnosis
# Run Census
RunCensus
if($CollectNetTrace -ne 0)
{
# Stop Netsh trace
StopNetworkTrace
}
if($CollectUTCTrace -ne 0)
{
# Stop UTC trace
StopUTCTrace
}
# Run Appraiser
RunAppraiser
# Collect the logs
Try
{
Log "Running diagnose_internal to collect logs"
DiagnoseInternal $global:logFolder
}
Catch
{
Log "diagnose_internal failed with unexpected exception" "Error" "37" "diagnose_internal" $_.Exception.HResult $_.Exception.Message
}
# Collect M365AHandler logs
CollectM365AHandlerLog
if($global:errorCount -eq 0)
{
Log "Script finished successfully"
Exit(0)
}
}
Catch
{
Log "Unexpected error occured while executing the script" "Error" "1" "UnExpectedException" $_.Exception.HResult $_.Exception.Message
Log "Script failed" "Failure" "1" "ScriptEnd"
[System.Environment]::Exit(1)
}
Finally
{
# Disable appriaser verbose mode after running the appriaser
DisableAppraiserVerboseMode
# Restart Diagtrack service
RestartDiagtrack
# Cleanup temporary file
Remove-Item -Path $global:tempProviderFile
}
}
#----------------------------------------------------------------------------------------------------------
#
# Function Definitions
#
#----------------------------------------------------------------------------------------------------------
function InitializeProviderFile
{
$global:providersText | Out-File $global:tempProviderFile -Append -Encoding ascii
}
function DiagnoseInternal($diaLogPath)
{
if ((test-path $diaLogPath) -eq $false)
{
New-Item -ItemType Directory -Path $diaLogPath -Force | Out-Null
}
Get-WmiObject -Query 'select * from win32_quickfixengineering' | sort hotfixid | Out-File "$diaLogPath\installedKBs.txt" -Force
ROBOCOPY "$env:windir\appcompat" "$diaLogPath\appcompat" *.* /E /XF *.hve* /R:1 | Out-Null
regedit /e "$diaLogPath\RegAppCompatFlags.txt" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags"
regedit /e "$diaLogPath\RegCensus.txt" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Census"
regedit /e "$diaLogPath\RegSQM.txt" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SQMClient"
regedit /e "$diaLogPath\RegDiagTrack.txt" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Diagnostics\DiagTrack"
regedit /e "$diaLogPath\RegPoliciesDataCollection.txt" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection"
regedit /e "$diaLogPath\RegDataCollection.txt" "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\DataCollection"
}
function Get-SqmID
{
Try
{
$sqmID = (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\SQMClient -Name MachineId).MachineId
$global:sClientId = "s:" + $sqmID.Substring(1).Replace("}", "")
}
Catch
{
$hexHresult = "{0:X}" -f $_.Exception.HResult
$exceptionMessage = $_.Exception.Message
Write-Error "Get-SqmID failed with unexpected exception.`nException: $exceptionMessage HResult: 0x$hexHresult"
[System.Environment]::Exit(38)
}
}
function Get-CmClientVersion
{
try {
$propertyPath = "HKLM:\SOFTWARE\Microsoft\SMS\Mobile Client"
$propertyName = "SmsClientVersion"
if (Test-Path -Path $propertyPath)
{
$property = Get-ItemProperty -Path $propertyPath -Name $propertyName -ErrorAction SilentlyContinue
if ($null -eq $property)
{
Log "Get-CmClientVersion: Could not find registry value $propertyName at path $propertyPath" "Warning"
}
else {
$global:smsClientVersion = $property.SmsClientVersion
}
}
else
{
Log "Get-CmClientVersion: Could not find registry key $propertyPath" "Warning"
}
}
catch {
Log "Get-CmClientVersion: Error getting $propertyName registry value at path $propertyPath" "Warning" $null "Get-CmClientVersion" $_.Exception.HResult $_.Exception.Message
}
}
function CreateLogFile
{
Write-Verbose "Creating output folder"
$timeStart=Get-Date
$timeStartString=$timeStart.ToString("yy_MM_dd_HH_mm_ss")
$logFolderName = "M365AnalyticsLogs_" + $timeStartString
$global:logFolder = $logPath +"\"+$logFolderName
Try
{
$outputFolder = New-Item $global:logFolder -type directory
Write-Host "Output folder created successfully: $outputFolder"
}
Catch
{
$hexHresult = "{0:X}" -f $_.Exception.HResult
$exceptionMessage = $_.Exception.Message
Write-Error "Could not create output folder at the given logPath: $LogPath`nException: $exceptionMessage HResult: 0x$hexHresult"
[System.Environment]::Exit(28)
}
if($LogMode -ne 0)
{
Write-Verbose "Creating Log File"
$fileName = $logFolderName+".txt"
$global:logFile=$global:logFolder+"\"+$fileName
Try
{
New-Item $global:logFile -type file | Out-Null
Write-Verbose "Log File created successfully: $global:logFile"
}
Catch
{
$hexHresult = "{0:X}" -f $_.Exception.HResult
$exceptionMessage = $_.Exception.Message
Write-Error "Could not create log file at the given logPath: $LogPath`nException: $exceptionMessage HResult: 0x$hexHresult"
[System.Environment]::Exit(28)
}
}
}
function StartNetworkTrace
{
Try
{
Log "Start: StartNetworkTrace"
netsh trace start capture=yes scenario=InternetClient provider=Microsoft-Windows-CAPI2 traceFile="$global:logFolder\nettrace.etl" | Out-Null
Log "Passed: StartNetworkTrace"
}
Catch
{
Log "StartNetworkTrace failed with an unexpected exception." "Error" "2001" "StartNetworkTrace" $_.Exception.HResult $_.Exception.Message
}
}
function StartUTCTrace
{
Try
{
Log "Start: StartUTCTrace"
$logmanFolder = $null
if($global:osArchitecture.contains("64"))
{
$logmanFolder = "$global:windir\system32\"
}
else
{
$logmanFolder = "$global:windir\system32\"
}
& logman start $global:utcTraceName -pf "$global:tempProviderFile" -bs 32768 -nb 128 -ets -o "$global:logFolder\DAUTCtrace.etl" | Out-Null
Log "Passed: StartUTCTrace"
}
Catch
{
Log "StartUTCTrace failed with an unexpected exception." "Error" "2003" "StartUTCTrace" $_.Exception.HResult $_.Exception.Message
}
}
function StopNetworkTrace
{
Try
{
Log "Start: StopNetworkTrace"
netsh trace stop | Out-Null
Log "Passed: StopNetworkTrace"
}
Catch
{
Log "StopNetworkTrace failed with an unexpected exception." "Error" "2002" "StopNetworkTrace" $_.Exception.HResult $_.Exception.Message
}
}
function StopUTCTrace
{
Try
{
Log "Start: StopUTCTrace"
$logmanFolder = $null
if($global:osArchitecture.contains("64"))
{
$logmanFolder = "$global:windir\system32\"
}
else
{
$logmanFolder = "$global:windir\system32\"
}
& logman.exe stop $global:utcTraceName -ets | Out-Null
Log "Passed: StopUTCTrace"
Log "Collect DownloadedSettings to log folder"
& takeown -f "$Env:ProgramData\Microsoft\Diagnosis\DownloadedSettings\*" | Out-Null
& icacls "$Env:ProgramData\Microsoft\Diagnosis\DownloadedSettings\*" /grant administrators:f | Out-Null
New-Item $global:logFolder\DownloadedSettings -type directory | Out-Null
Copy-Item "$Env:ProgramData\Microsoft\Diagnosis\DownloadedSettings\*" -Destination $global:logFolder\DownloadedSettings | Out-Null
}
Catch
{
Log "StopUTCTrace failed with an unexpected exception." "Error" "2004" "StopUTCTrace" $_.Exception.HResult $_.Exception.Message
}
}
function RestartDiagtrack
{
Log "Start: RestartDiagtrack"
Try
{
& Net stop diagtrack | Out-Null
& Reg add hklm\software\microsoft\windows\currentversion\diagnostics\diagtrack\testhooks /v ResetEventStore /t REG_DWORD /d 1 /f | Out-Null
& Net start diagtrack | Out-Null
& Reg delete hklm\software\microsoft\windows\currentversion\diagnostics\diagtrack\testhooks /v ResetEventStore /f | Out-Null
Log "Passed: RestartDiagtrack"
}
Catch
{
Log "RestartDiagtrack failed to execute - script will continue." "Warning" $null "RestartDiagtrack" $_.Exception.HResult $_.Exception.Message
return
}
}
function RunConnectivityDiagnosis
{
Log "Start: RunConnectivityDiagnosis"
Try
{
$propertyPath = "HKLM:\SOFTWARE\Microsoft\CCM\Logging\@Global"
if(Test-Path -Path $propertyPath)
{
if ((Get-ItemProperty -Path $propertyPath -Name LogDirectory -ErrorAction SilentlyContinue) -eq $null)
{
Log "Could not find registry key LogDirectory at path HKLM:\SOFTWARE\Microsoft\CCM\Logging\@Global"
}
else
{
Try
{
$logDirectoryKeyM365 = Get-ItemProperty -Path $propertyPath -Name LogDirectory
$logDirectoryM365 = $logDirectoryKeyM365.LogDirectory
$connectivitydiagnosis = $logDirectoryM365.ToString().Replace("Logs", "settingsplugins\connectivitydiagnosis.exe")
if((Test-Path -Path $connectivitydiagnosis) -eq $False)
{
$connectivitydiagnosis = $logDirectoryM365.ToString().Replace("Logs", "connectivitydiagnosis.exe")
}
#Log $connectivitydiagnosis
#Log $logDirectoryM365
$currentDirectory = $global:scriptRoot
& cd $global:logFolder
& timeout 5 | Out-Null
& $connectivitydiagnosis -verbose > ConnectivityDiagnosis.txt
& timeout 5 | Out-Null
& cd $currentDirectory
Log "Passed: RunConnectivityDiagnosis"
}
Catch
{
Log "Error running RunConnectivityDiagnosis" "Warning" $null "RunConnectivityDiagnosis" $_.Exception.HResult $_.Exception.Message
return
}
}
}
}
Catch
{
Log "Error running RunConnectivityDiagnosis" "Warning" $null "RunConnectivityDiagnosis" $_.Exception.HResult $_.Exception.Message
}
}
function SetAppraiserVerboseMode
{
Log "Start: SetAppraiserVerboseMode"
Try
{
$vAppraiserPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Appraiser"
Log "Enabling Appraiser logs for debugging by setting VerboseMode property to 1 at the registry key path: $vAppraiserPath"
if ((Get-ItemProperty -Path $vAppraiserPath -Name VerboseMode -ErrorAction SilentlyContinue) -eq $null)
{
Try
{
New-ItemProperty -Path $vAppraiserPath -Name VerboseMode -PropertyType DWord -Value 1 | Out-Null
}
Catch
{
Log "SetAppraiserVerboseMode failed to write the VerboseMode property at registry key $vAppraiserPath. This is not fatal, script will continue." "Warning" $null "SetAppraiserVerboseMode" $_.Exception.HResult $_.Exception.Message
return
}
}
else
{
Log "Appraiser verbose mode is already enabled"
}
Log "Enabling Appraiser logs for debugging by setting TestHooksEnabled property to 1 at the registry key path: $vAppraiserPath"
if ((Get-ItemProperty -Path $vAppraiserPath -Name TestHooksEnabled -ErrorAction SilentlyContinue) -eq $null)
{
Try
{
New-ItemProperty -Path $vAppraiserPath -Name TestHooksEnabled -PropertyType DWord -Value 1 | Out-Null
}
Catch
{
Log "SetAppraiserVerboseMode failed to write the TestHooksEnabled property at registry key $vAppraiserPath. This is not fatal, script will continue." "Warning" $null "SetAppraiserVerboseMode" $_.Exception.HResult $_.Exception.Message
return
}
}
else
{
Log "Appraiser TestHooksEnabled property is already set"
}
Log "Passed: SetAppraiserVerboseMode"
}
Catch
{
Log "SetAppraiserVerboseMode failed with unexpected exception. This is not fatal, script will continue." "Warning" $null "SetAppraiserVerboseMode" $_.Exception.HResult $_.Exception.Message
}
}
function DisableAppraiserVerboseMode
{
Log "Start: DisableAppraiserVerboseMode"
Try
{
$vAppraiserPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Appraiser"
if ((Get-ItemProperty -Path $vAppraiserPath -Name VerboseMode -ErrorAction SilentlyContinue) -ne $null)
{
Try
{
Remove-ItemProperty -Path $vAppraiserPath -Name VerboseMode
}
Catch
{
Log "DisableAppraiserVerboseMode failed deleting VerboseMode property at registry key path: $vAppraiserPath. This is not fatal, script will continue." "Warning" $null "DisableAppraiserVerboseMode" $_.Exception.HResult $_.Exception.Message
}
}
else
{
Log "Appraiser VerboseMode key already deleted"
}
Log "Passed: DisableAppraiserVerboseMode"
}
Catch
{
Log "DisableAppraiserVerboseMode failed with unexpected exception. This is not fatal, script will continue." "Warning" $null "DisableAppraiserVerboseMode" $_.Exception.HResult $_.Exception.Message
}
}
function SetRequestAllAppraiserVersions
{
Log "Start: SetRequestAllAppraiserVersions"
Try
{
$propertyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection"
$propertyGPOPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection"
if(Test-Path -Path $propertyPath)
{
if ((Get-ItemProperty -Path $propertyPath -Name RequestAllAppraiserVersions -ErrorAction SilentlyContinue) -eq $null)
{
Try
{
New-ItemProperty -Path $propertyPath -Name RequestAllAppraiserVersions -PropertyType DWord -Value 1 | Out-Null
}
Catch
{
Log "SetRequestAllAppraiserVersions failed setting RequestAllAppraiserVersions property at registry key path: $propertyPath" "Error" "20" "SetRequestAllAppraiserVersions" $_.Exception.HResult $_.Exception.Message
return
}
}
else
{
Try
{
Set-ItemProperty -Path $propertyPath -Name RequestAllAppraiserVersions -Value 1
}
Catch
{
Log "SetRequestAllAppraiserVersions failed setting RequestAllAppraiserVersions property at registry key path: $propertyPath" "Error" "20" "SetRequestAllAppraiserVersions" $_.Exception.HResult $_.Exception.Message
return
}
}
}
if(Test-Path -Path $propertyGPOPath)
{
if ((Get-ItemProperty -Path $propertyGPOPath -Name RequestAllAppraiserVersions -ErrorAction SilentlyContinue) -eq $null)
{
Try
{
New-ItemProperty -Path $propertyGPOPath -Name RequestAllAppraiserVersions -PropertyType DWord -Value 1 | Out-Null
}
Catch
{
Log "SetRequestAllAppraiserVersions failed setting RequestAllAppraiserVersions property at registry key path: $propertyGPOPath" "Error" "20" "SetRequestAllAppraiserVersions" $_.Exception.HResult $_.Exception.Message
return
}
}
else
{
Try
{
Set-ItemProperty -Path $propertyPath -Name RequestAllAppraiserVersions -Value 1
}
Catch
{
Log "SetRequestAllAppraiserVersions failed setting RequestAllAppraiserVersions property at registry key path: $propertyGPOPath" "Error" "20" "SetRequestAllAppraiserVersions" $_.Exception.HResult $_.Exception.Message
return
}
}
}
Log "Passed: SetRequestAllAppraiserVersions"
}
Catch
{
Log "SetRequestAllAppraiserVersions failed with unexpected exception." "Error" "21" "SetRequestAllAppraiserVersions" $_.Exception.HResult $_.Exception.Message
}
}
function RunAppraiser
{
Try
{
Log "Start: RunAppraiser"
Log "Attempting to run inventory...This may take a few minutes to complete, please do not cancel the script."
do
{
CompatTelRunner.exe -m:appraiser.dll -f:DoScheduledTelemetryRun ent | out-null
$appraiserLastExitCode = $LASTEXITCODE
$appraiserLastExitCodeHex = "{0:X}" -f $appraiserLastExitCode
if($appraiserLastExitCode -eq 0x80070021)
{
Log "RunAppraiser needs to run CompatTelRunner.exe, but it is already running. Waiting for 60 seconds before retry."
Start-Sleep -Seconds 60
}
else
{
break
}
$NoOfAppraiserRetries = $NoOfAppraiserRetries - 1
}While($NoOfAppraiserRetries -gt 0)
if ($appraiserLastExitCode -ne 0x0)
{
if ($appraiserLastExitCode -lt 0x0)
{
Log "RunAppraiser failed. CompatTelRunner.exe exited with last error code: 0x$appraiserLastExitCodeHex." "Error" "33" "RunAppraiser" "0x$appraiserLastExitCodeHex" "CompatTelRunner.exe returned with an error code."
}
else
{
Log "RunAppraiser succeeded with a return code: 0x$appraiserLastExitCodeHex."
}
}
else
{
Log "Passed: RunAppraiser"
}
}
Catch
{
Log "RunAppraiser failed with unexpected exception." "Error" "22" "RunAppraiser" $_.Exception.HResult $_.Exception.Message
}
}
function RunCensus
{
Log "Start: RunCensus"
Try
{
$censusRunRegKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Census"
if($(Test-Path $censusRunRegKey) -eq $false)
{
New-Item -Path $censusRunRegKey -ItemType Key | Out-Null
}
# Turn Census FullSync mode on
Log "Setting property: FullSync to value 1 at registry key path $censusRunRegKey to turn on Census FullSync mode"
if ((Get-ItemProperty -Path $censusRunRegKey -Name FullSync -ErrorAction SilentlyContinue) -eq $null)
{
New-ItemProperty -Path $censusRunRegKey -Name FullSync -PropertyType DWord -Value 1 | Out-Null
}
else
{
Set-ItemProperty -Path $censusRunRegKey -Name FullSync -Value 1
}
# Run Census and validate the run
# Census invocation commands are different for Windows 10 and Downlevel
[int] $runCounterBefore = (Get-ItemProperty -Path $censusRunRegKey).RunCounter
if($runCounterBefore -eq $null)
{
New-ItemProperty -Path $censusRunRegKey -Name RunCounter -PropertyType DWord -Value 0 | Out-Null
}
if($global:operatingSystemName.ToLower().Contains("windows 10"))
{
$censusExe = "$global:windir\system32\devicecensus.exe"
if(Test-Path -Path $censusExe)
{
Log "Running $censusExe"
& $censusExe | Out-Null
}
else
{
Log "$censusExe path not found" "Error" "52" "RunCensus"
return
}
}
else
{
CompatTelRunner.exe -m:generaltel.dll -f:DoCensusRun | Out-Null
}
[int] $runCounterAfter = (Get-ItemProperty -Path $censusRunRegKey).RunCounter
$returnCode = (Get-ItemProperty -Path $censusRunRegKey).ReturnCode
$startTime = Get-Date (Get-ItemProperty -Path $censusRunRegKey).StartTime
$endTime = Get-Date (Get-ItemProperty -Path $censusRunRegKey).EndTime
if($returnCode -eq 0)
{
if($runCounterAfter -gt $runCounterBefore -and $endTime -gt $startTime)
{
Log "Passed: RunCensus"
}
else
{
Log "Census did not run correctly. Registray data at $censusRunRegKey are: RunCounter Before trying to run Census:$runCounterBefore, RunCounter after trying to run Census:$runCounterAfter, ReturnCode:$returnCode, UTC StartTime:$startTime, UTC EndTime:$endTime" "Warning" $null "RunCensus"
}
}
else
{
Log "Census returned a non zero ReturnCode:$returnCode" "Warning" $null "RunCensus"
}
# Turn Census FullSync mode off
Log "Resetting property: FullSync to value 0 at registry key path $censusRunRegKey to turn off Census FullSync mode"
Set-ItemProperty -Path $censusRunRegKey -Name FullSync -Value 0
}
Catch
{
Log "RunCensus failed with unexpected exception" "Error" "51" "RunCensus" $_.Exception.HResult $_.Exception.Message
}
}
function CollectM365AHandlerLog
{
Log "Start: CollectM365AHandlerLog"
Try
{
$propertyPath = "HKLM:\SOFTWARE\Microsoft\CCM\Logging\@Global"
if(Test-Path -Path $propertyPath)
{
if ((Get-ItemProperty -Path $propertyPath -Name LogDirectory -ErrorAction SilentlyContinue) -eq $null)
{
Log "Could not find registry key LogDirectory at path HKLM:\SOFTWARE\Microsoft\CCM\Logging\@Global"
}
else
{
Try
{
$logDirectoryKeyM365 = Get-ItemProperty -Path $propertyPath -Name LogDirectory
$logDirectoryM365 = $logDirectoryKeyM365.LogDirectory
Copy-Item "$logDirectoryM365\M365AHandler.log" -Destination $global:logFolder | Out-Null
Log "Passed: CollectM365AHandlerLog"
}
Catch
{
Log "Error getting logs at registry key LogDirectory at path HKLM:\SOFTWARE\Microsoft\CCM\Logging\@Global" "Warning" $null "CollectM365AHandlerLog" $_.Exception.HResult $_.Exception.Message
return
}
}
}
}
Catch
{
Log "Error getting logs at registry key LogDirectory at path HKLM:\SOFTWARE\Microsoft\CCM\Logging\@Global" "Warning" $null "CollectM365AHandlerLog" $_.Exception.HResult $_.Exception.Message
}
}
function Log($logMessage, $logLevel, $errorCode, $operation, $exceptionHresult, $exceptionMessage)
{
$global:logDate = Get-Date -Format s
$global:utcDate = ((Get-Date).ToUniversalTime()).ToString("yyyy-MM-ddTHH:mm:ssZ")
$logMessageForAppInsights = $logMessage
if(($logLevel -eq $null) -or ($logLevel -eq [string]::Empty))
{
$logLevel = "Info"
}
if($logLevel -eq "Error")
{
# check and update the errorCode (the script will exit with the first errorCode)
if(($errorCode -ne $null) -and ($errorCode -ne [string]::Empty))
{
if(($global:errorCode -eq $null) -or ($global:errorCode -eq [string]::Empty))
{
$global:errorCode = $errorCode
}
$logMessage = "ErrorCode " + $errorCode + " : " + $logMessage
}
if($exceptionHresult -ne $null)
{
$logMessage = $logMessage + " HResult: " + $exceptionHresult
}
if($exceptionMessage -ne $null)
{
$logMessage = $logMessage + " ExceptionMessage: " + $exceptionMessage
}
$global:errorCount++
}
elseif($logLevel -eq "Exception")
{
if($exceptionHresult -ne $null)
{
$logMessage = $logMessage + " HResult: " + $exceptionHresult
}
if($exceptionMessage -ne $null)
{
$logMessage = $logMessage + " ExceptionMessage: " + $exceptionMessage
}
}
elseif($logLevel -eq "Warning")
{
if($exceptionHresult -ne $null)
{
$logMessage = $logMessage + " HResult: " + $exceptionHresult
}
if($exceptionMessage -ne $null)
{
$logMessage = $logMessage + " ExceptionMessage: " + $exceptionMessage
}
}
if ($LogMode -eq 0)
{
Try
{
WriteLogToConsole $logLevel $logMessage
}
Catch
{
# Error when logging to console
$exceptionDetails = "Exception: " + $_.Exception.Message + "HResult: " + $_.Exception.HResult
$message = "Error when logging to consloe."
Write-Error "$message`n$exceptionDetails"
SendEventToAppInsights "logging" $message "Failure" $global:utcDate "2" $_.Exception.HResult $_.Exception.Message
[System.Environment]::Exit(2)
}
}
elseif ($LogMode -eq 1)
{
Try
{
WriteLogToConsole $logLevel $logMessage
Add-Content $global:logFile "$global:logDate : $logLevel : $logMessage"
}
Catch
{
# Error when logging to console and file
$exceptionDetails = "Exception: " + $_.Exception.Message + "HResult: " + $_.Exception.HResult
$message = "Error when logging to consloe and file."
Write-Error "$message`n$exceptionDetails"
SendEventToAppInsights "logging" $message "Failure" $global:utcDate "3" $_.Exception.HResult $_.Exception.Message
[System.Environment]::Exit(3)
}
}
elseif ($LogMode -eq 2)
{
Try
{
Add-Content $global:logFile "$global:logDate : $logLevel : $logMessage"
}
Catch
{
# Error when logging to file
$exceptionDetails = "Exception: " + $_.Exception.Message + "HResult: " + $_.Exception.HResult
$message = "Error when logging to file."
Write-Error "$message`n$exceptionDetails"
SendEventToAppInsights "logging" $message "Failure" $global:utcDate "4" $_.Exception.HResult $_.Exception.Message
[System.Environment]::Exit(4)
}
}
else
{
Try
{
WriteLogToConsole $logLevel $logMessage
Add-Content $global:logFile "$global:logDate : $logLevel : $logMessage"
}
Catch
{
# Error when logging to console and file
$exceptionDetails = "Exception: " + $_.Exception.Message + "HResult: " + $_.Exception.HResult
$message = "Error when logging to consloe and file."
Write-Error "$message`n$exceptionDetails"
SendEventToAppInsights "logging" $message "Failure" $global:utcDate "5" $_.Exception.HResult $_.Exception.Message
[System.Environment]::Exit(5)
}
}
}
function WriteLogToConsole($logLevel, $logMessage)
{
switch ($logLevel)
{
"Error"
{
Write-Error "$global:logDate : $logMessage"; Break
}
"Exception"
{
Write-Error "$global:logDate : $logMessage"; Break
}
"Warning"
{
Write-Warning "$global:logDate : $logMessage"; Break
}
default
{
Write-Host "$global:logDate : $logMessage"; Break
}
}
}
# Calling the main function
&$main
# SIG # Begin signature block
# MIIoAgYJKoZIhvcNAQcCoIIn8zCCJ+8CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBIE+lkqmSnrxsW
# 2upP9cl3n3z3Xa6n76xQ00V6M5n8n6CCDYUwggYDMIID66ADAgECAhMzAAADri01
# UchTj1UdAAAAAAOuMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjMxMTE2MTkwODU5WhcNMjQxMTE0MTkwODU5WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQD0IPymNjfDEKg+YyE6SjDvJwKW1+pieqTjAY0CnOHZ1Nj5irGjNZPMlQ4HfxXG
# yAVCZcEWE4x2sZgam872R1s0+TAelOtbqFmoW4suJHAYoTHhkznNVKpscm5fZ899
# QnReZv5WtWwbD8HAFXbPPStW2JKCqPcZ54Y6wbuWV9bKtKPImqbkMcTejTgEAj82
# 6GQc6/Th66Koka8cUIvz59e/IP04DGrh9wkq2jIFvQ8EDegw1B4KyJTIs76+hmpV
# M5SwBZjRs3liOQrierkNVo11WuujB3kBf2CbPoP9MlOyyezqkMIbTRj4OHeKlamd
# WaSFhwHLJRIQpfc8sLwOSIBBAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUhx/vdKmXhwc4WiWXbsf0I53h8T8w
# VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
# dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzUwMTgzNjAfBgNVHSMEGDAW
# gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw
# MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx
# XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB
# AGrJYDUS7s8o0yNprGXRXuAnRcHKxSjFmW4wclcUTYsQZkhnbMwthWM6cAYb/h2W
# 5GNKtlmj/y/CThe3y/o0EH2h+jwfU/9eJ0fK1ZO/2WD0xi777qU+a7l8KjMPdwjY
# 0tk9bYEGEZfYPRHy1AGPQVuZlG4i5ymJDsMrcIcqV8pxzsw/yk/O4y/nlOjHz4oV
# APU0br5t9tgD8E08GSDi3I6H57Ftod9w26h0MlQiOr10Xqhr5iPLS7SlQwj8HW37
# ybqsmjQpKhmWul6xiXSNGGm36GarHy4Q1egYlxhlUnk3ZKSr3QtWIo1GGL03hT57
# xzjL25fKiZQX/q+II8nuG5M0Qmjvl6Egltr4hZ3e3FQRzRHfLoNPq3ELpxbWdH8t
# Nuj0j/x9Crnfwbki8n57mJKI5JVWRWTSLmbTcDDLkTZlJLg9V1BIJwXGY3i2kR9i
# 5HsADL8YlW0gMWVSlKB1eiSlK6LmFi0rVH16dde+j5T/EaQtFz6qngN7d1lvO7uk
# 6rtX+MLKG4LDRsQgBTi6sIYiKntMjoYFHMPvI/OMUip5ljtLitVbkFGfagSqmbxK
# 7rJMhC8wiTzHanBg1Rrbff1niBbnFbbV4UDmYumjs1FIpFCazk6AADXxoKCo5TsO
# zSHqr9gHgGYQC2hMyX9MGLIpowYCURx3L7kUiGbOiMwaMIIHejCCBWKgAwIBAgIK
# 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/Xmfwb1tbWrJUnMTDXpQzTGCGdMwghnPAgEBMIGVMH4x
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAOuLTVRyFOPVR0AAAAA
# A64wDQYJYIZIAWUDBAIBBQCggd4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIMK3
# faqKQD4G7qVdjnlYCcOT7ptJNIWBvSzhUCNnblNkMHIGCisGAQQBgjcCAQwxZDBi
# oESAQgBEAGUAcwBrAHQAbwBwAEEAbgBhAGwAeQB0AGkAYwBzAEwAbwBnAHMAQwBv
# AGwAbABlAGMAdABvAHIALgBwAHMAMaEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20wDQYJKoZIhvcNAQEBBQAEggEAzypMT9O9UC3+hJ4aqyj63LA4eG1yjOHc/Y2J
# OtqortoqXycVSI8rjfLYH9xu84U77YschS9f5nPEGfXhgf2dcMNbpva0ANbOMytn
# rMKEhWgz8WZeWhiKOskP6rRil365jjrEzaw3xXQIsvoaEys5+WzKd/pVMTX3HMms
# vDemXn/JPnXLQGPovGw8md8AtyM+Zo53pvVpu6ZJf7czXQpRXeLz12QIE9m+uY78
# 1RfJFg2R2kn1zkAedPPsVL5szITAY8t8oUjZyEd71xTw22rkD6ak0rgcgPiBNTC9
# hINCJHV0pdcQs3wt4X02Mc1+X7au7GDhBuQy3HLAPNFzrOjeDqGCFy0wghcpBgor
# BgEEAYI3AwMBMYIXGTCCFxUGCSqGSIb3DQEHAqCCFwYwghcCAgEDMQ8wDQYJYIZI
# AWUDBAIBBQAwggFZBgsqhkiG9w0BCRABBKCCAUgEggFEMIIBQAIBAQYKKwYBBAGE
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCChl/7qbI6omZ+csG323sGjozGE77HHxLRe
# Xw+WY9dnOAIGZjOhcVduGBMyMDI0MDUwMjIwNTU1Mi40NTVaMASAAgH0oIHYpIHV
# MIHSMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQL
# EyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsT
# HVRoYWxlcyBUU1MgRVNOOjJBRDQtNEI5Mi1GQTAxMSUwIwYDVQQDExxNaWNyb3Nv
# ZnQgVGltZS1TdGFtcCBTZXJ2aWNloIIRfDCCBycwggUPoAMCAQICEzMAAAHenkie
# lp8oRD0AAQAAAd4wDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNV
# BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv
# c29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAg
# UENBIDIwMTAwHhcNMjMxMDEyMTkwNzEyWhcNMjUwMTEwMTkwNzEyWjCB0jELMAkG
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9z
# b2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMg
# VFNTIEVTTjoyQUQ0LTRCOTItRkEwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt
# U3RhbXAgU2VydmljZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALSB
# 9ByF9UIDhA6xFrOniw/xsDl8sSi9rOCOXSSO4VMQjnNGAo5VHx0iijMEMH9LY2SU
# IBkVQS0Ml6kR+TagkUPbaEpwjhQ1mprhRgJT/jlSnic42VDAo0en4JI6xnXoAoWo
# KySY8/ROIKdpphgI7OJb4XHk1P3sX2pNZ32LDY1ktchK1/hWyPlblaXAHRu0E3yn
# vwrS8/bcorANO6DjuysyS9zUmr+w3H3AEvSgs2ReuLj2pkBcfW1UPCFudLd7IPZ2
# RC4odQcEPnY12jypYPnS6yZAs0pLpq0KRFUyB1x6x6OU73sudiHON16mE0l6LLT9
# OmGo0S94Bxg3N/3aE6fUbnVoemVc7FkFLum8KkZcbQ7cOHSAWGJxdCvo5OtUtRdS
# qf85FklCXIIkg4sm7nM9TktUVfO0kp6kx7mysgD0Qrxx6/5oaqnwOTWLNzK+BCi1
# G7nUD1pteuXvQp8fE1KpTjnG/1OJeehwKNNPjGt98V0BmogZTe3SxBkOeOQyLA++
# 5Hyg/L68pe+DrZoZPXJaGU/iBiFmL+ul/Oi3d83zLAHlHQmH/VGNBfRwP+ixvqhy
# k/EebwuXVJY+rTyfbRfuh9n0AaMhhNxxg6tGKyZS4EAEiDxrF9mAZEy8e8rf6dlK
# IX5d3aQLo9fDda1ZTOw+XAcAvj2/N3DLVGZlHnHlAgMBAAGjggFJMIIBRTAdBgNV
# HQ4EFgQUazAmbxseaapgdxzK8Os+naPQEsgwHwYDVR0jBBgwFoAUn6cVXQBeYl2D
# 9OXSZacbUzUZ6XIwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDovL3d3dy5taWNyb3Nv
# ZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUy
# MDIwMTAoMSkuY3JsMGwGCCsGAQUFBwEBBGAwXjBcBggrBgEFBQcwAoZQaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBUaW1l
# LVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcnQwDAYDVR0TAQH/BAIwADAWBgNVHSUB
# Af8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQELBQAD
# ggIBAOKUwHsXDacGOvUIgs5HDgPs0LZ1qyHS6C6wfKlLaD36tZfbWt1x+GMiazSu
# y+GsxiVHzkhMW+FqK8gruLQWN/sOCX+fGUgT9LT21cRIpcZj4/ZFIvwtkBcsCz1X
# EUsXYOSJUPitY7E8bbldmmhYZ29p+XQpIcsG/q+YjkqBW9mw0ru1MfxMTQs9MTDi
# D28gAVGrPA3NykiSChvdqS7VX+/LcEz9Ubzto/w28WA8HOCHqBTbDRHmiP7MIj+S
# QmI9VIayYsIGRjvelmNa0OvbU9CJSz/NfMEgf2NHMZUYW8KqWEjIjPfHIKxWlNMY
# huWfWRSHZCKyIANA0aJL4soHQtzzZ2MnNfjYY851wHYjGgwUj/hlLRgQO5S30Zx7
# 8GqBKfylp25aOWJ/qPhC+DXM2gXajIXbl+jpGcVANwtFFujCJRdZbeH1R+Q41Fjg
# Bg4m3OTFDGot5DSuVkQgjku7pOVPtldE46QlDg/2WhPpTQxXH64sP1GfkAwUtt6r
# rZM/PCwRG6girYmnTRLLsicBhoYLh+EEFjVviXAGTk6pnu8jx/4WPWu0jsz7yFzg
# 82/FMqCk9wK3LvyLAyDHN+FxbHAxtgwad7oLQPM0WGERdB1umPCIiYsSf/j79EqH
# doNwQYROVm+ZX10RX3n6bRmAnskeNhi0wnVaeVogLMdGD+nqMIIHcTCCBVmgAwIB
# AgITMwAAABXF52ueAptJmQAAAAAAFTANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UE
# BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
# BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0
# IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMjEwOTMwMTgyMjI1
# WhcNMzAwOTMwMTgzMjI1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
# cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCC
# AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOThpkzntHIhC3miy9ckeb0O
# 1YLT/e6cBwfSqWxOdcjKNVf2AX9sSuDivbk+F2Az/1xPx2b3lVNxWuJ+Slr+uDZn
# hUYjDLWNE893MsAQGOhgfWpSg0S3po5GawcU88V29YZQ3MFEyHFcUTE3oAo4bo3t
# 1w/YJlN8OWECesSq/XJprx2rrPY2vjUmZNqYO7oaezOtgFt+jBAcnVL+tuhiJdxq
# D89d9P6OU8/W7IVWTe/dvI2k45GPsjksUZzpcGkNyjYtcI4xyDUoveO0hyTD4MmP
# frVUj9z6BVWYbWg7mka97aSueik3rMvrg0XnRm7KMtXAhjBcTyziYrLNueKNiOSW
# rAFKu75xqRdbZ2De+JKRHh09/SDPc31BmkZ1zcRfNN0Sidb9pSB9fvzZnkXftnIv
# 231fgLrbqn427DZM9ituqBJR6L8FA6PRc6ZNN3SUHDSCD/AQ8rdHGO2n6Jl8P0zb
# r17C89XYcz1DTsEzOUyOArxCaC4Q6oRRRuLRvWoYWmEBc8pnol7XKHYC4jMYcten
# IPDC+hIK12NvDMk2ZItboKaDIV1fMHSRlJTYuVD5C4lh8zYGNRiER9vcG9H9stQc
# xWv2XFJRXRLbJbqvUAV6bMURHXLvjflSxIUXk8A8FdsaN8cIFRg/eKtFtvUeh17a
# j54WcmnGrnu3tz5q4i6tAgMBAAGjggHdMIIB2TASBgkrBgEEAYI3FQEEBQIDAQAB
# MCMGCSsGAQQBgjcVAgQWBBQqp1L+ZMSavoKRPEY1Kc8Q/y8E7jAdBgNVHQ4EFgQU
# n6cVXQBeYl2D9OXSZacbUzUZ6XIwXAYDVR0gBFUwUzBRBgwrBgEEAYI3TIN9AQEw
# QTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9E
# b2NzL1JlcG9zaXRvcnkuaHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsGAQQB
# gjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/
# MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJ
# oEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01p
# Y1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYB
# BQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9v
# Q2VyQXV0XzIwMTAtMDYtMjMuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCdVX38Kq3h
# LB9nATEkW+Geckv8qW/qXBS2Pk5HZHixBpOXPTEztTnXwnE2P9pkbHzQdTltuw8x
# 5MKP+2zRoZQYIu7pZmc6U03dmLq2HnjYNi6cqYJWAAOwBb6J6Gngugnue99qb74p
# y27YP0h1AdkY3m2CDPVtI1TkeFN1JFe53Z/zjj3G82jfZfakVqr3lbYoVSfQJL1A
# oL8ZthISEV09J+BAljis9/kpicO8F7BUhUKz/AyeixmJ5/ALaoHCgRlCGVJ1ijbC
# HcNhcy4sa3tuPywJeBTpkbKpW99Jo3QMvOyRgNI95ko+ZjtPu4b6MhrZlvSP9pEB
# 9s7GdP32THJvEKt1MMU0sHrYUP4KWN1APMdUbZ1jdEgssU5HLcEUBHG/ZPkkvnNt
# yo4JvbMBV0lUZNlz138eW0QBjloZkWsNn6Qo3GcZKCS6OEuabvshVGtqRRFHqfG3
# rsjoiV5PndLQTHa1V1QJsWkBRH58oWFsc/4Ku+xBZj1p/cvBQUl+fpO+y/g75LcV
# v7TOPqUxUYS8vwLBgqJ7Fx0ViY1w/ue10CgaiQuPNtq6TPmb/wrpNPgkNWcr4A24
# 5oyZ1uEi6vAnQj0llOZ0dFtq0Z4+7X6gMTN9vMvpe784cETRkPHIqzqKOghif9lw
# Y1NNje6CbaUFEMFxBmoQtB1VM1izoXBm8qGCAtgwggJBAgEBMIIBAKGB2KSB1TCB
# 0jELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
# ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMk
# TWljcm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1U
# aGFsZXMgVFNTIEVTTjoyQUQ0LTRCOTItRkEwMTElMCMGA1UEAxMcTWljcm9zb2Z0
# IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIaAxUAaKBSisy4y86pl8Xy
# 22CJZExE2vOggYMwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
# cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAN
# BgkqhkiG9w0BAQUFAAIFAOneH+MwIhgPMjAyNDA1MDIyMjIxMjNaGA8yMDI0MDUw
# MzIyMjEyM1oweDA+BgorBgEEAYRZCgQBMTAwLjAKAgUA6d4f4wIBADALAgEAAgMB
# HHgCAf8wBwIBAAICE/YwCgIFAOnfcWMCAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYK
# KwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQUF
# AAOBgQChqUVzyjSvZsd79JUJddw2P0vHrT2Azx/D5Nh33MUFAU0AUMRWx6pqbyHD
# 7Gf0OYljwMdX8TLfsorsODpvMVFyLQQhANBQMzScn6JVYUyJWGlXEFf3zEVmoXzf
# Y3wtQnrDdUVaeg9NoY9ttFqPtJamKUBRZnfPO8xtfvRBgfm8rjGCBA0wggQJAgEB
# MIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV
# BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB3p5InpafKEQ9
# AAEAAAHeMA0GCWCGSAFlAwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcN
# AQkQAQQwLwYJKoZIhvcNAQkEMSIEIEOH7oT0feHVIo2VpC5Q0ldGCYZmSyaDyjpn
# TKCg8LKyMIH6BgsqhkiG9w0BCRACLzGB6jCB5zCB5DCBvQQgjj4jnw3BXhAQSQJ/
# 5gtzIK0+cP1Ns/NS2A+OB3N+HXswgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEG
# A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj
# cm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFt
# cCBQQ0EgMjAxMAITMwAAAd6eSJ6WnyhEPQABAAAB3jAiBCCqlMZRRFgGINs4+HhX
# dMQi8+rUCVp+3udHqe8NfDTWAjANBgkqhkiG9w0BAQsFAASCAgBGwl1+0uDZseka
# q/ceaXwJ8/fp/4Er6cxJrm7/+0ENEAkRzho/tajjVen5+RftqjYY7tdjWw01s1xw
# MEOik/nqqzCtEBqMZrGS1p67cnJBpUVpONW+inXHh7CPnOrZTQ/4olXp1UVWFczR
# rs3cFyOgrtRTL1a7/EprXVFjRWXRY+dHGho/5+C46g5rp4HR2h8ucIABrbrQ880H
# PC73+Nr7g30XgKkRkD2eUH/McZICsfi+7ONLvDMJQyUsZML6MwQtSm2jjWNe4gIw
# 2xy1RgfaJV5w0ve9hx1MU+WcjxX7Z3M1IaG+XGxf+4FpNBczzd0BY0dY5iOSCuqp
# aEDuu3DIZ9bLyN8VoFaI98plJkbba9J/nRnSRSTxbg6UoUQTiMBRLhfrEVbfGVw4
# u1ABt1mFaBX70UXhLZYYQxHG1GQnm6MSLklihtZu57yxY/VhyfH8Z3hRfAfxbyen
# HpCS5AmKJpHiRSeTC2bDlfaWGOFXwcAufxXvgu+EWNgukuXKLwtT8blZv/VxuXUs
# eq+YToI4oHcU9+hlFQ3+9pVH+xlppa8HJcIeqhY0WA9wMvIh4eIa97iAusIsiRh4
# xeeqxdppBFpIzQhRkK14sLggRZeJs7ayVQWTRbFyA5ZAxa9H+eJ3UA7WknMwh7g1
# vEFP+/1yvj66y7dD3Mv1nYRkpHizHQ==
# SIG # End signature block