Case of the Missing Desktop Shortcut Icons

On Windows 7 a user was reporting their desktop icons kept disappearing, but only specific ones. Each time they got re-created they kept disappearing randomly on Monday mornings.

Initial investigation started with the Event Log, and having an approximate time period assists. Windows 7 Event Viewer is far superior to that of Windows XP. One thing in Windows 7 is I usually check the initial summary screen to see if I find anything of interest. This is a very useful feature. Clicking on an event here will take you to all events of that type.

image

However it was not immediately obvious a cause so I set a filter on the date the problem occurred. I used the right column Create Custom View

image

I used the  Custom Range with an estimated start/end date of when the problem occurred.

image

I chose all the logs, but if you are looking at specific applications you can limit this further. In Windows 7 there are many very specific event logs, more so show up in Event Viewer than in XP.

image

When you choose a lot of event logs you get a warning. But if you’ve limited the time period it should be OK.

image

You can save your filter for frequent use, even categorize by folders if necessary.

image

I saw a lot of TaskScheduler events going and thought this is probably a good thing to filter on, so I updated the filter using Filter Current Custom View

image

This time I selected a more specific event log. You should know these on Windows 7 there are many lifesavers here. The one for Task Scheduler is under Application and Service Logs –> Microsoft –> Windows –> TaskScheduler –> Operational

I also filtered by Event ID 102 which is Task Completed.

image

One I found was called Diagnosis

image

I then went to Task Scheduler, another MMC Snap-In that is vastly improved over the one in Windows XP. OK scheduled for Weekly on Sundays looks like good chance of culprit here.

image

From the General Tab we can see how this runs:

image

Key points here:

  • It runs as INTERACTIVE – that is it runs as the logged in user account
  • Only runs when user is logged on
  • It will elevate to admin privilege if the logged in user is member of local administrators
  • The task is Hidden –> This does not have much effect, Hidden tasks are shown in Task Scheduler by default. But you can switch it off by deselecting View –> Show Hidden Tasks

Looking at the trigger we can see what sets it off. Triggers here in Windows 7 are much more powerful than available through XP Task Scheduler GUI. If you have not explored the capabilities of Windows 7 here you should.

image

Conditions tab in addition shows us some important points for when the task gets started:

image

The final important point is the Settings tab. Good thing to know if this task has been running for 3 days it will get stopped automatically. But another important point is Run task as soon as possible after a scheduled start is missed.

image 

But how to diagnosis what this script does, when I look in the Actions tab it just said Custom Handler. There was no way to get any info about what process launched, etc. To get this information for the in-built scheduled tasks I first exported the event as XML

image

Viewing the XML we see section

<Actions Context=”Users”>
  <ComHandler>
    <ClassId>{C1F85EF8-BCC2-4606-BB39-70C523715EB3}</ClassId>
  </ComHandler>
</Actions>

So I immediately checked HKCR\CLSID\{C1F85EF8-BCC2-4606-BB39-70C523715EB3}

Here we found a .DLL file. But we can’t execute that directly…image

