[EDIT 01/13/2008] Please note that this article has been rewritten to accommodate changes found in Vista Service Pack 1 (SP1 RC1). For those revisiting this article, all references to hacking the registry with a mapped drive letter have been modified. Now the correct value to use is "%HomeShare%%HomePath%" - the attached script has been modified accordingly (although it could be further simplified to ignore drive letter verification now). [/EDIT]
This is a follow-up to my article Folder Redirection: Duplicate User Files Folders II where I suggest the use of the Folder Redirection GPO setting "Move the contents of ______ to the new location". This setting is important to prevent duplication of User File Folders, but can have other undesirable effects. It turns out that this setting can cause all sorts of bad folder redirection behavior when a user's redirected folders get moved from one network share to another. In this article I will discuss the triggers for the problem and possible solutions. I will also be providing a sample script that can help you avoid the problem entirely.
This article is only necessary if one uses the Folder Redirection GPO setting "Move the contents of ______ to the new location". If this setting is disabled, the problems described here don't occur. However, I think I made a very good case for using this setting in my previous article. This setting provides the valuable service of moving user data stored in local User File Folders to the new network locations defined in the Folder Redirection GPOs. Now one might think that Vista has a very sophisticated way of determining when it needs to move data - but in fact, it is really quite simple. Vista looks at registry keys in "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\Documents" There is one key per User File Folder that records it's storage location (i.e. Documents = "C:\Users\SRDTest5\Documents"). When Vista kicks off the folder redirection feature at logon time, it simply looks at the keys. If the storage location defined in the key is different than the one defined by the Folder Redirection GPO, Vista knows there has been a change. If the move setting is set, then Vista knows that it must move data from the old location specified in the registry to the new location specified by the GPO.
This may sound just fine -- it works great if we have local data that must get up to the network -- but Vista uses this same thought process if we are moving user data from one server to another. In this case the move setting isn't so good. The problem is that I don't know any self-respecting network administrator who would change the target location for the Folder Redirection GPO from a target such as \\ServerA\ShareA\SRDTest5\Documents to a target such as \\ServerB\ShareB\SRDTest5\Documents and then sit back and wait for Vista to move the data.
The Vista GPO seems to expect an administrator to follow this scenario:
- An administrator would leave the old target alone.
- Create an empty folder in the new location and set user permissions to it.
- The administrator would set the new target in the Folder Redirection GPO.
- The administrator would then wait for the user to eventually log on.
- The user finally shows up and logs on.
- Vista's Folder Redirection feature notices that the GPO target doesn't match the old target specified in the registry and springs into action!
- Vista holds up the logon process while it moves all data from the old location to the new location (How long does it take to copy a few hundred megabytes in your environment?).
- Eventually the data finishes copying and the user can get on with his life. (Somewhere in here the Offline Files feature will create a new partnership with the new target and sync up all the data as well.)
- A few weeks later our administrator checks on the user and sees that he has logged in and that the data has been moved. He then proceeds to remove the user's permissions from the old location -- and decommission the server if that was what he was planning.
I now present the scenario we would all expect (and which this article will help you attain):
- The administrator moves the user's folders from the old target to the new target.
- He sets the permissions on the new target and removes them from the old one.
- He tells the Folder Redirection GPO where to find the data (sets the new target).
- The administrator walks away and never gives the issue another thought.
- The user shows up weeks later and logs in without a care in the world. (Maybe he is particular bright and notices that the target path changed, but I doubt it.)
The user never receives any error messages at all. The best Vista does is to put errors in the application event log:
If the user is very aware, they might notice the Offline status being displayed at the bottom of each folder in Explorer - but I doubt they will. How long will the user work before noticing that their user files are no longer getting stored on the network and getting backed up properly? - a week? - a year? Perhaps only after their hard drive crash.
Want to see some other symptoms? Try implementing DFS where the target goes from pointing to the real physical UNC path to a aliased UNC DFS Link. In this case the data doesn't change location but Folder Redirection will be fooled into thinking it did. In this case Folder Redirection will attempt to copy files to themselves and error out again. Folder Redirection will again stay pointed to the old location. In this case it will be a valid path, so files will get stored on the network. But the Offline Files feature decides to disable itself for some reason. This becomes an interesting trap since an administrator will feel he can safely move servers hidden under a DFS link at any time without notifying the user community since they would never notice - but in this case Folder Redirection would break all over again as in the first scenario, but this time the user wouldn't have an Offline cache to fall back on. NASTY!!
What to do to avoid this problem...
I've already mentioned disabling the move feature to avoid the whole mess it creates. But that creates other problems equally problematic. I don't recommend this option.
It turns out you can turn off the Offline Files feature to avoid the problem. For some reason Folder Redirection is willing to adopt the new target location even when it encounters errors - so long as Offline Files isn't in the mix. Of course, laptops absolutely rely on this feature and I'm sure you will have many other valid reasons to want to keep Offline Files.
This leaves us with only one solution. It's cludgy, but it works. Trick Folder Redirection so it never notices the target change.
Remember how Folder Redirection recognizes a data move? It compares the target in the GPO against the target it has stored in the registry. Remember how in my article Folder Redirection: Specifying a target share we learned how to setup Basic Folder Redirection so we never have to change the target values in the GPO but rather just change paths in user AD profiles? Well, we can use the same trick on the registry! Let's use the Documents folder as an example... The GPO has a target set to "%HomeShare%%HomePath%Documents". Set the registry key to the exact same string. If you give a user's AD profile a new Home Path like "\\ServerB\ShareB\SRDTest5", the GPO will determine that the new target is "\\ServerB\ShareB\SRDTEst5\Documents" - the GPO will then check the registry to see if the target had changed since last time - but since the registry is now using the same variables, it will return the same path of "\\ServerB\ShareB\SRDTest5\Documents". Folder Redirection will have no clue anything happened. It won't attempt a move of the data - no errors will occur and no strange coping decisions will be made. Life will be calm and beautiful.
(I know this article has been a long one already.... please bear with me for a long explanation and a long script.)
You may feel that this doesn't offer much of a solution because you can't find or visit the registry of every affected user on every machine they may have a profile on in order to make this change. It turns out there is a nice labour saving trick if you lay the cards out right...
The main thing to do is to make sure that every user has a Home Path defined - as I described in Folder Redirection: Specifying a target share. You can put the variables in the various Folder Redirection registry keys like so: "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\Documents" = "%HomeShare%%HomePath%Documents"
Substituting variables for the UNC path is a simple generic change that can be made to all users at logon time through a logon script. Folder Redirection will continue to function during the user's session because the variables and real UNC path agree with each other and point to the exact same location.
Here's a sample VBScript that you can incorporate into your logon script. It will pull off the trick just discussed. It will run in any domain with any Folder Redirection scheme. It does assume that a drive letter and UNC path have been defined as the user's Home Path in his AD User Profile - if this is not the case then you will need to adjust the script.
(This script should be largely unreadable here, but if you highlight it, you can copy and past it into a text editor and save it as a .VBS file.)
'********************************************************************
' Vista Logon script by GordonPMartin@gmail.com, November 2007
'********************************************************************
' User Files Folders are redirected to the Home drive UNC path in Windows Vista
' To improve the user experience and solve an Offline file problem, the redirection must be
' reset to a drive letter at every logon...
' First we need to connect to Active Directory to collect information about the user's AD Profile...
Set objSysInfo = CreateObject("ADSystemInfo")
strUserDN = objSysInfo.UserName
strUserDN = Replace(strUserDN, "/", "\/") ' Microsoft AD uses "/" as a delimiter - any occurrances of it must be prefaced by a "\"
Set objLDAPUser = GetObject("LDAP://" & strUserDN) ' This is our LDAP handle to AD info about the current user
' Time to collect information about the user's home paths.
blnHomeDrive = False ' Flag tracks if we have a valid home drive
strMessage = "No Home Drive defined in the user's AD profile." ' Default error message
If objLDAPUser.HomeDrive > "" then ' The user has a home drive defined
strHomeMapping = ""
strHomeDrive = UCase(Left(Trim(objLDAPUser.HomeDrive),1)) ' Here is the home drive's letter
strHomeDirectory = UCase(Trim(objLDAPUser.HomeDirectory)) ' Here is the UNC path of the user's home directory
strHomeFolder = strHomeDrive & ": = " & strHomeDirectory
' Let's ensure that any Home Folder that has been defined in AD was actually mapped...
Set objFSO = CreateObject("Scripting.FileSystemObject")
For Each objDrive In objFSO.Drives ' Let's look at all mappings to find the one that we need...
if objDrive.DriveLetter = strHomeDrive then
' wscript.echo objDrive.DriveLetter & objDrive.DriveType & objDrive.ShareName
if Ucase(objDrive.ShareName) = strHomeDirectory then
blnHomeDrive = True ' The mapped U: drive matches the defined one! (yay)
else
strHomeMapping = objDrive.ShareName ' It isn't mapped correctly - record the current path so we can report it
end if
end if
Next
If blnHomeDrive Then
strMessage = "Valid home folder: " & strHomeFolder & vbCRLF & vbCRLF
Else
strMessage = "Missing Home Folder: " & strHomeFolder & vbCRLF
strMessage = strMessage & "It is currently: " & strHomeDrive & ": = " & strHomeMapping & vbCRLF& vbCRLF
End If
End If
' If we have a valid home drive mapping, we can proceed to work on the Folder Redirection paths...
If blnHomeDrive then
strKey = "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" ' The area of the registry to play in
' Load an array with the 13 User Files Folders that might be getting redirected...
' (0 = display name, 1 = registry key, 2 = desired folder path)
Dim arrUserFolders(16,2)
' (0,x) has been intentionally left blank ;-)
arrUserFolders(1,0) = "AppData Roaming"
arrUserFolders(1,1) = "\AppData"
arrUserFolders(1,2) = "AppData"
arrUserFolders(2,0) = "Contacts"
arrUserFolders(2,1) = "\{56784854-C6CB-462B-8169-88E350ACB882}"
arrUserFolders(2,2) = "Contacts"
arrUserFolders(3,0) = "Desktop"
arrUserFolders(3,1) = "\Desktop"
arrUserFolders(3,2) = "Desktop"
arrUserFolders(4,0) = "Documents"
arrUserFolders(4,1) = "\Personal"
arrUserFolders(4,2) = "Documents"
arrUserFolders(5,0) = "Downloads"
arrUserFolders(5,1) = "\{374DE290-123F-4565-9164-39C4925E467B}"
arrUserFolders(5,2) = "Downloads"
arrUserFolders(6,0) = "Favorites"
arrUserFolders(6,1) = "\Favorites"
arrUserFolders(6,2) = "Favorites"
arrUserFolders(7,0) = "Links"
arrUserFolders(7,1) = "\{BFB9D5E0-C6A9-404C-B2B2-AE6DB6AF4968}"
arrUserFolders(7,2) = "Links"
arrUserFolders(8,0) = "Music"
arrUserFolders(8,1) = "\My Music"
arrUserFolders(8,2) = "Music"
arrUserFolders(9,0) = "Pictures"
arrUserFolders(9,1) = "\My Pictures"
arrUserFolders(9,2) = "Pictures"
arrUserFolders(10,0) = "Saved Games"
arrUserFolders(10,1) = "\{4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4}"
arrUserFolders(10,2) = "Saved Games"
arrUserFolders(11,0) = "Searches"
arrUserFolders(11,1) = "\{7D1D3A04-DEBB-4115-95CF-2F29DA2920DA}"
arrUserFolders(11,2) = "Searches"
arrUserFolders(12,0) = "Start Menu"
arrUserFolders(12,1) = "\Start Menu"
arrUserFolders(12,2) = "Start Menu"
arrUserFolders(13,0) = "Videos"
arrUserFolders(13,1) = "\My Video"
arrUserFolders(13,2) = "Videos"
' That takes care of the main 13 folders that get redirected. Now here are some more that seem relevant...
arrUserFolders(14,0) = "Administrative Tools"
arrUserFolders(14,1) = "\Administrative Tools"
arrUserFolders(14,2) = "Start Menu\Programs\Administrative Tools"
arrUserFolders(15,0) = "Programs"
arrUserFolders(15,1) = "\Programs"
arrUserFolders(15,2) = "Start Menu\Programs"
arrUserFolders(16,0) = "Startup"
arrUserFolders(16,1) = "\Startup"
arrUserFolders(16,2) = "Start Menu\Programs\Startup"
' Process each of the User Files Folders in the array...
Set objShell = WScript.CreateObject("WScript.Shell")
for intFolder = 1 to 16
strCurrent = objShell.RegRead (strKey & arrUserFolders(intFolder, 1)) ' Get the path from the registry
If Left(strCurrent, 2) = "\\" then ' We have a UNC path! The folder is being redirected!
' Do the drive letter substition...
' strSubstPath = strHomeDrive & ":\" ' This is the pre-SP1 version where we substituted a drive letter
strSubstPath = "%HomeShare%%HomePath%" ' This is the post-SP1 version where we substitute variables that get evaluated at logon time
If Right(objEnvProcess("HomePath"), 1) <> "\" then strSubstPath = strSubstPath & "\" ' We need one backslash at the end (no more, no less)
objShell.RegWrite strKey & arrUserFolders(intFolder, 1), strSubstPath & arrUserFolders(intFolder, 2)
' wscript.echo strKey & arrUserFolders(intFolder, 1) & vbcrlf & strHomeDrive & ":" & arrUserFolders(intFolder, 2)
' Check the registry again to ensure that the new setting is there
strCurrent = objShell.RegRead (strKey & arrUserFolders(intFolder, 1))
End If
' Report the paths to the user
strMessage = strMessage & arrUserFolders(intFolder, 0) & " directed to " & strCurrent & vbcrlf
Next
End if
wscript.echo strMessage
I should mention that this script will only modify User Shell Folders that have been redirected to a UNC path. It will not affect users who have local User Files Folders. You can safely deploy a version of this script to all users in your organization.Obviously the ideal solution to all of this is for Microsoft to fix the Folder Redirection feature. It wouldn't take much. I think a simple addition of one more setting in the Folder Redirection GPO would do the trick. The GPO should have a setting to determine how to treat new accounts or local data - something like "Move local User File Folders to the network". If the current move setting was to only apply to UNC path changes where both paths are network paths, it would fix everything. We could use the local setting to make sure we get all user data up to the network (avoiding duplicate folders) but at the same time choose to have no data moved when a server-to-server data move occurs. Are you listening Microsoft?
Thanks for slogging through this long article with me. Please share any interesting behaviours you may encounter.