views:

478

answers:

2

I'm trying to move my entire User folder in Vista to a non-system partition. To do so with a minimum hassle I'm following the directions provided at Ben's Blog, specifically the vbs script he provides. However executing the script throws up an error which I can't resolve myself. Here's the vbs code followed by the text file it calls on, and finally my error message. Can someone help me correct the problem? (I really don't know much about VBS, so please write as simple as possible.)

VBS Code:

'# 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 = " Directory of..." ' Modify to your language
sourcedrive = "C:\"
targetdrive = "D:\"
altsourcedrive = "C:\" 'leave same as target drive unless otherwise indicated
alttargetdrive = "E:\" 'leave same as target drive unless otherwise indicated

inname = "dir.txt"
outname = "script.bat"
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)

dir.txt:

Volume in drive C is ACER
Volume Serial Number is 08D7-C0CC

Directory of c:\users

07/16/2009 12:29 PM <DIR
07/16/2009 12:29 PM <DIR> ..
11/02/2006 09:02 AM <SYMLINKD> All Users [C:\ProgramData]
11/02/2006 09:02 AM <DIR> Default
11/02/2006 09:02 AM <JUNCTION> Default User [C:\Users\Default]
08/21/2008 08:37 AM 174 desktop.ini
11/02/2006 08:50 AM <DIR> Public
07/19/2009 08:54 PM <DIR> Steve
1 File(s) 174 bytes
7 Dir(s) 5,679,947,776 bytes free

Error Message:

Windows Script Host

Script: C:\userlocationchange.vbs
Line: 25
Char: 2
Error: Subscript out of range: '[number: 1]'
Code: 800A0009
Source: Microsoft VBScript runtime error
A: 

The problem is at these lines:

arr = Split(tuple, "[")

oldtarget = Replace(arr(1), "]", "")

I assume that arr(1) is giving the error because arr has only one entry - and since arrays are zero-based in VBS, that entry should be accessed as arr(0).

Hmmm... if there's only one entry, then presumably no "[" was found. The code probably needs to check for that (by testing whether UBound(arr) > 1).

What that means in a wider context - i.e. why there's no "[" I can't say.


EDIT: OK, I took a look at the blog you referred to, and the exact same problem was reported. The blog author replied:

A couple of pointers: look in the txt file output by the dir command. On my system, the targets of the symlinks are shown in square brackets []. Apparently in your case there aren't any - in any case that is a hypothesis that would explain why the script can't parse out the link targets.

...which pretty much confirms my theory. I suggest you do as he suggests and take a look at the txt file to see if some other character is used.

Note that this isn't really a problem with the script per se - it's just that the script expects some input that it's not getting.

Gary McGill
How can I correct the script
A: 

@Gary, I'm the same one who reported the problem on that blog. I posted the txt file here under the VBS code. My txt file also has the symlink-junction targets within square brackets. Is there anything else I'm missing?