This time I started ProcMon (http://live.sysinternals.com/ProcMon.exe) and set a filter on Details Contains sdiag then Include (This filter may not work in all cases, if not filter by path contains and the above CLSID, then trace events that follow)

image

Then using right side Action menu in Task Scheduler hit Run to run the Task.

image

Once again ProcMon comes to the party with some beautiful results…I smell a solution not far off. Looking through the sequence of events we see the .exe that gets launched: sdiagnhost.exe

image\

I selected a sdiagnhost.exe event then hit Ctrl+R to reset filter, followed by right-clicking sdiagnhost.exe and selecting Include ‘sdiagnhost.exe’

image

Looking through the log I noticed it is launching .ps1 scripts, which are PowerShell cmdlets. Adding a filter Path ends with .ps1 we found them

image

OK! Pretty sure I found what I’m looking for here. TS_BrokenShortcuts.ps1. So I right clicked the Path and clicked Jump To… to display it in Explorer

image

But this didn’t bring me to the folder, because the folder had been deleted. It just opened up my profile folder.

image

But I then did a file search for the filename under C:\WINDOWS

So I found the file here image

Looking at the directory structure we can see this is something based on the Windows Troubleshooting Framework.  Your own Troubleshooters can be built using the Windows 7 SDK. Details about creating Troubleshooting packs can be found here: http://msdn.microsoft.com/en-us/library/dd776530.aspx

image

Some key components of a Windows Troubleshooting Package include:

File Purpose
DiagPackage.diagpkg .XML file describing contents of the Troubleshoot package.

Includes information such as Troubleshooter Name, Required PowerShell Version, Required OS Version, etc

PowerScripts to identify issues are defined in <Troubleshooter></Troubleshooter> tags. Scripts to resolve issues are defined in <Resolver></Resolver> tags. Scripts to verify issues are resolved are defined in <Verifier></Verifier> tags. Typically these are the same as the troubleshooter scripts, but they can be different.

DiagPackage.dll Contains resource strings for the Trouble shooter. Also will use files in locale specific directory i.e. \en-us\ etc
CL_Utility.ps1 Typically used in all the Microsoft Troubleshooter scripts, this is just library of functions used by all scripts in that specific troubleshooter.
TS_*.ps1 The troubleshooter scripts. These may return values using a command like Update-DiagRootCause -id “RC_BrokenShortcuts” -Detected $true

The  Resolver scripts then use this information to determine whether an issue requires fixing.

RS_*.ps1 The resolver scripts. These check for root causes configured by TS_*.ps1 scripts and will attempt to fix them.

There are many such Troubleshooting scripts inbuilt to Windows 7, just search the Windows directory to find a treasure trove of PowerShell script samples. Looking at the .diagpkg XML file we can find the following steps in the process (note: I made these notes by quickly reviewing the scripts, if I made any error in analysis let me know):

Trouble-shooter Resolver
TS_BrokenShortcuts.ps1

1) Checks Desktop for broken shortcuts
2) Checks Start Menu Startup Path for broken shortcuts
3) Checks ability to delete shortcuts before adding them to the broken shortcut list.
3) If the total of broken Startup Shortcuts + Broken Desktop Shortcuts exceed 4 the root cause RC_BrokenShortcuts is set to true.
RS_RemoveShortcuts.ps1

If root cause RC_BrokenShortcuts is set to true the following actions are taken:

1) Broken shortcuts in Desktop folder are deleted
2) Broken shortcuts in Startup folder are deleted

Items are deleted using

Remove-Item [filename] –Force

Because –Force is used setting the files to Read only will not prevent them from being deleted.

TS_UnusedDesktopIcons.ps1

1) Looks at all shortcuts that haven’t been access in 3 months or longer
2) If there are more than 10 such shortcuts the root cause RC_UnusedDesktopIcons is set to true.

RS_RemoveUnusedDesktopIcons.ps1

If RC_UnusedDesktopIcons is set to true:

1) Provide list of files and last access time to users to confirm if they should be deleted
2) Delete selected files

TS_VolumeErrors.ps1

This script is an example of using inline C# in a PowerShell script and calling Windows API using Interop.

1) Loop through all Device_ID from Win32_LogicalDisk WHERE MediaType=12
2) On each volume use Kernel32!DeviceIoControl with FSCTL_IS_VOLUME_DIRTY option to determine if volume is dirty. If it is set root cause RC_VolumeErrors to True

None
TS_InaccurateSystemTime.ps1

1) Checks if w32time service is disabled, if so exits
2) Checks if w32time service is started, if not starts it
3) Attempts to retrieve time server using command

w32tm.exe /query /source

If the w32tm.exe exits with a value other than 0 this script exits.

4) Checks each time server if pingable using command

ping.exe $timeServer /n 2

5) If time server is pingable checks accuracy using command

w32tm.exe
/stripchart /computer:$timeServer
/dataonly /samples:1

