Centralized Desktop and Favorites with a Centralized My Documents?

What about Desktop and Favorites migration? Wouldn’t it be nice if there was a GPO that made the migration of your user’s Desktop and Favorites as easy as the migration of their My Documents? I think it would be nice. Since there isn’t, I created a script that would do the migration. This script should be run following a successful My Documents migration as the goal would be to put the files in the same location as the My Documents files.

When I first started the project, I was hoping that my script would run prior to showing the desktop. This is important because if it runs while the user has access to the desktop, that user may start using files that would prevent the script from running correctly (file locks). I had no luck; if anyone has an idea on how to do this, let me know. Otherwise, I created a .NET application that covers the entire screen on the primary monitor (if more than 1 monitor, then the second one is still visible).

BlankScreen

The BlankScreen application is written in VisualStudio .NET 2008 using .NET Framework 2.0 if I remember correctly. There are some changes you may want to make on this application to tailor it for your environment. The first change would be to put your logo on the application form. The second change, and really the more important change, is to change the ProcessPath variable to point to the UNC path of where you plan on putting the desktop.vbs file. This application just runs the VBScript.

So you might be thinking, why would you have an application that is capable of much more advanced programming run a VBScript? Well, I wrote the script first and didn’t feel like porting it to VB.NET. If you feel like spending the time, go for it.

desktop.vbs

Enough chatter about the other stuff, on to the real product of this blog post, the VBScript.

The VBScript has four basic functions that it completes one after the other based on the success of the previous function. Step 1 is to get the username of the logged in user. Step 2 is to create the folders in the user’s My Documents location and copy the files into that new folders (nothing is moved). Step 3 is to update the registry for the Desktop and Favorites locations to the newly created folders. Step 4 renames the old folders in the C:\Documents and Settings\[user]\ folder to DesktopOLD and FavoritesOLD. I feared losing user files, so I did not make the script perform anything that couldn’t be reversed.

Just as you had to change a string variable in the BlankScreen application for your specific server, you also have to change the location of your user’s folder on the network. In my case it was \\fileserver\users\.

The migration will change the registry keys:

HKCR\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders, Favorites
HKCR\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders, Desktop
HKCR\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders, Favorites
HKCR\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders, Desktop

The new locations will look something like this:

Desktop: \\[server]\[share]\[username]\Desktop-[username]
Favorites: \\[server]\[share]\[username]\Favorites-[username]
e.g. \\fileserver\users\aaron\Desktop-aaron\ would be my desktop folder.

Conclusion

Implementing this solution is fairly easy. First modify the VB.NET application and compile it. Place the .exe file in a shared location that your login script for users has permissions. Place the VBScript file in a similar location, as you specified in the VB.NET application, and modify the serverpath variable and email variables. Test with your user account in your login script batch file using something similar to below:

if %USERNAME% == yourusername (
 rem lets make sure the user has a my documents folder prior to trying to migrate their desktop
 if exist "\\[server]\Users\%USERNAME%" (
  if exist "C:\Documents and Settings\%USERNAME%\Desktop" (
   rem lets make sure they have the 2.0 Framework installed.
   if exist "C:\Windows\Microsoft.Net\Framework\v2.0*" (
    start "Desktop Migration" "\\[server]\[share]\blankscreen.exe"
   )
  )
 )
)

As a disclaimer, the application AND script are provided without any warranty and is only for educational / informational purposes. If you choose to use it in your environment, production or not, the outcome is your responsibility.

desktop.vbs Code

On Error Resume Next

'alert user of what is happening...
MsgBox "Please click OK to begin the backup process for your Desktop and Internet Explorer Favorites.  This process could take a few minutes, please be patient and Do NOT Cancel anything, otherwise data could be lost!" & vbCrLf & vbCrLf & "If you have Administrator privileges, your computer will restart after all of your files have been copied!"

'get the current user
user = getUser()
'set the server location, the following \ is required!
serverpath = "\\[server]\Users\"
'if you have a helpdesk solution with email capability:
useemailnotify = 0
smtpfrom = "email@domain.com"
smtpto = "email@domain.com"
smtpserver = "smtp.domain.com"

'create folders
m_cf = createFolderscopyFiles(user)
If m_cf <> 1 Then
	'update the registry and reboot
	m_ur = updateRegistry(user)
	If m_ur <> 1 Then
		'rename the old folders so it does not use them anymore!
		m_rof = renameOldFolders(user)
		'reboot
		Set WSHShell = WScript.CreateObject("WScript.Shell")
		WshShell.Run "C:\WINDOWS\system32\shutdown.exe -r -t 0"
	End If
End If

Function getUser()
	'get the current user environment variable.
	Set oShell = CreateObject( "WScript.Shell" )
	user = oShell.ExpandEnvironmentStrings("%UserName%")

	If Err.Number <> 0 Then
		'we have failure!
		getUser = 1
		Err.Clear
	Else
		getUser = user
	End If
End Function

