(Apologies to regulars, this is not an interesting post!)IntroductionNow that I've finally managed to do it, my blogging self can't resist the temptation to explain how (in the vein of the unreasonably popular
headlamp post).
If you search for this subject, pretty much all paths lead or refer to the same
web page on Joshua Mouch's blog, where there is a fairly comprehensive step-by-step how to. However, reading through the (pages of) comments, I noted that there were some unhandled issues with 'symbolic links'. Which is where this post comes in.
Disclaimer(Read this stuff, it's not your usual yada-yada.)- This
seems to have worked for me, but I've only been running it for couple of days.
- I'm running Vista Home Premium, in French.
- I did this on a new machine, soI had zero data or configuration to lose.
- If you have no way of restoring your system if things go pear-shaped, or you don't trust it enough to test it, venture no further.
- If anything goes wrong, you're on your own, I'm a programmer, not an IT specialist (I had to start over at least 5 times)
- The 'solution' I found involved complications which may not exist on other systems, I've included the extra detail here, which you will have to wade through.
- This post is loooong, sorry. And no pictures (except the totally unrelated introductory picture).
- Broadly-speaking there are three ways of doing this, I only explain one here.
-
UPDATE: Upon reflection, I realise why doing this may NOT be a good idea. The plan was to be able to backup and restore the system and data separately. The problem is that the Users folder contains both data AND system stuff. And now that I've got the Users folder on another partition, I can't back it up with the system, which means that if I ever have the disk go down, I'm going to have trouble restoring the users configuration. Ho-hum,
MirrorFolder is probably going to be the solution...
Nitty-grittyYou could just skip this bit and go to the instructions, but one is generally well advised to understand what is going on. I do provide a script to automate a part of the grunt work, but it doesn't 'just work' without help.
The basic problem/question is how do I get the Users folder on another drive/partition in Windows Vista? (If you've got to here and you're wondering why anyone would want to do that, you must be really bored!) For me, the main motivation is being able to backup system and data separately. My old PC got progressively slower and slower with time, even though I didn't install that much new software on it. If I can restore the system without losing my data, that means I can always roll back all the bloat/temp stuff, and (hopefully) keep the system nippy. This will mean maintaining a log of all new programs installed, then periodically rolling back to the last backup, and reinstalling the programs and re-doing a backup. Whether I manage to be that disciplined is another question.
Why can't I just cut and paste the Users folder? Well, one problem is that Windows is using bits of it, so you can't move them. The other problem is that even if you did move them, Windows would still be looking for them in the old location, and nasty things happen.
One solution is to modify the installation parameters to set a non-default location for the Users folder. As far as I can tell this is the only clean 'Microsoft' solution. Unfortunately I couldn't do this, because I bought an Acer which just dumps a disk image of a pre-installed Vista.
The solution on Josh Mouch's blog is to 'trick' Windows and progressively move the Users folder a bit at a time. Basically by first telling Windows to put new users in the new location, then logging in with a new user and copying across the other users. As you can see, it's a bit 'dirty', and on top of that, without tweaking it breaks Windows Update.
The other solution that is hinted at in comments is to use the Vista installation disk to 'boot into Recovery mode' and then move everything in one go. This basically means that you get access to all the files and folders, without Windows 'holding' on to them, so you can do what you want. The problem with this method is that 'symbolic links' don't get copied automatically, and you have to recreate them (and their access rights) by hand. I tried this, but at the end couldn't get access to some folders and figured that I'd got it wrong, so re-initialised my system.
So what's a symbolic link? It's kind of a software teleporter. It tells the file system 'from here, go somewhere completely different, but make it look like it's here'. So C:\Documents and Settings doesn't actually exist on disk, it's a symbolic link which points to somewhere else. This is heavily used in Vista to reproduce the 'expected' system paths for older systems, so that old programs will still work. So not reproducing them won't break Vista, but could potentially mean some programs won't work properly.
I must just say in passing that they are all
hidden symbolic links, which seem evil to me. I started over 3 or 4 times because I kept ending up with folders that I didn't have access to. It took me a long time to work out that even in normal Vista I didn't have access to the folders, they are part of the backwards-compatibility spaghetti that I shouldn't even have been seeing - except that I had followed the instructions on the blog which told me to change the settings to show all hidden and system files...
So basically, I came up with a script which writes the script to do the copying and recreation of those symbolic links. My script is complicated by the fact that my hard drives are SATA, and the Vista recovery disk didn't have the drivers on, which meant I had to load them separately, which in turn meant that all the disk letters were offset. (Did I mention that it took me a long time to get this working?) This means that my script has to allow for different drive letters between 'normal' running and 'script' running.
Oh the last thing is the really clever bit (not of my invention), which is to create 'one link to rule them all' which makes Windows believe that D:\Users is still in C:\Users...
OK, that said, let's roll...
InstructionsYou will need:
- Internet access
- A blank DVD & something to write to it with
- A USB stick
- Potentially, the appropriate disk drivers for your machine
- The script below
- To be comfortable with DOS commands
- To have read these instructions before starting, preferably
1. Download the Vista recovery disc from
here (it is a torrent file, so you need to follow the instructions for downloading it, and burning it to disk)
2. Try booting from the DVD, if you see a drive in the list, you are rocking, if not, you're going to have to find the drivers somewhere, copy them onto your USB stick, and hit Load Drivers to go and get them and load them.
3. Select the drive in the list. The next step will invite you to choose a login. If you haven't enabled the Administrator account, I wouldn't use that one.
4. Next, DO NOT hit the big Install button, but at the bottom, click on the Repair option.
5. Now hit the command line link, and have a nosy around to work out what the drive letters of your different drives/partitions are. In my case, I have 5 USB drives, and I had to load the drivers separately, so my C: and D: became I: and J: in recovery mode. This is important!
6. Now boot normally. Open a command prompt and run the following command:
dir /a c:\users > c:\dir.txt
7. This creates a directory listing which the script below will 'eat'
8. Open up the file and check what the prefix of each directory listing is, in English it is " Directory of...", in my case it was " R,pertoire de".
9. Save the script below to a file "script.vbs" at the root of your C: drive
10. Modify the
repprefix parameter in the file to reflect the value discovered in step 8 (space included)
11. Check the
sourcedrive and
targetdrive values. If you had the same driver problem as me in recovery mode, modify the
alt values accordingly.
12. Save and run the vbs file (double click it, I think)
13. Have a look at the script.bat file,
it starts with a robocopy command, which copies everything except symbolic links (lots of sources on the internet say you can't use robocopy to copy the symbolic links because there is a recursive link under Users. This is true, but even without that link, when robocopy copies links, it creates real folders, not links). Then there are a load of commands which recreate the links one at a time, copy the permissions and set the hidden attribute (confession, I assumed that all the links are hidden, but never checked). Finally, the script renames the Users fold to _Users, and creates a symbolic link from C:\Users to D:\Users.14. Now boot from the DVD again, do all the same steps (2-5) to get to the command line. Navigate to C:\ (or whatever the equivalent is), and run script.bat.
15. Depending on how much data you have, it could take a while.
16. Note that the script doesn't delete your existing Users folder, it just renames it, so if anything does go wrong, you should be able to delete the symbolic link (rd C:\Users), and rename your Users folder back.
17. One last thing to do, boot back normally, open regedit.exe to edit the registry, navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList and change %SystemDrive% to D: (or whatever) for Default, ProfilesDirectory and Public. The open ProfileList and correct the ProfileImagePath for the existing users (the ones with long SIDs). This is apparently necessary for Windows Desktop Search.
18. Hope it works for you.
'# Perform dir /a c:\users > c:\dir.txt
'# place this script file in c:\ too
'# double click to run it
'# run resulting script.bat from recovery mode
repprefix = " R" & Chr(130) & "pertoire de " ' Modify to your language
sourcedrive = "C:\"
targetdrive = "D:\"
altsourcedrive = "I:\" 'leave same as target drive unless otherwise indicated
alttargetdrive = "J:\" 'leave same as target drive unless otherwise indicated
inname = "dir.txt"
outname = "script.bat"
juncname = "[jonction]" //After copying from web, replace [] with angle brackets!!!
linkname = "[symlinkd]" //After copying from web, replace [] with angle brackets!!!
userroot = "Users"
set fso = CreateObject("Scripting.FileSystemObject")
' construct batch commands for saving rights, then link, the recreating rights
Function GetCommand(curroot, line, typ, keyword)
' first need to get source and target
pos = Instr(line, keyword) + Len(keyword)
tuple = Trim(Mid(line, pos))
arr = Split(tuple, "[")
oldtarget = Replace(arr(1), "]", "")
oldlink = curroot & "\" & Trim(arr(0))
' need to determine if we are pointing back to old disk
newlink = replace(oldlink, sourcedrive, targetdrive)
if(Instr(oldtarget, sourcedrive & userroot)) then
newtarget = Replace(oldtarget, sourcedrive, targetdrive)
else
newtarget = oldtarget ' still pointing to original target
end if
' comment
out = "echo " & newlink & " --- " & newtarget & vbCrLf
' save permissions
out = out & "icacls """ & replace(oldlink, sourcedrive, altsourcedrive) & """ /L /save " & altsourcedrive & "permissions.txt" & vbCrLf
' create link
newlink = replace(newlink, targetdrive, alttargetdrive)
if typ = "junction" then
out = out & "mklink /j """ & newlink & """ """ & newtarget & """" & vbCrLf
else ' typ = "symlink"
out = out & "mklink /d """ & newlink & """ """ & newtarget & """" & vbCrLf
end if
'set hidden attribute
out = out & "attrib +h """ & newlink & """ /L" & vbCrLf
' apply permissions
shortlink = Left(newlink, InstrRev(newlink, "\") - 1) 'icacls works strangely - non-orthogonal for restore
out = out & "icacls """ & shortlink & """ /L /restore " & altsourcedrive & "permissions.txt" & vbCrLf
GetCommand = out & vbCrLf
End Function
Sub WriteToFile(file, text)
ForWriting = 2
Create = true
set outfile = fso.OpenTextFile(file, ForWriting, Create)
Call outfile.Write(text)
Call outfile.Close()
End Sub
outtext = "ROBOCOPY " & altsourcedrive & userroot & " " & alttargetdrive & userroot & " /E /COPYALL /XJ" & vbCrLf & vbCrLf
set intext = fso.OpenTextFile(inname)
while not intext.AtEndOfStream
line = intext.ReadLine()
if Instr(line, repprefix) then
curroot = Replace(line, repprefix, "")
elseif Instr(line, juncname) then
outtext = outtext & GetCommand(curroot, line, "junction", juncname)
elseif Instr(line, linkname) then
outtext = outtext & GetCommand(curroot, line, "symlink", linkname)
end if
Wend
outtext = outtext & "icacls " & altsourcedrive & userroot & " /L /save " & altsourcedrive & "permissions.txt" & vbCrLf
outtext = outtext & "ren " & altsourcedrive & userroot & " _" & userroot & vbCrLf
outtext = outtext & "mklink /j " & altsourcedrive & userroot & " " & targetdrive & userroot & vbCrLf
outtext = outtext & "icacls " & altsourcedrive & " /L /restore " & altsourcedrive & "permissions.txt"
Call intext.Close()
Call WriteToFile(outname, outtext)
MsgBox("Done writing to " & outname)