Checks for inaccurate samples, if they’re not right details are added to log and RC_InaccurateSystemTime is set to true.

6) If this failed will check time against time.windows.com

RS_SyncSystemTime.ps1

If RC_InaccurateSystemTime is set to true:

1) If machine is Domain Joined set and HKLM:\SYSTEM\CurrentControlSet\
Services\W32Time\Parameters\Type
is set to NoSync then update
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\
Services\W32Time\Parameters\Type
to NT5D5. Restart W32time service followed by running command w32tm.exe /resync /rediscover

2) If machine is not Domain Joined and HKLM:\SYSTEM\CurrentControlSet\
Services\W32Time\Parameters\Type
is set to NoSync then update
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\
Services\W32Time\Parameters\Type
to NTP. Restart W32time service followed by command w32tm.exe /config /update
/manualpeerlist:”time.windows.com
followed by w32tm.exe /resync /force

TS_WERQueue.ps1

1) Check free disk space
2) Retrieves maximum queue size % from
HKLM:\SOFTWARE\Microsoft\Windows\
Windows Error Reporting\
MaxQueueSizePercentage

Default value of this key is 1. If this key is not set 100% will be allowed.

2) Check size of %LOCALAPPDATA%\Microsoft\Windows\WER\ReportQueue
(User Queue)
3) Check size of %ALLUSERSPROFILE%
\Microsoft\Windows\WER\ReportQueue
(Machine Queue)
4) If free disk space + size of user queue is greater than 0 and maximum % of queue size is greater than 0 perform the calculation:

if (user queue size / (free space + user queue size) * 100) is greater than maximum queue size % root cause RC_WERQueue is set to True.

5) If free disk space + size of machine queue is greater than 0 and maximum % of queue size is greater than 0 perform the calculation:

if (machine queue size / (free space + machine queue size) * 100) is greater than maximum queue size % root cause RC_WERQueue is set to True.

RS_MachineWERQueue.ps1

If C_WERQueue is set to True.

1) Checks each sub folder of

%ALLUSERSPROFILE%
\Microsoft\Windows\WER\ReportQueue

If the size is greater than value in

HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\

PurgeThreshholdValueInKB

(default is 10 KB)

then the file is deleted..

This continues until the correct % queue size of free disk space is reached.

RS_UserWERQueue.ps1

Same as above, except folder is
%LOCALAPPDATA%\Microsoft\Windows\WER\ReportQueue

TS_DiagnosticHistory.ps1

1) Retrieves size of User Diagnostic Folder:

%localappdata%\diagnostics

2) Retrieves size of Admin Diagnostics Folder:

%localappdata%\elevateddiagnostic

3) Checks above folders  for subfolders older than one month. If they are found it sets the root cause RC_DiagnosticHistory to true

RS_UserDiagnosticHistory.ps1

If RC_DiagnosticHistory is true then deletes subfolders older than 1 month in %localappdata%\diagnostics

RS_AdminDiagnosticHistory.ps1
Same as above except
%localappdata%\elevateddiagnostic

OK so now apologies if there was any information overload. But how do we solve the problem of the missing shortcut?

Well if we had started our search on http://support.microsoft.com we would have found the solution from Microsoft http://support.microsoft.com/kb/978980

Now to summarize the Microsoft solution;

1) Keep the number of broken shortcuts on your desktop to four or less.

2) If you must have more than four broken shortcuts on your desktop, you can disable the System Maintenance troubleshooter.

Instructions for disabling it are:

  1. Click Start and then click Control Panel.
  2. Under System and Security, click Find and fix problems.
  3. On the left navigation pane, click Change settings.
  4. Set Computer Maintenance to Off.

OK – but wait? What about all the useful stuff system maintenance does? And what about my shortcuts? I still need them on my Desktop?

1) How about patching the scripts to not remove Desktop icons?

Unless Microsoft fixes this, I would not recommend modifying the inbuilt scripts (if you can, and it still runs ok) If Windows Updates occur etc, there might be possibility your scripts got overwritten, etc. Not a good idea to mess with stuff built into the OS. (except for fun)

