Monday, July 12, 2010

Windows 7 - Icons / Shortcuts Disappear from the Desktop

Have you seen my
shortcuts?! They’ve been missing since Windows 7! :-(




UPDATE: 2012-02-28 - Thanks to "Anonymous", the commenter, it has been pointed out that Microsoft has addressed this issue as of 2012-01-11 with a hotfix and registry setting. I'd imagine that it's only a matter of time and this issue is finally addressed in a mainstream patch.
"... After you install this hotfix, you can disable the "Broken Shortcut" task or the "Unused Desktop Icon" task in the System Maintenance troubleshooter by configuring the registry. Detailed steps are described in the "Registry information" section. ..."
http://support.microsoft.com/kb/2642357



We've been deploying Windows 7 for a few months now and we noticed that a few users initially complained that their shortcut icons have been randomly missing or somehow deleted off the desktop. We started putting back old copies of their shortcuts and, lo and behold, they would disappear again in about a week or so.

After digging around on the internet, we found the source of the problem to be the part of the Windows 7's System Action Center scripts. It turns out that the Desktop Cleanup Wizard is now part of the scheduled maintenance. "... The System Maintenance troubleshooter performs a weekly maintenance of the operating system. ... When there are more than four broken shortcuts on the desktop, the System Maintenance troubleshooter automatically removes all broken shortcuts from the desktop. ..." This is also along with unused icons.

Now, knowing the source of the problem, we dug further and found that the scheduled maintenance can be controlled by Active Directory’s GPO policies, but only in an Enable all/On or Disable all/Off fashion. It also turns out that many people have posted how to modify the files responsible for removing those desktop shortcuts, so that their function is disabled without interfering with the other features or causing any errors. We couldn't find a complete solution that would fit our needs. We’re a large orginization and there didn't seem to be an already published way to disable the remove shortcuts feature globally without disable all the features of System Maintenance Troubleshooter and/or manually going to each computer, editing the troubleshooter's power shell script files.

The last few days, I’ve poured through the discussion board posts via Google and brushed up on my VBs scripting skills, and the end result is I came up with a script file to launch via network login on each computer. The script patches the files responisble for removing the shortcuts only once and only if they exist (so, they won't error or annoy any other OS users). The script will also ask the user for UAC elevation to modify the protected files. The original files are backed up using the orginal file names, plus the date the script was run, and plus the '.original' as the file extension. The files modified are: “c:\Windows\diagnostics\scheduled\Maintenance\TS_BrokenShortcuts.ps1” and “c:\Windows\diagnostics\scheduled\Maintenance\TS_UnusedDesktopIcons.ps1”.

Post analysis of our problem described by users: They reported that the icons being deleted seemed to happened more often when they left the computer locked vs. on without being logged in and the shortcuts where to documents saved on mapped network drives vs. the local shortcuts. Your mileage may very as far as exact scenario. Any feedback on your troubles would be great! (Comment below)

So, what would the internet be if we all didn’t all share?! Below are the script we now use and your welcome to it. Just be warned, I warranty NONE of my script; Use my script at your own risk! Please leave my author tag. Thanks! : )

VBS Script (Just copy and paste the below text into notepad and save it as any_filename_you_desire.vbs)


'----------------------------------------------------------------------------------'
'' Disable the Windows 7 Broken Shortcuts and Unused Desktop Shortcuts Scripts    ''
''                                                                                ''
'' Description:  Open up the two power shell scripts responsible for repairing    ''
''  the broken shortcuts and removen unused one, and then stop them from          ''
''  running any longer.  The original files are backed up in the same location.   ''
''                                                                                ''
'' Author - Justin Bennett, 9:24 AM 6/30/2010                                     ''
''          jbennett at msjc d0t edu                                              ''
''                                                                                ''
'' Resources -                                                                    ''
''  http://www.ghacks.net/2010/03/30/fix-windows-7-desktop-shortcuts-disappearing ''
''           - http://www.winhelponline.com/articles/185/1/VBScripts-and-         ''
''                                                              UAC-elevation.html''
''                                                                                ''
''  !!!!!!!!!!!!!!!     NO WARRANTY EXPRESSED OR IMPLIED     !!!!!!!!!!!!!!!!!!   ''
'----------------------------------------------------------------------------------'
'
  'Continue on errors - needed for ...
  'On error resume next 
'
'
' START - Script
'
'
'
' Global Variables
set wshShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
'
'
'----------------------------------------------------------------------------------
''
'' START - Patch File Function
''
'' Description:  A function to check a file for existence, size, then replace the
''   line it has been instructed to.  The original file is backed up as
''   'filename.ext.1-1-1990 1.00.00 AM.original' in the original directory.
''
'' filePath - The file path of where the file is.  It is used for adding/removing
''             permissions durning the patching process to create the patched file
''             and backing up the original.
'' fileName - The file name of the file.  It is used making a patched copy of the
''             file and renaming the original file for a backup durning the patching
''             process.
'' reqdSize - The file size in bytes.  Used to verify the file is the correct size.
''             If the file size has changed, it will not be patched.
'' findLine - Which line to replace in the file.
'' replaceWith - The text to be written into the patched file.
''
  function patchFile(filePath, fileName, reqdSize, findLine, replaceWith)
   'Temporary Variables
   dim tmpFilename, curLine
  
   'Check if file exists
   If objFSO.FileExists(filepath&filename) <> True Then
    exit function
   End If
   
   'Check if file is the desired size
   If objFSO.GetFile(filepath&filename).Size <> reqdSize Then
    exit function
   End If
   
   'Check to see if UAC needs elevation
   uacCheck()
   
   'Add permission to modify/create files
   wshShell.Run "takeown /f "&filepath, 0, true
   wshShell.Run "takeown /f "&filepath&filename, 0, true
   wshShell.Run "icacls "&filepath&" /grant %USERNAME%:F", 0, true
   wshShell.Run "icacls "&filepath&filename&" /grant %USERNAME%:F", 0, true
   
   'Open main and temporary files  
   Set myFile = objFSO.OpenTextFile(filepath&filename, 1, True)
   Set myTemp= objFSO.OpenTextFile(filepath&filename&".patch", 2, True)
   
   'Loop through and find my line, then replace it
   curLine = 0
   Do While Not myFile.AtEndofStream
    curLine = curLine+1
    If curLine <> findline Then
  myTemp.WriteLine myfile.ReadLine
  'myFile.Skipline
 Else
  myFile.Skipline
  myTemp.WriteLine replaceWith
 End If
   Loop
   
   'Close the main and temporary files
   myFile.Close
   myTemp.Close
   
   'Temporary new filename
   tmpFilename = filepath&filename&"."&Replace(Replace(Now, ":", "."), "/", "-")&".orginal"
   'Rename input file to filename plus date and .orginal
   objFSO.MoveFile filepath&filename, tmpFilename
   
   'Rename temp file to input filename
   objFSO.MoveFile filepath&filename&".patch", filepath&filename
   
   'Remove granted permission to modify/create files
   wshShell.Run "icacls "&filepath&" /setowner ""nt service\trustedinstaller""", 0, true
   wshShell.Run "icacls "&filepath&filename&" /setowner ""nt service\trustedinstaller""", 0, true
   wshShell.Run "icacls "&tempFilename&" /setowner ""nt service\trustedinstaller""", 0, true
   wshShell.Run "icacls "&tempFilename&" /remove:g %USERNAME%", 0, true
   wshShell.Run "icacls "&filepath&filename&" /remove:g %USERNAME%", 0, true
   wshShell.Run "icacls "&filepath&" /remove:g %USERNAME%", 0, true

  end function
''
'' END - Patch File Function
''
'----------------------------------------------------------------------------------
''

'
' START - Main Subroutine
call main
'
sub main
'On error resume next 
'----------------------------------------------------------------------------------
''
'' START - Launch fix functions
''
''           
  patchFile wshShell.ExpandEnvironmentStrings("%windir%")&"\diagnostics\scheduled\Maintenance\", "TS_BrokenShortcuts.ps1", 2724, 22, "    return """" #removed $list to cancel out script"
  patchFile wshShell.ExpandEnvironmentStrings("%windir%")&"\diagnostics\scheduled\Maintenance\", "TS_UnusedDesktopIcons.ps1", 2567, 36, "    return """" #removed $list to cancel out script"
  
''
'' END - Launch fix functions
''
''
'
'
' END - Main Subroutine
end sub
'
'
'----------------------------------------------------------------------------------
''
'' START - UAC Check Function
''
''
  function uacCheck()
'''Check to make sure this is a Vista or 2008 server first
   strComputer = "."
   Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
   Set colOperatingSystems = objWMIService.ExecQuery _
    ("Select Caption from Win32_OperatingSystem Where Caption like '%Vista%' or Caption like '%2008%' or Caption like '%Windows 7%'")
   For Each objOperatingSystem in colOperatingSystems 
    If WScript.Arguments.length =0 Then
     Set objShelluac = CreateObject("Shell.Application")
     'Pass a bogus argument with leading blank space, say [ uac]
     objShelluac.ShellExecute "wscript.exe", Chr(34) &  WScript.ScriptFullName & Chr(34) & " uac", "", "runas", 1
     wscript.quit
    End If
   next
''
  end function
''
'' END - UAC Check Function
''
' END - SCRIPT



Here's how we're launching it from our batch network login script

::Disable Deleting Broken/Unused Shortcuts (Windows 7)
:: 12:55 PM 7/12/2010 Justin
::
if "%ALLUSERSPROFILE%"=="%SYSTEMDRIVE%\ProgramData" ( call cscript "\\domainname\netlogon\_patch_Windows_7_ScheduledMaint-Stop_Icons_Disappearing.vbs" )




References:
http://www.ghacks.net/2010/03/30/fix-windows-7-desktop-shortcuts-disappearing
http://www.winhelponline.com/articles/185/1/VBScripts-and-UAC-elevation.html
http://support.microsoft.com/kb/978980