Tools/SmartM365-DeviceRebootManager-GalleryUpdate.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS Updates and deploys SmartM365 Device Reboot Manager from PowerShell Gallery. .DESCRIPTION This helper is packaged with the PowerShell Gallery module and copied to the stable ProgramData installation. It updates the module, validates the pinned WorkplaceCloudHub signer, deploys the runtime, preserves local configuration, and optionally registers the automatic update task. #> [CmdletBinding()] param( [string]$ModuleName = 'SmartM365.DeviceRebootManager', [string]$InstallPath = "$env:ProgramData\SmartM365\DeviceRebootManager", [string]$ConfigSourcePath = '', [switch]$ForceConfig, [switch]$SkipScheduledTask, [string]$TaskPath = '\SmartM365\', [string]$TaskName = 'Device Reboot Manager', [ValidateRange(15, 10080)] [int]$RepeatIntervalMinutes = 240, [bool]$EnableAutomaticUpdate = $false, [string]$UpdateTaskPath = '\SmartM365\', [string]$UpdateTaskName = 'Device Reboot Manager Update', [ValidateRange(1, 168)] [int]$UpdateIntervalHours = 24, [bool]$IncludePrerelease = $false, [string]$ExpectedSignerThumbprint = 'D70ECB7B00377EBFB76B304C08DFC6620584E114', [switch]$SkipPackageUpdate ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' function Test-IsAdministrator { $identity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object Security.Principal.WindowsPrincipal($identity) return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } function Write-UpdateLog { param([string]$Message, [ValidateSet('INFO', 'WARN', 'ERROR')][string]$Level = 'INFO') $line = '[{0}] [{1}] {2}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'),$Level,$Message Write-Output $line try { $logRoot = Join-Path -Path $InstallPath -ChildPath 'Logs' if (-not (Test-Path -LiteralPath $logRoot -PathType Container)) { New-Item -ItemType Directory -Path $logRoot -Force | Out-Null } Add-Content -LiteralPath (Join-Path $logRoot 'PowerShellGalleryUpdate.log') -Value $line -Encoding UTF8 } catch { Write-Warning ("Unable to write update log. {0}" -f $_.Exception.Message) } } function Get-NormalizedThumbprint { param([string]$Value) return ([string]$Value).Replace(' ', '').ToUpperInvariant() } function Get-LatestModuleInfo { param([Parameter(Mandatory = $true)][string]$Name) $module = Get-Module -ListAvailable -Name $Name | Sort-Object Version -Descending | Select-Object -First 1 if (-not $module) { throw "Installed module not found: $Name" } return $module } function Invoke-GalleryPackageUpdate { param([Parameter(Mandatory = $true)][string]$Name) [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 $powerShellGetInstall = $null if (Get-Command Get-InstalledModule -ErrorAction SilentlyContinue) { $powerShellGetInstall = Get-InstalledModule -Name $Name -ErrorAction SilentlyContinue } if ($powerShellGetInstall -and (Get-Command Update-Module -ErrorAction SilentlyContinue)) { Write-UpdateLog "Updating $Name with PowerShellGet." $updateModuleParameters = @{ Name = $Name Force = $true ErrorAction = 'Stop' } if ($IncludePrerelease) { $updateModuleParameters.AllowPrerelease = $true } Update-Module @updateModuleParameters return } if (Get-Command Update-PSResource -ErrorAction SilentlyContinue) { Write-UpdateLog "Updating $Name with PSResourceGet." $updateResourceParameters = @{ Name = $Name Repository = 'PSGallery' Scope = 'AllUsers' TrustRepository = $true Quiet = $true ErrorAction = 'Stop' } if ($IncludePrerelease) { $updateResourceParameters.Prerelease = $true } Update-PSResource @updateResourceParameters return } throw 'No supported PowerShell Gallery update command is available.' } function Assert-ModuleSignature { param( [Parameter(Mandatory = $true)][string]$ModuleBase, [Parameter(Mandatory = $true)][string]$Thumbprint ) $expected = Get-NormalizedThumbprint $Thumbprint $powerShellFiles = @(Get-ChildItem -LiteralPath $ModuleBase -Recurse -File | Where-Object { $_.Extension -in @('.ps1', '.psm1', '.psd1') }) if ($powerShellFiles.Count -eq 0) { throw "No PowerShell files found in package: $ModuleBase" } foreach ($file in $powerShellFiles) { $signature = Get-AuthenticodeSignature -LiteralPath $file.FullName $actual = if ($signature.SignerCertificate) { Get-NormalizedThumbprint $signature.SignerCertificate.Thumbprint } else { '' } if ($signature.Status -ne 'Valid' -or $actual -ne $expected) { throw ("Package signature validation failed: file={0}; status={1}; signer={2}" -f $file.FullName,$signature.Status,$actual) } } } function Register-GalleryUpdateTask { param( [Parameter(Mandatory = $true)][string]$ScriptPath, [Parameter(Mandatory = $true)][string]$ScheduledTaskPath, [Parameter(Mandatory = $true)][string]$ScheduledTaskName, [Parameter(Mandatory = $true)][int]$IntervalHours ) $powerShellPath = "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" if (-not (Test-Path -LiteralPath $powerShellPath -PathType Leaf)) { $powerShellPath = 'powershell.exe' } $arguments = @( '-NoProfile' '-ExecutionPolicy' 'Bypass' '-File' ('"{0}"' -f $ScriptPath) '-ModuleName' ('"{0}"' -f $ModuleName) '-InstallPath' ('"{0}"' -f $InstallPath) '-TaskPath' ('"{0}"' -f $TaskPath) '-TaskName' ('"{0}"' -f $TaskName) '-RepeatIntervalMinutes' $RepeatIntervalMinutes '-EnableAutomaticUpdate:$true' '-UpdateTaskPath' ('"{0}"' -f $ScheduledTaskPath) '-UpdateTaskName' ('"{0}"' -f $ScheduledTaskName) '-UpdateIntervalHours' $IntervalHours ('-IncludePrerelease:${0}' -f $IncludePrerelease.ToString().ToLowerInvariant()) '-ExpectedSignerThumbprint' ('"{0}"' -f $ExpectedSignerThumbprint) ) $action = New-ScheduledTaskAction -Execute $powerShellPath -Argument ($arguments -join ' ') $now = Get-Date $firstRun = $now.Date.AddHours(3) if ($firstRun -le $now) { $firstRun = $firstRun.AddDays(1) } $trigger = New-ScheduledTaskTrigger ` -Once ` -At $firstRun ` -RepetitionInterval (New-TimeSpan -Hours $IntervalHours) ` -RepetitionDuration (New-TimeSpan -Days 3650) $principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest $settings = New-ScheduledTaskSettingsSet ` -AllowStartIfOnBatteries ` -DontStopIfGoingOnBatteries ` -StartWhenAvailable ` -MultipleInstances IgnoreNew ` -ExecutionTimeLimit (New-TimeSpan -Hours 1) Register-ScheduledTask ` -TaskPath $ScheduledTaskPath ` -TaskName $ScheduledTaskName ` -Action $action ` -Trigger $trigger ` -Principal $principal ` -Settings $settings ` -Description 'Updates SmartM365 Device Reboot Manager from PowerShell Gallery.' ` -Force | Out-Null } if (-not (Test-IsAdministrator)) { throw 'Device Reboot Manager Gallery deployment must run elevated.' } try { Write-UpdateLog "Starting Device Reboot Manager Gallery deployment. Module=$ModuleName; SkipPackageUpdate=$SkipPackageUpdate" if (-not $SkipPackageUpdate) { Invoke-GalleryPackageUpdate -Name $ModuleName } $moduleInfo = Get-LatestModuleInfo -Name $ModuleName $moduleBase = $moduleInfo.ModuleBase Assert-ModuleSignature -ModuleBase $moduleBase -Thumbprint $ExpectedSignerThumbprint $latestToolPath = Join-Path -Path $moduleBase -ChildPath 'Tools\SmartM365-DeviceRebootManager-GalleryUpdate.ps1' if (-not $SkipPackageUpdate -and $latestToolPath -ne $PSCommandPath) { & $latestToolPath ` -ModuleName $ModuleName ` -InstallPath $InstallPath ` -ConfigSourcePath $ConfigSourcePath ` -ForceConfig:$ForceConfig ` -SkipScheduledTask:$SkipScheduledTask ` -TaskPath $TaskPath ` -TaskName $TaskName ` -RepeatIntervalMinutes $RepeatIntervalMinutes ` -EnableAutomaticUpdate:$EnableAutomaticUpdate ` -UpdateTaskPath $UpdateTaskPath ` -UpdateTaskName $UpdateTaskName ` -UpdateIntervalHours $UpdateIntervalHours ` -IncludePrerelease:$IncludePrerelease ` -ExpectedSignerThumbprint $ExpectedSignerThumbprint ` -SkipPackageUpdate return } $installerPath = Join-Path -Path $moduleBase -ChildPath 'Runtime\Deploy\SmartM365-DeviceRebootManager-Install.ps1' if (-not (Test-Path -LiteralPath $installerPath -PathType Leaf)) { throw "Runtime installer not found in package: $installerPath" } $installParameters = @{ InstallPath = $InstallPath ConfigSourcePath = $ConfigSourcePath ForceConfig = $ForceConfig SkipScheduledTask = $SkipScheduledTask TaskPath = $TaskPath TaskName = $TaskName RepeatIntervalMinutes = $RepeatIntervalMinutes PackageSource = 'PowerShellGallery' UpdateTaskPath = $UpdateTaskPath UpdateTaskName = $UpdateTaskName } & $installerPath @installParameters $installedUpdateScript = Join-Path -Path $InstallPath -ChildPath 'SmartM365-DeviceRebootManager-GalleryUpdate.ps1' Copy-Item -LiteralPath $latestToolPath -Destination $installedUpdateScript -Force if ($EnableAutomaticUpdate) { Register-GalleryUpdateTask ` -ScriptPath $installedUpdateScript ` -ScheduledTaskPath $UpdateTaskPath ` -ScheduledTaskName $UpdateTaskName ` -IntervalHours $UpdateIntervalHours Write-UpdateLog ("Automatic update task registered: {0}{1}" -f $UpdateTaskPath,$UpdateTaskName) } else { $existingUpdateTask = Get-ScheduledTask -TaskPath $UpdateTaskPath -TaskName $UpdateTaskName -ErrorAction SilentlyContinue if ($existingUpdateTask) { Unregister-ScheduledTask -TaskPath $UpdateTaskPath -TaskName $UpdateTaskName -Confirm:$false } Write-UpdateLog 'Automatic update task is disabled.' } $metadataPath = Join-Path $InstallPath 'SmartM365-DeviceRebootManager.installation.json' $metadata = Get-Content -LiteralPath $metadataPath -Raw | ConvertFrom-Json $metadata | Add-Member -NotePropertyName ModuleName -NotePropertyValue $ModuleName -Force $metadata | Add-Member -NotePropertyName SignerThumbprint ` -NotePropertyValue (Get-NormalizedThumbprint $ExpectedSignerThumbprint) -Force $metadata | Add-Member -NotePropertyName AutomaticUpdateEnabled ` -NotePropertyValue ([bool]$EnableAutomaticUpdate) -Force $metadata | Add-Member -NotePropertyName UpdateIntervalHours ` -NotePropertyValue $UpdateIntervalHours -Force $metadata | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $metadataPath -Encoding UTF8 Write-UpdateLog ("Device Reboot Manager deployed successfully. PackageVersion={0}" -f $metadata.PackageVersion) } catch { Write-UpdateLog -Level ERROR -Message $_.Exception.Message throw } # SIG # Begin signature block # MIIeYwYJKoZIhvcNAQcCoIIeVDCCHlACAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCqRVJVefXuqISM # ecSsajV7Co8AQqaiPu1cKUqB4UU2MqCCF/swggS9MIIDJaADAgECAhAebu87xzjh # s0Q4yPEDH+JoMA0GCSqGSIb3DQEBCwUAME4xHjAcBgNVBAMMFXdvcmtwbGFjZWNs # b3VkaHViLmNvbTEsMCoGCSqGSIb3DQEJARYdY29udGFjdEB3b3JrcGxhY2VjbG91 # ZGh1Yi5jb20wHhcNMjYwNzEzMDgyMjM1WhcNMjkwNzEzMDgzMjI5WjBOMR4wHAYD # VQQDDBV3b3JrcGxhY2VjbG91ZGh1Yi5jb20xLDAqBgkqhkiG9w0BCQEWHWNvbnRh # Y3RAd29ya3BsYWNlY2xvdWRodWIuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8A # MIIBigKCAYEAse6XztERSyHn9DVqj8Rdv0qjc5owqvgAIGaYxBmfiQuoM48Fo4Xt # 1ovi9brLUtf55G4XgthNPCoanxfCRRg30IVRxaDfdPXJzYmgsM5tXlsuNU49lE7E # PJk3+jEOgSCt8NKzmVPKpNRG0NmK0a8wm12cceYZOZlSYE0+ZtT6wy5PQQjMUqIx # XnGjt4H0nfgZZa7D4FyARKOVg/Xr9sUq5jIn3zszvg4jjeb4b0DKJtfbHukhWc2Y # oVFgswxVBXCWIaBnfF/cjqMfK/CaToT2trVb4hG4qcQ31s1nR4keoRaOw/vyd6ap # rEtCsT22N/Jx0dz7fIo1tVyvIaVcHdN9LW3chn0en0OKZ6Ke1OH9wf2prl4KA6Ww # VzrAZrOlXTAItdK7D9kKO/HeJd4PZvO53oy1LdmMGLSz3OLB9e5q7yo8rfqi5Ka9 # KzM2CrSzz1yphn/H90wz7Q2pm4FIlWdcj86A/0kmhYg+5Wqqbg1drrPXu4nEBwWN # /dzoGtKZKHTdAgMBAAGjgZYwgZMwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG # CCsGAQUFBwMDMD8GA1UdEQQ4MDaBHWNvbnRhY3RAd29ya3BsYWNlY2xvdWRodWIu # Y29tghV3b3JrcGxhY2VjbG91ZGh1Yi5jb20wDAYDVR0TAQH/BAIwADAdBgNVHQ4E # FgQUXIOOADQM78XfPAncirgCECedg9gwDQYJKoZIhvcNAQELBQADggGBADhZUB2R # 5J/Jw030xodhEWeCQ0vnJRaiEsjOxuArQREKH3lCrQ3UsUVl292d6LnQUSTH/jF7 # rovEZ+JN2GQ/LCrXRaCuwCEGZKzlSEbtYWhfwDyj6GpIPq8Y4SeXyjdq4/rrI1bm # iTK4Sq7EoBlGJuX6l2nfvx1tTioSr11FoDfllJR7EYawRj9hBFJ0gG0b2SuYZMgW # gaDKefcnJDmOwcRNAZUII0ss8EeyANukWSkNN5ILZ+iKDpQgZxgDLPTiRguCyx45 # PI5wrVTjV/pR7IrtSIfq8UladlrSZJyyDn3NV2ATvIZ6wNxbTmPFcE0uMg/EYzwd # Tek+CgXL3TxUKeldJM4YDWPimNBRhOPXzBDiOQIj6WNswt/KM1oDLnA00CNtciPN # dn+dXlneMvTEUah9wyt8o8tkLpoBw+KN+Bq/K0O1qPtS7umi70l45pPiej+mwbwq # ztcaoVD7a8ggHP1Vdp/rnafM4GtyCAE6b7U9Yzgvp1/a1kh7XffmqVhRRjCCBY0w # ggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZIhvcNAQEMBQAwZTELMAkG # A1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRp # Z2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENB # MB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVowYjELMAkGA1UEBhMCVVMx # FTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv # bTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MIICIjANBgkqhkiG # 9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjwwIjBpM+zCpyUuySE98orY # WcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J58soR0uRf1gU8Ug9SH8ae # FaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMHhOZ0O21x4i0MG+4g1ckg # HWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6Zu53yEioZldXn1RYjgwr # t0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQecN4x7axxLVqGDgDEI3Y # 1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4bA3VdeGbZOjFEmjNAvwjX # WkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9WV1CdoeJl2l6SPDgohIb # Zpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCUtNJhbesz2cXfSwQAzH0c # lcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvoZKYz0YkH4b235kOkGLim # dwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/JvNNBERJb5RBQ6zHFynIW # IgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCPorF+CiaZ9eRpL5gdLfXZ # qbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOzX # 44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3z # bcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGG # GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2Nh # Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDBF # BgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNl # cnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG # 9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cHvZqsoYcs7IVeqRq7IviH # GmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8UgPITtAq3votVs/59Pes # MHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTnf+hZqPC/Lwum6fI0POz3 # A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxUjG/voVA9/HYJaISfb8rb # II01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8jLfR+cWojayL/ErhULSd+ # 2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDCCBrQwggScoAMCAQICEA3HrFcF # /yGZLkBDIgw6SYYwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNV # BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8G # A1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4XDTI1MDUwNzAwMDAwMFoX # DTM4MDExNDIzNTk1OVowaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0 # LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGlu # ZyBSU0E0MDk2IFNIQTI1NiAyMDI1IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP # ADCCAgoCggIBALR4MdMKmEFyvjxGwBysddujRmh0tFEXnU2tjQ2UtZmWgyxU7UNq # EY81FzJsQqr5G7A6c+Gh/qm8Xi4aPCOo2N8S9SLrC6Kbltqn7SWCWgzbNfiR+2fk # HUiljNOqnIVD/gG3SYDEAd4dg2dDGpeZGKe+42DFUF0mR/vtLa4+gKPsYfwEu7EE # bkC9+0F2w4QJLVSTEG8yAR2CQWIM1iI5PHg62IVwxKSpO0XaF9DPfNBKS7Zazch8 # NF5vp7eaZ2CVNxpqumzTCNSOxm+SAWSuIr21Qomb+zzQWKhxKTVVgtmUPAW35xUU # FREmDrMxSNlr/NsJyUXzdtFUUt4aS4CEeIY8y9IaaGBpPNXKFifinT7zL2gdFpBP # 9qh8SdLnEut/GcalNeJQ55IuwnKCgs+nrpuQNfVmUB5KlCX3ZA4x5HHKS+rqBvKW # xdCyQEEGcbLe1b8Aw4wJkhU1JrPsFfxW1gaou30yZ46t4Y9F20HHfIY4/6vHespY # MQmUiote8ladjS/nJ0+k6MvqzfpzPDOy5y6gqztiT96Fv/9bH7mQyogxG9QEPHrP # V6/7umw052AkyiLA6tQbZl1KhBtTasySkuJDpsZGKdlsjg4u70EwgWbVRSX1Wd4+ # zoFpp4Ra+MlKM2baoD6x0VR4RjSpWM8o5a6D8bpfm4CLKczsG7ZrIGNTAgMBAAGj # ggFdMIIBWTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTvb1NK6eQGfHrK # 4pBW9i/USezLTjAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNV # HQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBp # MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUH # MAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRS # b290RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0 # LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EM # AQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAF877FoAc/gc9EXZx # ML2+C8i1NKZ/zdCHxYgaMH9Pw5tcBnPw6O6FTGNpoV2V4wzSUGvI9NAzaoQk97fr # PBtIj+ZLzdp+yXdhOP4hCFATuNT+ReOPK0mCefSG+tXqGpYZ3essBS3q8nL2UwM+ # NMvEuBd/2vmdYxDCvwzJv2sRUoKEfJ+nN57mQfQXwcAEGCvRR2qKtntujB71WPYA # gwPyWLKu6RnaID/B0ba2H3LUiwDRAXx1Neq9ydOal95CHfmTnM4I+ZI2rVQfjXQA # 1WSjjf4J2a7jLzWGNqNX+DF0SQzHU0pTi4dBwp9nEC8EAqoxW6q17r0z0noDjs6+ # BFo+z7bKSBwZXTRNivYuve3L2oiKNqetRHdqfMTCW/NmKLJ9M+MtucVGyOxiDf06 # VXxyKkOirv6o02OoXN4bFzK0vlNMsvhlqgF2puE6FndlENSmE+9JGYxOGLS/D284 # NHNboDGcmWXfwXRy4kbu4QFhOm0xJuF2EZAOk5eCkhSxZON3rGlHqhpB/8MluDez # ooIs8CVnrpHMiD2wL40mm53+/j7tFaxYKIqL0Q4ssd8xHZnIn/7GELH3IdvG2XlM # 9q7WP/UwgOkw/HQtyRN62JK4S1C8uw3PdBunvAZapsiI5YKdvlarEvf8EA+8hcpS # M9LHJmyrxaFtoza2zNaQ9k+5t1wwggbtMIIE1aADAgECAhAKgO8YS43xBYLRxHan # lXRoMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp # Q2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3Rh # bXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwHhcNMjUwNjA0MDAwMDAwWhcN # MzYwOTAzMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs # IEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFNIQTI1NiBSU0E0MDk2IFRpbWVzdGFt # cCBSZXNwb25kZXIgMjAyNSAxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC # AgEA0EasLRLGntDqrmBWsytXum9R/4ZwCgHfyjfMGUIwYzKomd8U1nH7C8Dr0cVM # F3BsfAFI54um8+dnxk36+jx0Tb+k+87H9WPxNyFPJIDZHhAqlUPt281mHrBbZHqR # K71Em3/hCGC5KyyneqiZ7syvFXJ9A72wzHpkBaMUNg7MOLxI6E9RaUueHTQKWXym # OtRwJXcrcTTPPT2V1D/+cFllESviH8YjoPFvZSjKs3SKO1QNUdFd2adw44wDcKgH # +JRJE5Qg0NP3yiSyi5MxgU6cehGHr7zou1znOM8odbkqoK+lJ25LCHBSai25CFyD # 23DZgPfDrJJJK77epTwMP6eKA0kWa3osAe8fcpK40uhktzUd/Yk0xUvhDU6lvJuk # x7jphx40DQt82yepyekl4i0r8OEps/FNO4ahfvAk12hE5FVs9HVVWcO5J4dVmVzi # x4A77p3awLbr89A90/nWGjXMGn7FQhmSlIUDy9Z2hSgctaepZTd0ILIUbWuhKuAe # NIeWrzHKYueMJtItnj2Q+aTyLLKLM0MheP/9w6CtjuuVHJOVoIJ/DtpJRE7Ce7vM # RHoRon4CWIvuiNN1Lk9Y+xZ66lazs2kKFSTnnkrT3pXWETTJkhd76CIDBbTRofOs # NyEhzZtCGmnQigpFHti58CSmvEyJcAlDVcKacJ+A9/z7eacCAwEAAaOCAZUwggGR # MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOQ7/PIx7f391/ORcWMZUEPPYYzoMB8G # A1UdIwQYMBaAFO9vU0rp5AZ8esrikFb2L9RJ7MtOMA4GA1UdDwEB/wQEAwIHgDAW # BgNVHSUBAf8EDDAKBggrBgEFBQcDCDCBlQYIKwYBBQUHAQEEgYgwgYUwJAYIKwYB # BQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBdBggrBgEFBQcwAoZRaHR0 # cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGltZVN0 # YW1waW5nUlNBNDA5NlNIQTI1NjIwMjVDQTEuY3J0MF8GA1UdHwRYMFYwVKBSoFCG # Tmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRpbWVT # dGFtcGluZ1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNybDAgBgNVHSAEGTAXMAgGBmeB # DAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAGUqrfEcJwS5rmBB # 7NEIRJ5jQHIh+OT2Ik/bNYulCrVvhREafBYF0RkP2AGr181o2YWPoSHz9iZEN/FP # sLSTwVQWo2H62yGBvg7ouCODwrx6ULj6hYKqdT8wv2UV+Kbz/3ImZlJ7YXwBD9R0 # oU62PtgxOao872bOySCILdBghQ/ZLcdC8cbUUO75ZSpbh1oipOhcUT8lD8QAGB9l # ctZTTOJM3pHfKBAEcxQFoHlt2s9sXoxFizTeHihsQyfFg5fxUFEp7W42fNBVN4ue # LaceRf9Cq9ec1v5iQMWTFQa0xNqItH3CPFTG7aEQJmmrJTV3Qhtfparz+BW60OiM # EgV5GWoBy4RVPRwqxv7Mk0Sy4QHs7v9y69NBqycz0BZwhB9WOfOu/CIJnzkQTwtS # SpGGhLdjnQ4eBpjtP+XB3pQCtv4E5UCSDag6+iX8MmB10nfldPF9SVD7weCC3yXZ # i/uuhqdwkgVxuiMFzGVFwYbQsiGnoa9F5AaAyBjFBtXVLcKtapnMG3VH3EmAp/js # J3FVF3+d1SVDTmjFjLbNFZUWMXuZyvgLfgyPehwJVxwC+UpX2MSey2ueIu9THFVk # T+um1vshETaWyQo8gmBto/m3acaP9QsuLj3FNwFlTxq25+T4QwX9xa6ILs84ZPvm # povq90K8eWyG2N01c4IhSOxqt81nMYIFvjCCBboCAQEwYjBOMR4wHAYDVQQDDBV3 # b3JrcGxhY2VjbG91ZGh1Yi5jb20xLDAqBgkqhkiG9w0BCQEWHWNvbnRhY3RAd29y # a3BsYWNlY2xvdWRodWIuY29tAhAebu87xzjhs0Q4yPEDH+JoMA0GCWCGSAFlAwQC # AQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwG # CisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZI # hvcNAQkEMSIEIOF5EE1inR67fseaXIjPqYm8mpfj+oLyC4z2uauD2pQWMA0GCSqG # SIb3DQEBAQUABIIBgEwBd7wHYc7ogJ0Ni6ugd+aS5EFvknuS+J4Ymm9Ei1lhUTMU # 0ZnyfXF8yHiNZ7gR72x4vaRvmXDhPW+DpCY9KNBlz/K4sQzhuOrQGKnjQRo2LqQA # exh1Zdpg4kAgGB7o5CRAcBpuwFlQ8u589o0h0J9SQrAxn6tNmpAOk5oWhvCpb0Fj # FlwTzDlK6QR/8lPU7g1kDH1kOBW5gqtWti/JNBP3/o5nRg1VM4Wbh1SSS7Sk89qJ # rNvrKuMDJCmX90DDjOB8r5buQjv9rcwWS0x1C6Ulo3BQq9u9gzZGIvLaKnFZ0aQ9 # f9auQBqdsfJyO4MZvD46W8e3WnfS2azFS3ts2h3l8/3AbnFIjgQ4wt7DWiul874A # zmo6IxUJfR12dOzc0z+7+FGS9Bf4cZZOtyuhmnsv9p3pysYcY3r+0jEwc5W3lbA5 # ns4nsDnt7E/7p8dFOOskmH+4JlIqT1ZANVahMsOMTASa/44KINAFimgqNE1jqcJd # N40jQgo5y7hsw7tfqaGCAyYwggMiBgkqhkiG9w0BCQYxggMTMIIDDwIBATB9MGkx # CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4 # RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYg # MjAyNSBDQTECEAqA7xhLjfEFgtHEdqeVdGgwDQYJYIZIAWUDBAIBBQCgaTAYBgkq # hkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNjA3MjkwNzU0 # MThaMC8GCSqGSIb3DQEJBDEiBCCA8IHvMF8VwQRTdVE1A/hnX50bdwOtlzSmzqZr # YZHwIDANBgkqhkiG9w0BAQEFAASCAgB6rCvP/2Ysf3ILDeIdoUndDlSNhXMRgjAd # ZnJXqS2pBYEe4J2T/OS5u0WCOnEzISfxtwgeaYr0VaxDDlTqYaMBX4xlO3JIA1WZ # cR3gSn+O4uioLiU3xO+AyMcgHRWfjOYIBPwm4YUelPa3REFR7wV2XEpgBn+xPwjh # Pncc2YMdrSLxQgTcmxMJ81ub12mZcIazIq/1RoqBeX9T2O4yqrskqacWmFex47s9 # dsLUmpVlJNEf1EtW4v4Xp4zR2SffVLKdiPbl2/bD7fMSvxDQ1TyHLeD0lgkePTVe # 8/DLKNrhfMPtzg+EtNDd9QRtfoa+s7skH6CXzYsC9yViMR3YdRi7etRM3idN0bEI # YE0GXHYLerrQUbXPN9DFvKuTH4XlrkZgGkoiJb1MnxItJjOL0/x27yfdHFKo5Vwz # y1oR3HiC2ocs5LSfT6zxgsJRJKR9JB5aDy4KE2QkVRWiXrmqFW9ykjXjHVoElfTh # nktEONkIWG3NlA/RzgCHccfEr69iryRiMrnnmQZSkQUYb++7YN+ADzAVPYI+YSgb # lSKdQp35BDm+l1vIKicQC20OX3+4NTJ/So+kK2fWcNAyuj68LNaeHur9oFJ0W0G1 # USmU8VNuatVD5K3ntCrpofPlljf2yL8jR8TQC+WNBn7nRkZy7YHLyVbjIElx35vO # q5HJk1ToXA== # SIG # End signature block |