2) Disable Computer Maintenance, copy the scripts to a new location, and just patch the desktop icon script. Create a new task scheduler event.

Yes, this would be possible, but a lot of effort & hacks required. Also if the Windows one got improvements, you wouldn’t get them.

3) I think at the moment if the two Microsoft suggestions don’t cut it the best option is to try:

Option 1

Modify the security permissions to ensure the current user does not have delete permission on the file.

This can be done as follows.

a) Right click the Desktop shortcut and click Properties, then click Advanced

image

b) Select the current logged in user and click Permissions

image

c) Untick Include inheritable permissions fromt his object’s parent

image

d) In the prompt Warning: If you proceed blah blah blah click Add

image

e) Set Delete permission to Deny. However keep in mind that in general it is never recommended to set Deny because using Deny often makes troubleshooting permissions issues later on. In any case it will be important to allow user to know once changing these permissions they cannot delete this shortcut, until they add back the Delete permission.

image

image

However I could still delete the shortcut. Clicking Effective Permissions and no delete was to be found.

image

So then I reset a filter in ProcMon with Path contains Dilbert – Shortcut.lnk. And I deleted the .lnk file. And no events in ProcMon. Even enabled Advanced Output, nothing.

OK either I’m up way too late or .lnk files completely bypass normal file operations and NTFS permissions. (Honestly it was the first time I’d ever tried to set permissions on them)

So Option 1 was a false alarm, turned out not to be a solution at all.

But don’t worry still came up with something:

Option 2

a) Right click on Desktop New  –> New Shortcut

image

b) For location of item specify C:\windows\explorer.exe network share”

image

c) Give it a friendly name

image

d) A shortcut that won’t get deleted. I hope!

image

Now to double test this I disconnected my network and ran a script, based off the Microsoft one, to check for invalid links to see if my new link would show up as invalid.

The program reported

Checking Desktop Icons…
Valid Link: d:\users\mccafferym\desktop\dilbert comic relief.lnk
I can delete this file: d:\users\mccafferym\desktop\dilbert comic relief.lnk

Which is good: because it’s valid it’ll never get deleted. And no permissions hacking either. Or disabling our friendly diag schedule.

The only bizarre consequence of this type of shortcut is that if you try to open it when there is no network connectivity to the server you don’t get an error message or anything. Nothing…and then about 30 seconds later My Documents pops up.

Hmm. So it’s not perfect.

Replacing Explorer.exe with Iexplore.exe works as well, but if you don’t have connectivity to the server you’ll get your homepage instead.

If you find any better solutions let me know. Now it’s 2:00 am and I think sleep might be a good idea.

P.S I did end up creating a shortcut I couldn’t delete, but it also crashed explorer whenever I clicked on it.

Finally The PowerShell code to check links on desktop if they’ll get deleted.:

# Function to convert to WQL path
function ConvertTo-WQLPath([string]$wqlPath = $(throw “No WQL path is specified”))
{
    if($wqlPath -eq $null)
    {
        return “”
    }

    return $wqlPath.Replace(“\”, “\\”)
}

# Function to get desktop path
function Get-DesktopPath()
{
$methodDefinition = @”
    public static string GetDesktopPath
    {
        get
        {
            return Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
        }
    }
“@

    $type = Add-Type -MemberDefinition $methodDefinition -Name “DesktopPath” -PassThru

    return $type::GetDesktopPath
}

# Function to check whether the shortcut is valid
function Test-ValidLink([Wmi]$wmiLinkFile = $(throw “No WMI link file is specified”))
{
    if(($wmiLinkFile -eq $null) -or ([String]::IsNullOrEmpty($wmiLinkFile.Target)))
    {
        return $false
    }

    return Test-Path $wmiLinkFile.Target
}

# Function to chech whether have permission to delete the shortcut file
function Test-Delete([Wmi]$wmiLinkFile = $(throw “No WMI link file is specified”))
{
    if($wmiLinkFile -eq $null)
    {
        return $false
    }

    return ($wmiLinkFile.AccessMask -band 0x10000) -eq 0x10000
}

