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.
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
I used the Custom Range with an estimated start/end date of when the problem occurred.
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.
When you choose a lot of event logs you get a warning. But if you’ve limited the time period it should be OK.
You can save your filter for frequent use, even categorize by folders if necessary.
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
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.
One I found was called Diagnosis
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.
From the General Tab we can see how this runs:
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.
Conditions tab in addition shows us some important points for when the task gets started:
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.
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
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…
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)
Then using right side Action menu in Task Scheduler hit Run to run the Task.
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
I selected a sdiagnhost.exe event then hit Ctrl+R to reset filter, followed by right-clicking sdiagnhost.exe and selecting Include ‘sdiagnhost.exe’
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
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
But this didn’t bring me to the folder, because the folder had been deleted. It just opened up my profile folder.
But I then did a file search for the filename under C:\WINDOWS
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
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 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 |
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 |
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 4) Checks each time server if pingable using command ping.exe $timeServer /n 2 w32tm.exe 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\ 2) If machine is not Domain Joined and HKLM:\SYSTEM\CurrentControlSet\ |
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 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% 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 |
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:
- Click Start and then click Control Panel.
- Under System and Security, click Find and fix problems.
- On the left navigation pane, click Change settings.
- 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
b) Select the current logged in user and click Permissions
c) Untick Include inheritable permissions fromt his object’s parent
d) In the prompt Warning: If you proceed blah blah blah click Add
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.
However I could still delete the shortcut. Clicking Effective Permissions and no delete was to be found.
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
b) For location of item specify C:\windows\explorer.exe “network share”
c) Give it a friendly name
d) A shortcut that won’t get deleted. I hope!
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
}
}
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.
One final point: If you create a subfolder on the desktop, the icons inside the folder won’t get touched.
Pingback: Windows 7 Default Scheduled Tasks–Complete Overview | chentiangemalc
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
I really like your wp web template, where do you get a hold
of it from?
it is available from wordpress.com, freely available.
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
Yes! Finally something about whatsapp en espaque significa.
Very nice work. Thanks.