Microsoft heeft een probleem bevestigd waarbij iconen van programma’s spontaan verdwijnen. Dit probleem is ontstaan door een bug in Windows Defender. Inmiddels is een script op github gezet om dit te herstellen.
Download zowel AddShortcuts.ps1 als MpTaskBarRecover.exe.
Voer het commando onderstaande commando als administrator uit.
powershell -ep bypass -file .\AddShortcuts.ps1 -MpTaskBarRecoverUtilLocal
Maakt je organisatie gebruik van intune, deploy dan AddShortcuts.ps1 en voer het volgende commando uit. Hierbij wordt MPTaskBarRecover.exe op de achtergrond door het script gedownload.
powershell –ep bypass –file .\AddShortcuts.ps1 -MpTaskBarRecoverUtilDownload
Gebruikers dienen hierna af- en aan te melden.
Het kan mogelijk nodig zijn om meerdere malen MPRecoverTaskbar.exe uit te voeren om alle iconen terug te krijgen. Eventueel is het zelfs noodzakelijk dit vanuit de eind-gebruiker context te doen (zonder elevation).
Het AddShortcuts.ps1 script:
<# MIT License Copyright (c) Microsoft Corporation. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE #> <# For information about this tool, including data it stores to understand effectiveness, go to https://aka.ms/ASR_shortcuts_deletion_FAQ #> <# # script to add deleted shortcuts back for common application. # Credits: https://github.com/InsideTechnologiesSrl/DefenderBug/blob/main/W11-RestoreLinks.ps1 # https://p0w3rsh3ll.wordpress.com/2014/06/21/mount-and-dismount-volume-shadow-copies/ # https://github.com/microsoft/MDE-PowerBI-Templates/issues/18 (RobertEbbrecht) # https://github.com/microsoft/MDE-PowerBI-Templates/issues/31 (MeIQL) # Help: Param Telemetry: enable or disable having telemetry logging, default: true Param ForceRepair: repair is done irrespective of machine being considered affected or not, default: false Param VssRecovery: Use VSS recovery to restore lnk files, default: false Param Verbose: Value 0: No stdout and no log file Value 1: Only stdout (default) Value 2: both stdout and log file output Value 3: detailed stdout along with log file output #> param ([bool] $Telemetry = $true, [switch] $ForceRepair = $false, [switch] $VssRecovery = $true, [switch] $MpTaskBarRecoverUtilDownload = $true, [switch] $SkipBinaryValidation = $false, [int] $Verbose = 1) $ScriptVersion = 3 $ScriptVersionStr = "v" + $ScriptVersion.ToString() $doesCFANeedsReset = $false $TaskbarRecoveryToolName = "MpRecoverTaskbar.exe" <# # Important: programs table below is a key=value pair, with [] are used to denote programs that have version year info, like [Visual Studio 2022] # for such entries with [], we will lookup file description in file version info and use that, if it doesnt exists, we will falback using generic name. #> $programs = @{ "Adobe Acrobat" = "Acrobat.exe" "[Adobe Photoshop]" = "photoshop.exe" "[Adobe Illustrator]" = "illustrator.exe" "Adobe Creative Cloud" = "Creative Cloud.exe" "Adobe Substance 3D Painter" = "Adobe Substance 3D Painter.exe" "Firefox Private Browsing" = "private_browsing.exe" "Firefox" = "firefox.exe" "Google Chrome" = "chrome.exe" "Microsoft Edge" = "msedge.exe" "Notepad++" = "notepad++.exe" "Parallels Client" = "APPServerClient.exe" "Remote Desktop" = "msrdcw.exe" "TeamViewer" = "TeamViewer.exe" "[Royal TS]" = "royalts.exe" "Elgato StreamDeck" = "StreamDeck.exe" "[Visual Studio]" = "devenv.exe" "Visual Studio Code" = "code.exe" "Camtasia Studio" = "CamtasiaStudio.exe" "Camtasia Recorder" = "CamtasiaRecorder.exe" "Jabra Direct" = "jabra-direct.exe" "7-Zip File Manager" = "7zFM.exe" "Access" = "MSACCESS.EXE" "Excel" = "EXCEL.EXE" "OneDrive" = "onedrive.exe" "OneNote" = "ONENOTE.EXE" "Outlook" = "OUTLOOK.EXE" "PowerPoint" = "POWERPNT.EXE" "Project" = "WINPROJ.EXE" "Publisher" = "MSPUB.EXE" "Visio" = "VISIO.EXE" "Word" = "WINWORD.exe" "[PowerShell 7]" = "pwsh.exe" "SQL Server Management Studio" = "ssms.exe" "Azure Data Studio" = "azuredatastudio.exe" "Zoom" = "zoom.exe" "Internet Explorer" = "IEXPLORE.EXE" "Skype for Business" = "Skype.exe" "VLC Player" = "vlc.exe" "Cisco Jabber" = "CiscoJabber.exe" "Microsoft Teams" = "msteams.exe" "PuTTY" = "putty.exe" "wordpad" = "WORDPAD.EXE" "[AutoCAD]" = "acad.exe" "[CORSAIR iCUE Software]" = "iCue.exe" "[Steam]" = "steam.exe" "Paint" = "mspaint.exe" } $LogFileName = [string]::Format("ShortcutRepairs{0}.log", (Get-Random -Minimum 0 -Maximum 99)) $LogFilePath = "$env:temp\$LogFileName"; Function Log { param($message); if ($Verbose -ge 2) { $currenttime = Get-Date -format u; $outputstring = "[" + $currenttime + "] " + $message; $outputstring | Out-File $LogFilepath -Append; } } Function LogAndConsole($message) { if ($Verbose -ge 1) { Write-Host $message -ForegroundColor Green } if ($Verbose -ge 2) { Log $message } } Function LogErrorAndConsole($message) { if ($Verbose -ge 1) { Write-Host $message -ForegroundColor Red } if ($Verbose -ge 2) { Log $message } } function Get-PSVersion { if ($PSVersionTable.PSVersion -like '7*') { [string]$PSVersionTable.PSVersion.Major + '.' + [string]$PSVersionTable.PSVersion.Minor + '.' + [string]$PSVersionTable.PSVersion.Patch } else { [string]$PSVersionTable.PSVersion.Major + '.' + [string]$PSVersionTable.PSVersion.Minor + '.' + [string]$PSVersionTable.PSVersion.Build } } # Saves the result of the script in the registry. # If you don't want this information to be saved use the -Telemetry $false option Function SaveResult() { param( [parameter(ParameterSetName = "Failure")][switch][Alias("Failed")]$script_failed = $false, [parameter(ParameterSetName = "Failure")][string][Alias("ScriptError")]$script_error = "Generic Error", [parameter(ParameterSetName = "Failure")][parameter(ParameterSetName = "Success")][int32][Alias("NumLinksFound")]$links_found = 0, [parameter(ParameterSetName = "Failure")][parameter(ParameterSetName = "Success")][int32][Alias("HKUAppsSuccess")]$hku_success = 0, [parameter(ParameterSetName = "Failure")][parameter(ParameterSetName = "Success")][int32][Alias("HKUAppsFailure")]$hku_failure = 0, [parameter(ParameterSetName = "Failure")][parameter(ParameterSetName = "Success")][int32][Alias("HKLMAppsSuccess")]$hklm_success = 0, [parameter(ParameterSetName = "Failure")][parameter(ParameterSetName = "Success")][int32][Alias("HKLMAppsFailure")]$hklm_failure = 0, [parameter(ParameterSetName = "Success")][switch][Alias("Succeeded")]$script_succeeded = $false, [parameter(ParameterSetName = "Success")][parameter(ParameterSetName = "Failure")][Alias("User")][switch]$use_hkcu = $false ) if ($use_hkcu) { $registry_hive = "HKCU:" } else { $registry_hive = "HKLM:" } $registry_hive += "Software\Microsoft" $registry_name = "ASRFix" if ($Telemetry) { $registry_full_path = $registry_hive + "\" + $registry_name if (Test-Path -Path $registry_full_path) { #Registry Exists } else { #Registry does not Exist, create it New-Item -Path $registry_hive -Name $registry_name -Force | Out-Null } #Create a timestamp $timestamp = [DateTime]::UtcNow.ToString('o') #If its a success, make sure there is no error left over from last run if ($PsCmdlet.ParameterSetName -eq "Success") { $script_error = "None" $result = "Success" $script_result = 0 } else { $result = "Failure" $script_result = 1 } #Save the result in the registry New-ItemProperty -Path $registry_full_path -Name Version -Value $ScriptVersion -Force | Out-Null New-ItemProperty -Path $registry_full_path -Name ScriptResult -Value $script_result -Force -PropertyType DWORD | Out-Null New-ItemProperty -Path $registry_full_path -Name Timestamp -Value $timestamp -Force | Out-Null New-ItemProperty -Path $registry_full_path -Name NumLinksFound -Value $links_found -PropertyType DWORD -Force | Out-Null New-ItemProperty -Path $registry_full_path -Name HKUAppSuccess -Value $hku_success -PropertyType DWORD -Force | Out-Null New-ItemProperty -Path $registry_full_path -Name HKUAppFailure -Value $hku_failure -PropertyType DWORD -Force | Out-Null New-ItemProperty -Path $registry_full_path -Name HKLMSuccess -Value $hklm_success -PropertyType DWORD -Force | Out-Null New-ItemProperty -Path $registry_full_path -Name HKLMFailure -Value $hklm_failure -PropertyType DWORD -Force | Out-Null New-ItemProperty -Path $registry_full_path -Name ScriptError -Value $script_error -Force | Out-Null if ($Verbose -ge 1) { LogAndConsole "[+] Saved Result: ScriptResult=$result ($script_result), TimeStamp=$timestamp, NumLinksFound=$links_found, HKUAppSuccess=$hku_success, HKUAppFailure=$hku_failure, HKLMSuccess=$hklm_success, HKLMFailure=$hklm_failure, ScriptError=$script_error in registry $registry_full_path" } } } #If there is any error, save the result as a failure trap { if ($doesCFANeedsReset) { # turn it back on LogAndConsole "[+] Turn CFA back ON to its original state" Set-MpPreference -EnableControlledFolderAccess 1 $doesCFANeedsReset = $false } $id = [System.Security.Principal.WindowsIdentity]::GetCurrent() $p = New-Object System.Security.Principal.WindowsPrincipal($id) if (!($p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) -Or ($id.Name -like "NT AUTHORITY\SYSTEM"))) { SaveResult -Failed -User -ScriptError $_ } else { SaveResult -Failed -ScriptError $_ } exit } Function Mount-VolumeShadowCopy { <# .SYNOPSIS Mount a volume shadow copy. .DESCRIPTION Mount a volume shadow copy. .PARAMETER ShadowPath Path of volume shadow copies submitted as an array of strings .PARAMETER Destination Target folder that will contain mounted volume shadow copies .EXAMPLE Get-CimInstance -ClassName Win32_ShadowCopy | Mount-VolumeShadowCopy -Destination C:\VSS -Verbose #> [CmdletBinding()] Param( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [ValidatePattern('\\\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy\d{1,}')] [Alias("DeviceObject")] [String[]]$ShadowPath, [Parameter(Mandatory)] [ValidateScript({ Test-Path -Path $_ -PathType Container } )] [String]$Destination ) Begin { Try { $null = [mklink.symlink] } Catch { Add-Type @" using System; using System.Runtime.InteropServices; namespace mklink { public class symlink { [DllImport("kernel32.dll")] public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags); } } "@ } } Process { $ShadowPath | ForEach-Object -Process { if ($($_).EndsWith("\")) { $sPath = $_ } else { $sPath = "$($_)\" } $tPath = Join-Path -Path $Destination -ChildPath ( '{0}-{1}' -f (Split-Path -Path $sPath -Leaf), [GUID]::NewGuid().Guid ) try { if ( [mklink.symlink]::CreateSymbolicLink($tPath, $sPath, 1) ) { LogAndConsole "`tSuccessfully mounted $sPath to $tPath" return $tPath } else { LogAndConsole "[!] Failed to mount $sPath" } } catch { LogAndConsole "[!] Failed to mount $sPath because $($_.Exception.Message)" } } } End {} } Function Dismount-VolumeShadowCopy { <# .SYNOPSIS Dismount a volume shadow copy. .DESCRIPTION Dismount a volume shadow copy. .PARAMETER Path Path of volume shadow copies mount points submitted as an array of strings .EXAMPLE Get-ChildItem -Path C:\VSS | Dismount-VolumeShadowCopy -Verbose #> [CmdletBinding()] Param( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias("FullName")] [string[]]$Path ) Begin { } Process { $Path | ForEach-Object -Process { $sPath = $_ if (Test-Path -Path $sPath -PathType Container) { if ((Get-Item -Path $sPath).Attributes -band [System.IO.FileAttributes]::ReparsePoint) { try { [System.IO.Directory]::Delete($sPath, $false) | Out-Null LogAndConsole "`tSuccessfully dismounted $sPath" } catch { LogAndConsole "[!] Failed to dismount $sPath because $($_.Exception.Message)" } } else { LogAndConsole "[!] The path $sPath isn't a reparsepoint" } } else { LogAndConsole "[!] The path $sPath isn't a directory" } } } End {} } Function GetTimeRangeOfVersion() { $versions = "1.381.2140.0", "1.381.2152.0", "1.381.2160.0" $properties2000 = @( 'TimeCreated', 'ProductName', 'ProductVersion', @{n = 'CurrentVersion'; e = { $_.Properties[2].Value } }, @{n = 'PreviousVersion'; e = { $_.Properties[3].Value } }) $installTime = $null $removalTime = $null $foundVersion = $null try { foreach ($version in $versions) { if ($null -eq $installTime) { $lgp_events = (Get-WinEvent -LogName "Microsoft-Windows-Windows Defender/Operational" | where { $_.Id -eq 2000 } | Select $properties2000 | Where-Object { $_.CurrentVersion -eq $($version) } ) if ($lgp_events) { $installTime = @($lgp_events[0]).TimeCreated $foundVersion = $version } } $rgp_events = (Get-WinEvent -LogName "Microsoft-Windows-Windows Defender/Operational" | where { $_.Id -eq 2000 } | Select $properties2000 | Where-Object { $_.PreviousVersion -eq $($version) } ) if ($rgp_events) { $removalTime = @($rgp_events[0]).TimeCreated } } if ($installTime ) { if ($removalTime) { if ($Verbose -gt 2) { LogAndConsole "`tInstall time $installTime, removal time $removalTime for build $foundVersion" } } else { if ($Verbose -gt 2) { LogAndConsole "[!] Broken build version $foundVersion is still installed! First update to a build >= 1.381.2164.0 and run again." } } } else { LogAndConsole "[+] Machine not impacted" } } catch { if ($Verbose -gt 2) { LogAndConsole "[!] Failed to find broken build version." } } if ($null -eq $installTime) { # We couldn't find broken build version, vss recovery will be enforced by hardcoded date we have from VDM release time $installTime = '2023-01-13T06:04:45.000Z' # convert UTC to current date $installTime = ([DateTime]$installTime).ToUniversalTime() $installTime = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($installTime, 'UTC', [System.TimeZoneInfo]::Local.Id) } return $installTime, $removalTime , $foundVersion } #check if Server SKU or not Function IsServerSKU { try { return ((Get-WmiObject -Class Win32_OperatingSystem).ProductType -ne 1) } catch { return (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Server\ServerLevels") } } #find shadow copy before bad update Function GetShadowcopyBeforeUpdate( $targetDate ) { $shadowCopies = $null $shadowcopies = Get-WmiObject Win32_shadowcopy | Where-Object { [System.Management.ManagementDateTimeConverter]::ToDateTime($_.InstallDate) -lt $targetDate } | Sort-Object InstallDate -Descending $driveDict = @{} foreach ($shadow in $shadowcopies ) { LogAndConsole "$($shadow.VolumeName) $($shadow.DeviceObject) $($shadow.InstallDate) $($shadow.CreationTime)" # this is intentional, to replace \ with \\ $escapedDrive = $shadow.VolumeName -replace '\\', '\\' $volume = Get-WmiObject -Class Win32_Volume -Namespace "root\cimv2" -Filter "DeviceID='$escapedDrive'" if ($null -eq $driveDict[$volume.DriveLetter]) { $driveDict[$volume.DriveLetter] = @() } $driveDict[$volume.DriveLetter] += $shadow } return $driveDict } function getAllValidExtsForDrive($path, $drive, $prefix, $extension) { $prefixLen = $($path).length LogAndConsole "[+] Listing $($extension) for $($path)\$($prefix)*" $extFiles = Get-ChildItem -ErrorAction SilentlyContinue -Path "$path\$($prefix)*" -Include "*$($extension)" -Recurse -Force if ($Verbose -gt 2) { LogAndConsole "`tNow analyzing ($extension) files..." } if ($extFiles) { $validFiles = @() foreach ($extFile in $extFiles) { if ($Verbose -gt 2) { LogAndConsole "`tFound $($extension): $($extFile.FullName)" } $drivePath = $drive + $extFile.FullName.Substring($prefixLen) try { if ($Verbose -gt 2) { LogAndConsole "`tChecking original: $($drivePath)" } $originalLink = Get-Item -Path $drivePath -ErrorAction Stop } catch { Copy-Item -Path $extFile.FullName -Destination $drivePath if ($Verbose -gt 2) { LogAndConsole "`tOriginal path doesn't exist anymore: $($drivePath)" } $validFiles += $extFile } } return $validFiles } } function getAllValidLNKsForDrive($path, $drive, $prefix) { $prefixLen = $($path).length LogAndConsole "[+] Listing .lnk for $path\$($prefix)*" $lnkFiles = Get-ChildItem -ErrorAction SilentlyContinue -Path "$path\$($prefix)*" -Include "*.lnk" -Recurse -Force if ($Verbose -gt 2) { LogAndConsole "`tNow analyzing .lnk files..." } if ($lnkFiles) { $validLinks = @() foreach ($lnkFile in $lnkFiles) { try { $target = (New-Object -ComObject WScript.Shell).CreateShortcut($lnkFile.FullName).TargetPath $targetFile = Get-Item -Path $target -ErrorAction Stop } catch { if ($Verbose -gt 2) { LogAndConsole "`tThe target of $($lnkFile.FullName) does not exist. Skipped!" } } if ($Verbose -gt 2) { LogAndConsole "`tFound LNK: $($lnkFile.FullName)" } $drivePath = $drive + $lnkFile.FullName.Substring($prefixLen) try { if ($Verbose -gt 2) { LogAndConsole "`tChecking original: $($drivePath)" } $originalLink = Get-Item -Path $drivePath -ErrorAction Stop } catch { if ($Verbose -gt 2) { LogAndConsole "`tOriginal path doesn't exist anymore: $($drivePath)" } Copy-Item -Path $lnkFile.FullName -Destination $drivePath $validLinks += $lnkFile } } return $validLinks } } Function VssFileRecovery($events_time) { LogAndConsole "[+] Starting vss file recovery" $lnks = @() if ($events_time) { if ($Verbose -gt 2) { LogAndConsole ("`tStart time of update: $($events_time[0])") LogAndConsole ("`tEnd time of update: $($events_time[1])") } LogAndConsole "[+] Attempting vss file recovery by looking for shadow copies before time: $($events_time[0])" $missed_drives = @{} $guid = New-Guid $target = "$env:SystemDrive\vssrecovery-$guid\" try { $shadowcopies = GetShadowcopyBeforeUpdate( $events_time[0]) if ($shadowcopies) { # create a directory for vss mount New-Item -Path $target -ItemType Directory -force | Out-Null # get list of profiles that have been modified within range $localUsersPath = Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" -Name ProfilesDirectory $profiles = Get-ChildItem -Path $localUsersPath -Force LogAndConsole "[+] Start recovering profiles" foreach ($profilename in $profiles) { $profiledir = (Split-Path $profilename.FullName -NoQualifier).Trim("\").ToString() $drive = Split-Path $profilename.FullName -Qualifier if ($null -ne $shadowCopies[$drive]) { $shadowCopy = $shadowCopies[$drive][0] if ($Verbose -gt 2) { LogAndConsole "`tRestoring items for drive $drive and profile $profilename" } LogAndConsole $($shadowCopy.DeviceObject) $res = Mount-VolumeShadowCopy $shadowCopy.DeviceObject -Destination $target -Verbose if ($Verbose -gt 2) { LogAndConsole "`tNow enumerating for $($profiledir)" } $lnks += getAllValidLNKsForDrive -path $res -drive $drive -prefix "\Windows\System32\config\systemprofile\AppData\Roaming\Microsoft\Internet Explorer\Quick Launch\" $lnks += getAllValidLNKsForDrive -path $res -drive $drive -prefix "\ProgramData\Microsoft\Windows\Start Menu\" $lnks += getAllValidLNKsForDrive -path $res -drive $drive -prefix "$($profiledir)\AppData\Roaming\Microsoft\Windows\" $lnks += getAllValidLNKsForDrive -path $res -drive $drive -prefix "$($profiledir)\AppData\Roaming\Microsoft\Internet Explorer\" $lnks += getAllValidLNKsForDrive -path $res -drive $drive -prefix "$($profiledir)\AppData\Roaming\Microsoft\Office\" $lnks += getAllValidExtsForDrive -path $res -drive $drive -prefix "$($profiledir)\Favorites\" -extension ".url" $lnks += getAllValidExtsForDrive -path $res -drive $drive -prefix "$($profiledir)\Desktop\" -extension ".url" $lnks += getAllValidExtsForDrive -path $res -drive $drive -prefix "$($profiledir)\Desktop\" -extension ".lnk" Get-ChildItem -Path $target | Dismount-VolumeShadowCopy -Verbose } else { if ($null -eq $missed_drives[$drive]) { $missed_drives[$drive] = 1 if ($Verbose -gt 2) { LogAndConsole ("[!] No shadow copy could be found before update for $drive, unable to do VSS recovery for it, skipping!") } } } } if ($Verbose -gt 2) { if ($lnks) { LogAndConsole "`tRecovered Links from VSS: $($lnks)" } else { LogAndConsole "[!] No .lnk and .url files were found in the shadow copy" } } #remove vss directory Remove-Item -Path $target -Recurse -force | Out-Null } else { LogAndConsole ("[!] No shadow copy could be found before update, unable to do VSS recovery, proceeding with re-creation attempt on Known apps!") } } catch { LogErrorAndConsole "[!] VSSRecovery failed!" #remove vss directory if (Test-Path -Path $target) { Remove-Item -Path $target -Recurse -force | Out-Null } } } return $lnks.Length } Function CopyAclFromOwningDir($path, $SetAdminsOwner) { $base_path = Split-Path -Path $path $acl = Get-Acl $base_path if ($SetAdminsOwner) { $SID = "S-1-5-32-544" $group = (New-Object System.Security.Principal.SecurityIdentifier($SID)).Translate([System.Security.Principal.NTAccount]) $acl.SetOwner($group) } Set-Acl $path $acl } Function LookupHKLMAppsFixLnks($programslist) { $success = 0 $failures = 0 $programslist.GetEnumerator() | ForEach-Object { $reg_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\$($_.Value)" try { $apppath = $null $target = $null try { $apppath = Get-ItemPropertyValue $reg_path -Name "Path" -ErrorAction SilentlyContinue } catch {} if ($null -ne $apppath) { if ($apppath.EndsWith(";") -eq $true) { $apppath = $apppath.Trim(";") } if ($apppath.EndsWith("\") -eq $false) { $apppath = $apppath + "\" } $target = $apppath + $_.Value } else { try { $target = Get-ItemPropertyValue $reg_path -Name "(default)" -ErrorAction SilentlyContinue } catch {} } if ($null -ne $target) { $targetName = $_.Key $target = $target.Trim("`"") if ($targetName.StartsWith("[") -and $targetName.EndsWith("]")) { try { $targetNameInVersion = (Get-Item -Path $target).VersionInfo.FileDescription.Trim() if ($targetNameInVersion) { $targetName = $targetNameInVersion } } catch { $targetName = $_.Key.Trim("][") } } $shortcut_path = "$env:PROGRAMDATA\Microsoft\Windows\Start Menu\Programs\$($targetName).lnk" if (-not (Test-Path -Path $shortcut_path)) { LogAndConsole ("`tShortcut for {0} not found in \Start Menu\, creating it now." -f $targetName) $description = $targetName $workingdirectory = (Get-ChildItem $target).DirectoryName $WshShell = New-Object -ComObject WScript.Shell $Shortcut = $WshShell.CreateShortcut($shortcut_path) $Shortcut.TargetPath = $target $Shortcut.Description = $description $shortcut.WorkingDirectory = $workingdirectory $Shortcut.Save() Start-Sleep -Seconds 1 # Let the LNK file be backed to disk if ($Verbose -gt 2) { LogAndConsole "`tCopying ACL from owning folder" } CopyAclFromOwningDir $shortcut_path $True $success += 1 } } } catch { $failures += 1 LogErrorAndConsole "Exception: $_" } } return $success, $failures } Function LookupHKUAppsFixLnks($programslist) { $success = 0 $failures = 0 $guid = New-Guid New-PSDrive -PSProvider Registry -Name $guid -Root HKEY_USERS -Scope Global | Out-Null $users = Get-ChildItem -Path "${guid}:\" foreach ($user in $users) { # Skip builtin if ($user.Name.Contains(".DEFAULT") -or $user.Name.EndsWith("_Classes")) { continue; } $sid_string = $user.Name.Split("\")[-1] ## Get the user profile path $profile_path = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$sid_string" -Name "ProfileImagePath").ProfileImagePath $programslist.GetEnumerator() | ForEach-Object { $reg_path = "${user}\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\$($_.Value)" try { $apppath = $null $target = $null try { $apppath = Get-ItemPropertyValue Registry::$reg_path -Name "Path" -ErrorAction SilentlyContinue } catch {} if ($null -ne $apppath) { if ($apppath.EndsWith(";") -eq $true) { $apppath = $apppath.Trim(";") } if ($apppath.EndsWith("\") -eq $false) { $apppath = $apppath + "\" } $target = $apppath + $_.Value } else { try { $target = Get-ItemPropertyValue Registry::$reg_path -Name "(default)" -ErrorAction SilentlyContinue } catch {} } if ($null -ne $target) { $targetName = $_.Key $target = $target.Trim("`"") if ($targetName.StartsWith("[") -and $targetName.EndsWith("]")) { try { $targetNameInVersion = (Get-Item -Path $target).VersionInfo.FileDescription.Trim() if ($targetNameInVersion) { $targetName = $targetNameInVersion } } catch { $targetName = $_.Key.Trim("][") } } $shortcut_path = "$profile_path\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\$($targetName).lnk" if (-not (Test-Path -Path $shortcut_path)) { LogAndConsole ("`tShortcut for {0} not found in \Start Menu\, creating it now." -f $targetName) $description = $targetName $workingdirectory = (Get-ChildItem $target).DirectoryName $WshShell = New-Object -ComObject WScript.Shell $Shortcut = $WshShell.CreateShortcut($shortcut_path) $Shortcut.TargetPath = $target $Shortcut.Description = $description $shortcut.WorkingDirectory = $workingdirectory $Shortcut.Save() Start-Sleep -Seconds 1 # Let the LNK file be backed to disk if ($Verbose -gt 2) { LogAndConsole "`tCopying ACL from owning folder" } CopyAclFromOwningDir $shortcut_path $False $success += 1 } } } catch { $failures += 1 LogErrorAndConsole "Exception: $_" } } } Remove-PSDrive -Name $guid | Out-Null return $success, $failures } Function IsValidBinary($taskpath) { # Optionally skip checks if ($SkipBinaryValidation) { return $true } # Validate authenticode $validatesig = Get-AuthenticodeSignature -FilePath $taskpath if ($Verbose -ge 3) { LogAndConsole "[+] $TaskbarRecoveryToolName Signature info: $validatesig" } if ($validatesig.Status -ne "Valid") { LogErrorAndConsole "[!] Failed to validate $TaskbarRecoveryToolName certificate status" return $false } # Need to change for new binaries if ($validatesig.SignerCertificate.Thumbprint -ne "63D7FBC20CD3AAB3AC663F465532AF9DCB8BBA33") { LogErrorAndConsole "[!] Failed to validate $TaskbarRecoveryToolName SignerCertificate" return $false } # Need to update the version info here $verinfo = (Get-Item $Taskpath).VersionInfo if ($Verbose -ge 3) { LogAndConsole "`t$TaskbarRecoveryToolName version info: $verinfo" } if ($verinfo.VersionString -lt 1.1.20029.0) { LogErrorAndConsole "[!] Failed to validate $TaskbarRecoveryToolName Version String" return $false } if ($verinfo.OriginalFilename -ne $TaskbarRecoveryToolName) { LogErrorAndConsole "[!] Failed to validate OriginalFilename of $TaskbarRecoveryToolName" return $false } if ($verinfo.InternalName -ne $TaskbarRecoveryToolName) { LogErrorAndConsole "[!] Failed to validate InternalName of $TaskbarRecoveryToolName" return $false } return $true } Function HandleMpTaskBarRecoverUtilRunOnce([bool]$download) { try { # Define the utility tool $util_path = "$env:windir\$TaskbarRecoveryToolName" # Handle local case if (-not $download) { # Copy locally from CWD $src_path = Join-Path -Path (Get-Location) -ChildPath $TaskbarRecoveryToolName # Validate tool authenticity if (-not (IsValidBinary($src_path))) { LogAndConsole "[!] Failed to validate '$src_path' authenticity, skipping automatic use RunOnce for $TaskbarRecoveryToolName" return } else { LogAndConsole "`t$TaskbarRecoveryToolName Passed Digital Thumbprint signature validation" } Copy-Item -Path $src_path -Destination $util_path -Force -ErrorAction SilentlyContinue if (-not (Test-Path $util_path)) { LogAndConsole "[!] Could not copy $TaskbarRecoveryToolName from current working directory to '$util_path'" return } } else { $util_download_url = "https://aka.ms/ASRTaskBarRepairTool" $wc = New-Object System.Net.WebClient try { $wc.DownloadFile($util_download_url, $util_path) } catch { LogAndConsole "[!] Could not download $TaskbarRecoveryToolName from '$util_download_url' to '$util_path'" return } # Validate tool authenticity if (-not (IsValidBinary($util_path))) { LogAndConsole "[!] Failed to validate '$util_path' authenticity, skipping automatic use RunOnce for $TaskbarRecoveryToolName" return } else { LogAndConsole "`t$TaskbarRecoveryToolName Passed Digital Thumbprint signature validation" } } # Register all user's RunOnce by traversing HKU $guid = New-Guid New-PSDrive -PSProvider Registry -Name $guid -Root HKEY_USERS -Scope Global | Out-Null $users = Get-ChildItem -Path "${guid}:\" foreach ($user in $users) { # Skip builtin $user_sid = $user.Name.Split("\")[-1] if ($user_sid.Contains(".DEFAULT") -or $user_sid.EndsWith("_Classes")) { if ($Verbose -ge 3) { LogAndConsole "`tSkipping $user_sid" } continue; } try { $fullprofile = Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$user_sid" -Name FullProfile if ($fullprofile -eq 1) { LogAndConsole "[+] Attempting RunOnce Registration for SID $user_sid" } } catch { if ($Verbose -ge 3) { LogAndConsole "`tSkipping $user_sid" } continue; } # Register RunOnce entry try { $RunOnceCmd = "`"$util_path`"" if ($ForceRepair) { $RunOnceCmd = $RunOnceCmd + " --force" } if ($Telemetry -ne $true) { $RunOnceCmd = $RunOnceCmd + " --notelemetry" } $RunOncePath = "${guid}:\$user_sid\Software\Microsoft\Windows\CurrentVersion\RunOnce" if (-not (Test-Path -Path $RunOncePath)) { $res = New-Item -Path "${guid}:\$user_sid\Software\Microsoft\Windows\CurrentVersion" -Name "RunOnce" -Force -ErrorAction SilentlyContinue if ($null -eq $res) { LogAndConsole "[!] RunOnce Key not found for SID $user_sid, unable to auto-create it" } } $res = New-ItemProperty -Path $RunOncePath -Name "MpTaskBarRecover" -Value $RunOnceCmd -Force -ErrorAction SilentlyContinue if ($null -eq $res) { LogAndConsole "[!] Failed registering RunOnce key for SID $user_sid" } else { LogAndConsole "[+] Successfully registered RunOnce key for SID $user_sid" } } catch { LogAndConsole "[!] Failed registering RunOnce key for SID $user_sid" } } Remove-PSDrive -Name $guid | Out-Null } catch { LogErrorAndConsole "Exception: $_" } } # Main Start # Validate elevated privileges LogAndConsole "[+] Starting LNK rescue - Script version: $ScriptVersionStr" try { $selfhash = (Get-FileHash -Algorithm:Sha1 $MyInvocation.MyCommand.Path).Hash LogAndConsole "`tScript hash: $selfhash" } catch {} LogAndConsole "`tPowerShell Version: $(Get-PSVersion)" $id = [System.Security.Principal.WindowsIdentity]::GetCurrent() $p = New-Object System.Security.Principal.WindowsPrincipal($id) if (!($p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) -Or ($id.Name -like "NT AUTHORITY\SYSTEM"))) { LogErrorAndConsole "[!] Not running from an elevated context" throw "[!] Please run this script from an elevated PowerShell as Admin or as System" exit } $isserver = IsServerSKU if ($isserver -and (-not $ForceRepair)) { LogAndConsole "[+] Server SKU didnt get affected, if repair is still needed, please run script again with parameter -ForceRepair" exit } # Is Machine Affected Check, continue if $ForceRepair is true $events_time = GetTimeRangeOfVersion if (-Not ($ForceRepair -or (($null -ne $events_time) -and ($null -ne $events_time[2]))) ) { LogAndConsole "[+] Machine didnt get affected, if repair is still needed, please run script again with parameter -ForceRepair" exit } else { if ($ForceRepair) { LogAndConsole "[+] Continue repair honoring ForceRepair" } } try { $doesCFANeedsReset = (Get-MpPreference).EnableControlledFolderAccess if ($doesCFANeedsReset) { LogAndConsole "[+] Turn off CFA temporarily for lnk repair" Set-MpPreference -EnableControlledFolderAccess 0 } } catch { LogAndConsole "[!] Unable to control CFA temporarily for lnk repair, for best results please turn off Controlled Folder Access and try again!" $doesCFANeedsReset = $false } # attempt vss recovery for restoring lnk files $VssRecoveredLnks = 0 if ($VssRecovery) { try { $VssRecoveredLnks = VssFileRecovery($events_time) LogAndConsole "[+] VSSRecovery found $VssRecoveredLnks lnks, Proceeding..." } catch { LogErrorAndConsole "[!] VSSRecovery failed!" } } # Check for shortcuts in Start Menu, if program is available and the shortcut isn't... Then recreate the shortcut LogAndConsole "[+] Enumerating installed software under HKLM" $hklm_apps_success, $hklm_apps_failures = LookupHKLMAppsFixLnks($programs) LogAndConsole "`tFinished with $hklm_apps_failures failures and $hklm_apps_success successes in fixing Machine level app links" LogAndConsole "[+] Enumerating installed software under HKU" $hku_apps_success, $hku_apps_failures = LookupHKUAppsFixLnks($programs) LogAndConsole "`tFinished with $hku_apps_failures failures and $hku_apps_success successes in fixing User level app links" # Handle MpTaskBarRecover.exe cases LogAndConsole "[+] Attempting TaskBar recovery for All Users using tool $TaskbarRecoveryToolName" HandleMpTaskBarRecoverUtilRunOnce $MpTaskBarRecoverUtilDownload if ($doesCFANeedsReset) { # turn it back on LogAndConsole "[+] Turn CFA back ON to its original state" Set-MpPreference -EnableControlledFolderAccess 1 $doesCFANeedsReset = $false } #Saving the result SaveResult -Succeeded -NumLinksFound $VssRecoveredLnks -HKLMAppsSuccess $hklm_apps_success -HKLMAppsFailure $hklm_apps_failures -HKUAppsSuccess $hku_apps_success -HKUAppsFailure $hku_apps_failures # SIG # Begin signature block # MIIlogYJKoZIhvcNAQcCoIIlkzCCJY8CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAOrI3shA45OmZ6 # 7AVcWxTl9KFBl2llNH0MI2rjgLsPvaCCC14wggTrMIID06ADAgECAhMzAAAJaWnl # VutOg/ZMAAAAAAlpMA0GCSqGSIb3DQEBCwUAMHkxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29mdCBXaW5kb3dzIFBD # QSAyMDEwMB4XDTIyMDUwNTIyMDAyN1oXDTIzMDUwNDIyMDAyN1owcDELMAkGA1UE # BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc # BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEaMBgGA1UEAxMRTWljcm9zb2Z0 # IFdpbmRvd3MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpucHUMbAq # 9TX7bb9eT5HgeUEAkCQqx8db9IGteLWtjh7NXNnUoxW79fDID+6GZihupXDFRFP7 # pD+iewhd91gfBNLczlB1hMeaggJ988VzxWpMNgQ3fYpeJDEwMdhmExRJyZEIKYFH # Dy/Bh5eykRIQmbiUi/r9+kj0W9hCMnuKRn2aXLee2YONt75g9vHH83+K+spbd04Y # ECV7o416V9cN/T5Sff4V8Bfx3q5B4wS8eWrTYV2CYwUFJaK4RSyuPIbBwxRuZ4Fk # uhonXnXHkaqQeMnd8PiFLppsga9wBhCDgmfamObmxwzl7gnl6jy0sNc7/3qMeWa2 # F/UKhk8suiwNAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEEAYI3CgMGBggr # BgEFBQcDAzAdBgNVHQ4EFgQUP5G9CxyPFlyBsy62z8QNx41WZv0wUAYDVR0RBEkw # R6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNv # MRYwFAYDVQQFEw0yMzAwMjgrNDcwMDM5MB8GA1UdIwQYMBaAFNFPqYoHCM70JBiY # 5QD/89Z5HTe8MFMGA1UdHwRMMEowSKBGoESGQmh0dHA6Ly9jcmwubWljcm9zb2Z0 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1dpblBDQV8yMDEwLTA3LTA2LmNybDBX # BggrBgEFBQcBAQRLMEkwRwYIKwYBBQUHMAKGO2h0dHA6Ly93d3cubWljcm9zb2Z0 # LmNvbS9wa2kvY2VydHMvTWljV2luUENBXzIwMTAtMDctMDYuY3J0MAwGA1UdEwEB # /wQCMAAwDQYJKoZIhvcNAQELBQADggEBAB4ai/kHW6cL86Rj+whuX/0UERNcW/Ls # KHite2ZfF46eYv73CyuLFzuCpc9Kuo41WjQx1Sl/pTeSPx57lJHQRmeVK+yYvm24 # 8LsVmLUiTZC1yRQ+PLvNfmwf26A3Bjv2eqi0xSKlRqYNcX1UWEJYBrxfyK+MWEtd # 84bwd8dnflZcPd4xfGPCtR9FUuFVjf+yXrSPUnD3rxT9AcebzU2fdqMGYHODndNz # ZmoroyIYPE7bIchKPa0WeQwT7pGf5FZdWCo/M8ym2qzIKhFGyG67cI5ZTErj4nvv # s5NSLMP0Og+6TQ5mRgVCwZyRknQ/1qLuuZNDd0USoHmOVTtp8tqqOiAwggZrMIIE # U6ADAgECAgphDGoZAAAAAAAEMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9v # dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDYyMDQwMjNaFw0y # NTA3MDYyMDUwMjNaMHkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u # MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp # b24xIzAhBgNVBAMTGk1pY3Jvc29mdCBXaW5kb3dzIFBDQSAyMDEwMIIBIjANBgkq # hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwHm7OrHwD4S4rWQqdRZz0LsH9j4NnRTk # sZ/ByJSwOHwf0DNV9bojZvUuKEhTxxaDuvVRrH6s4CZ/D3T8WZXcycai91JwWiwd # lKsZv6+Vfa9moW+bYm5tS7wvNWzepGpjWl/78w1NYcwKfjHrbArQTZcP/X84RuaK # x3NpdlVplkzk2PA067qxH84pfsRPnRMVqxMbclhiVmyKgaNkd5hGZSmdgxSlTAig # g9cjH/Nf328sz9oW2A5yBCjYaz74E7F8ohd5T37cOuSdcCdrv9v8HscH2MC+C5Me # KOBzbdJU6ShMv2tdn/9dMxI3lSVhNGpCy3ydOruIWeGjQm06UFtI0QIDAQABo4IB # 4zCCAd8wEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNFPqYoHCM70JBiY5QD/ # 89Z5HTe8MBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAP # BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjE # MFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kv # Y3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEF # BQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w # a2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGdBgNVHSAEgZUw # gZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5taWNy # b3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcCAjA0 # HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUAbgB0 # AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEALkGmhrUGb/CAhfo7yhfpyfrkOcKUcMNk # lMPYVqaQjv7kmvRt9W+OU41aqPOu20Zsvn8dVFYbPB1xxFEVVH6/7qWVQjP9DZAk # JOP53JbK/Lisv/TCOVa4u+1zsxfdfoZQI4tWJMq7ph2ahy8nheehtgqcDRuM8wBi # QbpIdIeC/VDJ9IcpwwOqK98aKXnoEiSahu3QLtNAgfUHXzMGVF1AtfexYv1NSPdu # QUdSHLsbwlc6qJlWk9TG3iaoYHWGu+xipvAdBEXfPqeE0VtEI2MlNndvrlvcItUU # I2pBf9BCptvvJXsE49KWN2IGr/gbD46zOZq7ifU1BuWkW8OMnjdfU9GjN/2kT+gb # Dmt25LiPsMLq/XX3LEG3nKPhHgX+l5LLf1kDbahOjU6AF9TVcvZW5EifoyO6BqDA # jtGIT5Mg8nBf2GtyoyBJ/HcMXcXH4QIPOEIQDtsCrpo3HVCAKR6kp9nGmiVV/UDK # rWQQ6DH5ElR5GvIO2NarHjP+AucmbWFJj/Elwot0md/5kxqQHO7dlDMOQlDbf1D4 # n2KC7KaCFnxmvOyZsMFYXaiwmmEUkdGZL0nkPoGZ1ubvyuP9Pu7sCYYDBw0bDXzr # 9FrJlc+HEgpd7MUCks0FmXLKffEqEBg45DGjKLTmTMVSo5xqx33AcQkEDXDeAj+H # 7lah7Ou1TIUxghmaMIIZlgIBATCBkDB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMSMwIQYDVQQDExpNaWNyb3NvZnQgV2luZG93cyBQQ0EgMjAx # MAITMwAACWlp5VbrToP2TAAAAAAJaTANBglghkgBZQMEAgEFAKCBrjAZBgkqhkiG # 9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIB # FTAvBgkqhkiG9w0BCQQxIgQgmdWZtWrtMmV86JK3oFTVNDgU0WBqWLoOP9Jgp58W # pFgwQgYKKwYBBAGCNwIBDDE0MDKgFIASAE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0 # dHA6Ly93d3cubWljcm9zb2Z0LmNvbTANBgkqhkiG9w0BAQEFAASCAQBZ/EKd1C23 # RPRcxHU0jBG/PP3LdW8yPZOuSU79hvSVLwJQM/+yCnkqQbrpIq06H6EM2MzEk8I2 # 8Vu0+QJtXCTw9e4712Diu3czjM5QC0ralTt7xAz/dKaCo2FLJmnjdnCdi/HX9YxL # 9GMlTgOhY63bv8+x+t9ZxllMjJZQ6u2SBMIK+kETnLl0Q2gRAkXNLrFjc4G9dcTI # OyHa2uWhYphcexm4JbrCH6BqKMjSVzrOfIvi80UY4+3ug1YpGDdtvpvvgb9DNKMX # 7iuwlxzKYMOWxmbMBEDsfvEyWBizssaRnVB8wu81rXrlDfffy03c/lJgGGw180xO # r5n1queJIPN+oYIXKTCCFyUGCisGAQQBgjcDAwExghcVMIIXEQYJKoZIhvcNAQcC # oIIXAjCCFv4CAQMxDzANBglghkgBZQMEAgEFADCCAVkGCyqGSIb3DQEJEAEEoIIB # SASCAUQwggFAAgEBBgorBgEEAYRZCgMBMDEwDQYJYIZIAWUDBAIBBQAEIGd/EBW2 # KdCHXoOWVQpSgz168kH5h6pTTz7wuDluswkJAgZjovNmJRMYEzIwMjMwMTE4MDQz # OTEyLjIxNlowBIACAfSggdikgdUwgdIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlv # bnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046MkFENC00QjkyLUZB # MDExJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WgghF4MIIH # JzCCBQ+gAwIBAgITMwAAAbHKkEPuC/ADqwABAAABsTANBgkqhkiG9w0BAQsFADB8 # MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk # bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N # aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMjA5MjAyMDIxNTlaFw0y # MzEyMTQyMDIxNTlaMIHSMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0 # ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjJBRDQtNEI5Mi1GQTAxMSUwIwYD # VQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG9w0B # AQEFAAOCAg8AMIICCgKCAgEAhqKrPtXsG8fsg4w8R4MzZTAKkzwvEBQ94ntS+72r # RGIMF0GCyEL9IOt7f9gkGoamfbtrtdY4y+KIFR8w19/nU3EoWhJfrYamrfpgtFmT # aE3XCKCsI7rnrPmlVOMmndDyN1gAlfeu4l5rdxx9ODECBPdS/+w/jDT7JkBhrYll # qVXcwGAgWLdXAoUDgKVByv5XhKkbOrPx9qppuZjKm4nflmfwb/bTWkA3aMMQ67tB # oMLSsbIN3BJNWZdwczjoQVXo3YXr2fB+PYNmHviCcDUMHs0Vxmf7i/WSpBafsDME # n6WY7G8qtRGVX+7X0zDVg/7NVDLMqfn/iv++5hJGP+2Fmv4WZkBS1MBpwvOi4EQ2 # 5pIG45jWTffR4ynyed1I1SxSOP+efuBx0WrN1A250lv5fGZHCL0vCMDT/w+U6wpN # nxfDoQRY9Ut82iNK5alkxNozPP/DNI+nknTaSliaR2XnSXDIZEs7lfuJYg0qahfJ # J1CZF2IYxOS9FK1crEigSb8QnEJoj6ThLf4FYpYLTsRXlPdQbvBsVvgt++Bttooz # nwfK0DKMOc718SLS+unwkVO0aF23CEQSStoy0ZW34K+cbRmUfia+k9E+4luoTnT1 # 7oKqYfDNO5Rk8UwVa8mfh8+/R3fZaz2O/ZhiYT/RZHV9Quz5PHGlaCfXPQ8A6zFJ # lE8CAwEAAaOCAUkwggFFMB0GA1UdDgQWBBT0m2eR7w2thIr18WehUTSmvQ45kzAf # BgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQ # hk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQl # MjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBe # MFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2Nl # cnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAM # BgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQE # AwIHgDANBgkqhkiG9w0BAQsFAAOCAgEA2Oc3kmql5VKEitAhoBCc1U6/VwMSYKQP # qhC59f00Y5fbwnD+B2Qa0wnJqADSVVu6bBCVrks+EGbkuMhRb/lpiHNKVnuXF4PK # TDnvCnYCqgwAmbttdxe0m38fJpGU3fmECEFX4OYacEhFwTkLZtIUVjdqwPnQpRII # +YqX/Q0Vp096g2puPllSdrxUB8xIOx3F7LGOzyv/1WmrLyWAhUGpGte0W3qfX4YW # kn7YCM+yl887tj5j+jO/l1MRi6bl4MsN0PW2FCYeRbyzQEENsg5Pd351Z08ROR/n # R8z+cAuQwR29ijaDKIms5IbRr1nZL/qZskFSuCuSA+nYeMuTJxHg2HCXrt6ECFbE # kYoPaBGTzxPYopcuJEcChhNlWkduCRguykEsmz0LvtmS7Fe68g4Zoh3sQkIE5VEw # nKC3HwVemhK7eNYR1q7RYExfGFUDMQdO7tQpbcPD4oaBbtFGWGu3nz1IryWs9K88 # zo8+eoQV/o9SxNU7Rs6TMqcLdM6C6LgmGVaWKKC0S2DVKU8zFx0y5z25h1ZJ7X/Z # haav1mtXVG6+lJIq8ktJgOU5/pomumdftgosxGjIp3NORy9fDUll+KQl4YmN9GzZ # xPYkhuI0QYriLmytBtUK+AK91hURVldVbUjP8sksr1dsiQwyOYQIkSxrTuhp0pw7 # h5329jphgEYwggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZAAAAAAAVMA0GCSqG # SIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ # MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u # MTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkg # MjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU # aW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC # AgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4X # YDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTz # xXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7 # uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928jaTjkY+yOSxRnOlw # aQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3tpK56KTesy+uDRedG # bsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGaRnXN # xF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fzpk03 # dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9 # ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5 # UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReT # wDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZ # MBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8 # RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAE # VTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAww # CgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQD # AgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb # 186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29t # L3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoG # CCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZI # hvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9 # MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2Lpyp # glYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OO # PcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8 # DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmRsqlb30mjdAy87JGA # 0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8x1Rt # nWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjc # ZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq7 # 7EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJ # C4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328 # y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIC # 1DCCAj0CAQEwggEAoYHYpIHVMIHSMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz # aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv # cnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25z # IExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjJBRDQtNEI5Mi1GQTAx # MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYF # Kw4DAhoDFQDtZLG+pANsDu/LLr1OfTA/kEbHK6CBgzCBgKR+MHwxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU # aW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBBQUAAgUA53GyUzAiGA8yMDIz # MDExODA3NDgzNVoYDzIwMjMwMTE5MDc0ODM1WjB0MDoGCisGAQQBhFkKBAExLDAq # MAoCBQDncbJTAgEAMAcCAQACAhIXMAcCAQACAhFAMAoCBQDncwPTAgEAMDYGCisG # AQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMB # hqAwDQYJKoZIhvcNAQEFBQADgYEABP/aSkP6NOcRABr+RH0QpvPYOq2+gL9UBg7m # yxY3UuIo+7OhU8tzEQOfsrv+ejVO6UxtxswMcN0WqddD4dT2VrUQvh2wIJKR5eXb # Kso7dj+mlIxxeefWbuLFpQy+Vxst+8RqOKQkamRa649hI1eJ+VGQja9ooVl36Hq9 # fmnBaBwxggQNMIIECQIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz # aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv # cnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAx # MAITMwAAAbHKkEPuC/ADqwABAAABsTANBglghkgBZQMEAgEFAKCCAUowGgYJKoZI # hvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCC2jqqUQUlh+JaK # wsVfyrcqyt0ZxQ/UPsforMB6RRLqzDCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQw # gb0EIIPtDYsUW9+p4OjL2Cm7fm3p1h6usM7RwxOU4iibNM9sMIGYMIGApH4wfDEL # MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v # bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWlj # cm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAGxypBD7gvwA6sAAQAAAbEw # IgQgNwPn5DB7n6ghuHmxli8SVdAQ6UsqcumjhiHcHTWcCcgwDQYJKoZIhvcNAQEL # BQAEggIAGx64O3uFasdVmlBotVacF1WjIT4Qc2VXDN2IwyftgZ1HDv8KlRQr3hN4 # IAqw/QMByBpuAxXDsDH9sRoA1VtZRtP405FItCaGytu8mEgUNGEa9jTQjBJt1C+U # GQAWbCbvQzOKid+d3O8HhxeXdmatqgv4BiTRJnsAahjqMDFYxGqozs+4otM/jHnq # ru5b7QzeZHcMpR70wKYamuqDrJq3OscDAVfke+TPgAUnHWPImdemrXP6E8ttOFhH # ZYO17o4KNPFK2UlnFscGvCBAkxrU8UCDC8MlCIKn999noOB51aOQejHCl3v84Sre # D1z0VwuphKSv8ltbSqqZ0niLwQxjpFHQ8jdPwe7DTndp+nr0swK4DGVOcXJNhybP # QfUUZgEzwI+5QSACNn0NXiLD98XshaYd4+/3WvqFWRouLENDGRvZ9WFsrBQo4Nsl # sCA/1LB4Pp62P+UtBNG0W62rrWK1d4LzcHodMZItzfAV8kAWh9q7jDS3uybg5Bm8 # 3KFlbRqpPu1+a/3FVjk0BHVpjYU+q6DkI2ClQruESCBd9gfDpmIqOR7wn98cVGde # rHjObC74HEsovF8Udfxs8LzZS4fes0TYz/dHERu1HNhQlnzyUIA5pOCSibbgEE8q # e1nfBNV5oLAPFRVy4VCGgWnInxmj+OYS0NdJjw6wmm54UojePck= # SIG # End signature block