“Checking Desktop Icons…”

[string]$desktopFolderPath = Get-DesktopPath

Get-ChildItem -Path $desktopFolderPath -filter *.lnk | Foreach-Object {
    $fullPath = ConvertTo-WQLPath $_.FullName
    $wmiLinkFile = Get-WmiObject -query “SELECT Name,Target,AccessMask FROM Win32_ShortcutFile WHERE Name = ‘$fullPath'”

    if (Test-ValidLink $wmiLinkFile)
    {
          “Valid Link: ” + $wmiLinkFile.Name
    }
    else
    {
        “Invalid Link: ” + $wmiLinkFile.Name       
    }
   
    if(Test-Delete $wmiLinkFile)
    {
       “I can delete this file: ” + $wmiLinkFile.Name
    }
    else
    {
        “CANT DELETE: ” + $wmiLinkFile.Name
    }
}

About chentiangemalc

specializes in end-user computing technologies. disclaimer 1) use at your own risk. test any solution in your environment. if you do not understand the impact/consequences of what you're doing please stop, and ask advice from somebody who does. 2) views are my own at the time of posting and do not necessarily represent my current view or the view of my employer and family members/relatives. 3) over the years Microsoft/Citrix/VMWare have given me a few free shirts, pens, paper notebooks/etc. despite these gifts i will try to remain unbiased.
This entry was posted in PowerShell, ProcMon, Scripting, Troubleshooting, Windows 7 and tagged . Bookmark the permalink.

10 Responses to Case of the Missing Desktop Shortcut Icons

  1. I don’t see why you would need to even mention XP in this article. Why the XP bashing?

    • Not bashing XP, praising Windows 7. The reason I mention it is because I see many support staff used to Windows XP not taking advantage of the new functionality in Windows 7 that makes support so much easier. Once familiar with all the advantages of Windows 7 from a support perspective you will not want to see XP around. Not because XP is bad. Because Windows 7 is vastly superior is so many ways.

  2. One final point: If you create a subfolder on the desktop, the icons inside the folder won’t get touched.

  3. Pingback: Windows 7 Default Scheduled Tasks–Complete Overview | chentiangemalc

  4. Anon12345 says:

    For Win7 SP1
    Install Direct Hotfix links:

    http://hotfixv4.microsoft.com/Windows%207/Windows%20Server2008%20R2%20SP1/sp2/Fix385439/7600/free/441240_intl_i386_zip.exe

    http://hotfixv4.microsoft.com/Windows%207/Windows%20Server2008%20R2%20SP1/sp2/Fix385439/7600/free/441224_intl_x64_zip.exe

    THEN
    make and run somethingsomething.reg:

    Windows Registry Editor Version 5.00

    [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\ScheduledDiagnostics]
    “IsBrokenShortcutsTSEnabled”=dword:00000000
    “IsUnusedDesktopIconsTSEnabled”=dword:00000000

  5. boyssweatpants.org says:

    I really like your wp web template, where do you get a hold
    of it from?

  6. Bernard says:

    Hello there, I scripted that so that I don’t have to do this again :
    Takeown /f C:\Windows\diagnostics\scheduled\Maintenance\TS_BrokenShortcuts.ps1 /A
    icacls c:\windows\diagnostics\scheduled\Maintenance\TS_BrokenShortcuts.ps1 /grant Administrators:F
    (Get-Content C:\windows\Diagnostics\Scheduled\Maintenance\TS_BrokenShortcuts.ps1) | Foreach-Object {$_ -replace “4”, “100”} | Set-Content C:\windows\Diagnostics\Scheduled\Maintenance\TS_BrokenShortcuts.ps1

    At line 2, the user group is dependant of your system language…

    regards

  7. apps of android says:

    Yes! Finally something about whatsapp en espaque significa.

  8. Stephen says:

    Very nice work. Thanks.

Leave a comment