Function createFolderscopyFiles(user)
	Set objFSO = CreateObject("Scripting.FileSystemObject")

	'lets only do the folder create and file copy if that folder doesn't already exist. Otherwise, its just gonna set the registry and reboot.
	If Not objFSO.FolderExists(serverpath & user & "\Desktop-" & user) Then
		'Create the new Desktop and the Favorites folder.
		objFSO.CreateFolder(serverpath & user & "\Desktop-" & user)
		objFSO.CreateFolder(serverpath & user & "\Favorites-" & user)

		Set oSHApp = CreateObject("Shell.Application")

		'Copy the Desktop files
		Set fromDFolder = oSHApp.Namespace("C:\Documents and Settings\" & user & "\Desktop")
		Set toDFolder = oSHApp.Namespace(serverpath & user & "\Desktop-" & user)
		toDFolder.CopyHere fromDFolder.Items, 16+512

		'Copy the Favorites files
		Set fromFFolder = oSHApp.Namespace("C:\Documents and Settings\" & user & "\Favorites")
		Set toFFolder = oSHApp.Namespace(serverpath & user & "\Favorites-" & user)
		toFFolder.CopyHere fromFFolder.Items, 16+512
	End If

	If Err.Number <> 0 Then
		'we have failure!
		SendEmail user,"failed at createFolderscopyFiles",Err.Description
		createFolderscopyFiles = 1
		Err.Clear
	Else
		createFolderscopyFiles = 0
	End If
End Function

Function updateRegistry(user)
	'lets work on the registry now
	Const HKEY_CURRENT_USER = &H80000001
	Const HKEY_LOCAL_MACHINE = &H80000002

	'update the registry for Desktop and Favorites (User Shell Folders)
	'set Favorites
	Set oFReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & "." & "\root\default:StdRegProv")
	strKeyPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
	strValueName = "Favorites"
	strValue = serverpath & user & "\Favorites-" & user
	oFReg.SetExpandedStringValue HKEY_CURRENT_USER,strKeyPath,strValueName,strValue
	'set Desktop
	Set oDReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & "." & "\root\default:StdRegProv")
	strKeyPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
	strValueName = "Desktop"
	strValue = serverpath & user & "\Desktop-" & user
	oDReg.SetExpandedStringValue HKEY_CURRENT_USER,strKeyPath,strValueName,strValue

	'update the registry for Desktop and Favorites (Shell Folders)
	'set Favorites
	Set otFReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & "." & "\root\default:StdRegProv")
	strKeyPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
	strValueName = "Favorites"
	strValue = serverpath & user & "\Favorites-" & user
	otFReg.SetStringValue HKEY_CURRENT_USER,strKeyPath,strValueName,strValue
	'set Desktop
	Set otDReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & "." & "\root\default:StdRegProv")
	strKeyPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
	strValueName = "Desktop"
	strValue = serverpath & user & "\Desktop-" & user
	otDReg.SetStringValue HKEY_CURRENT_USER,strKeyPath,strValueName,strValue

	If Err.Number <> 0 Then
		'we have failure!
		SendEmail user,"failed at updating registry",Err.Description
		updateRegistry = 1
		Err.Clear
	Else
		updateRegistry = 0
	End If
End Function

Function renameOldFolders(user)
	Set objFSO = CreateObject("Scripting.FileSystemObject")
	objFSO.MoveFolder "C:\Documents and Settings\" & user & "\Desktop", "C:\Documents and Settings\" & user & "\DesktopOLD"
	objFSO.MoveFolder "C:\Documents and Settings\" & user & "\Favorites", "C:\Documents and Settings\" & user & "\FavoritesOLD"

	If Err.Number <> 0 Then
		'we have failure!
		SendEmail user,"failed at renaming old folders",Err.Description
		renameOldFolders = 1
		Err.Clear
	Else
		renameOldFolders = 0
	End If
End Function

Sub SendEmail(user,contnt,contntB)
	'if the setting is to send an email, then do it, otherwise...nada.
	If useemailnotify = 1 Then
		'send an email!!
		Set objEmail = CreateObject("CDO.Message")
		objEmail.From = smtpfrom
		objEmail.To = smtpto
		objEmail.Subject = "Desktop and Favorites Migration Issue for " & user
		objEmail.Textbody = "User had a Desktop files migration error." & vbCrLf & vbCrLf & contnt & vbCrLf & vbCrLf & contntB
		objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
		objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = smtpserver
		objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
		objEmail.Configuration.Fields.Update
		objEmail.Send

		If Err.Number <> 0 Then
			'we have failure!
			MsgBox "Your Desktop migration didn't go very well."
			Err.Clear
		Else
			'YAY!
		End If
	End If
End Sub

Downloads

BlankScreen.zip – VB.NET application

desktop.zip – VBScript

About aaron

IT is not just a job but also a passion. Everything I have accomplished, both personally and professionally, has been generally entertaining, bordering on fun. Some of my projects, such as working with SharePoint Services workflow actions in Visual Studio or building a custom iSCSI SAN using the OpenSolaris, ZFS and COMSTAR, has been quite rewarding. You may think nerd...I think developing a new trend!