我正在尝试将 Windows Vista 中的整个用户文件夹移动到非系统分区。为了尽量减少麻烦,我按照以下说明进行操作本的博客,特别是VB脚本他提供。
但是执行脚本时会抛出一个我自己无法解决的错误。这是 VBScript 代码,后面是它工作的文本文件,最后是我的错误消息。我该如何纠正这个问题?
VBScript 代码:
'# 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)
目录.txt:
驱动器 C 中的卷是 ACER 卷序列号为 08D7-C0CC c:\users 目录 2009 年 7 月 16 日下午 12:29 {DIR}。 2009 年 7 月 16 日下午 12:29 {DIR} .. 2006 年 11 月 2 日上午 9:02 {SYMLINKD} 所有用户 [C:\ProgramData] 2006 年 11 月 2 日上午 9:02 {DIR} 默认 2006 年 11 月 2 日上午 9:02 {JUNCTION} 默认用户 [C:\Users\Default] 2008 年 8 月 21 日 上午 8:37 174 桌面.ini 2006 年 11 月 2 日上午 8:50 {DIR} 公开 2009 年 7 月 19 日 晚上 8:54 {DIR} Steve 1 个文件 174 字节 7 个目录 5,679,947,776 字节可用
错误信息:
Windows 脚本宿主
脚本:C:\user location.vbs 行:25 字符:2 错误:下标超出范围:'[number: 1]' 代码:800A0009 来源:Microsoft VBScript 运行时错误
(在我系统上使用的 VBScript 脚本中,我认为“第 25 行”对应于以 开头的行oldtarget = Replace(arr(1), "]", "")
。
答案1
确保从另一页复制脚本时,换行符按应有的方式复制过来。例如,在上面打印的脚本中,它显示以
pos = Instr(line, keyword) + Len(keyword)
实际上是附加到上一行的注释中(该行中 ' 后面的所有内容)。可以因为您在那个 pos 中遇到的问题永远无法得到适当设置,所以没有任何内容会被复制到 arr 中。
只需逐行检查计算机上的脚本,并将其与从 Ben's Blog 复制的版本进行比较。脚本文件中的每一行都必须单独成行。
编辑:至于错误消息的含义,看起来 oldTarget 正在尝试抓取两个括号之间的字符串。发生错误的原因是字符串中没有足够的文本从数组位置 1 开始(并且这是从零开始的,这意味着它实际上是在尝试获取字符串中的第二个字符),即它最多是一个字符的字符串,这是不可能的,因为即使是空白字符串“元素”也会有两个字符(开括号和闭括号)。因此,您需要弄清楚为什么在代码中的这一点上没有得到有效的字符串才能解决这个问题。
答案2
首先,这是一个写得很差的脚本。我建议你好好重写一下。这有点像是一份粗制滥造的工作,你的大多数问题都源于此。
具体来说,您的问题发生在这里的第二行:
arr = Split(tuple, "[")
oldtarget = Replace(arr(1), "]", "")
这意味着前一行中的 split 没有返回数组,也就是说在元组中找不到 [,因此arr(1)
超出范围。在尝试访问 arr 之前,请尝试检查它是否为数组。
答案3
除了对初学者的嘲讽,我同意 Nilpo 的观点。您的问题是“arr(1)”失败,因为脚本期望这是数组中的第二个位置,但它不在那里,99% 的时间都是“越界”错误。它可能并不总是在您的控制范围内,但这通常是对数组边界问题的引用。数组位置从零开始。例如 Array(0, 1, 2, 3, ...)。所以 (1) 是第二个位置。他也是对的,它可能更干净,但如果刚开始使用 VBScript,您不会知道。
我认为这就是您要找的,而且更简洁。这将拉出括号 [] 之间的路径。您永远不想假设两个括号都在那里,即使它是一个生成的文件,所以我在执行之前有一个 If/Then 检查两者,否则它将跳到下一行和结尾。
我确实运行了它,并且它在括号之间捕获成功了。你可能需要做一些调整,因为我不确定你到底想在输出中看到什么。:)
Option Explicit
Dim fso : set fso = CreateObject("Scripting.FileSystemObject")
Dim fileIn : set fileIn = fso.OpenTextFile("c:\users\MyFolder\desktop\input.txt")
Dim fileOut : set fileOut = fso.OpenTextFile("c:\users\MyFolder\desktop\output.txt", 2, true) ' for writing/create
Dim line
Dim arr
Do Until fileIn.AtEndOfStream
line = fileIn.ReadLine
if InStr(line, "[") > 0 And InStr(line, "]") > 0 then
arr = Split(Split(line, "[")(1), "]")
fileOut.WriteLine arr(0) & "\"
end if
Loop
fileIn.Close
fileOut.Close
Set fso = Nothing
Set fileIn = Nothing
Set fileOut = Nothing
Set line = Nothing
Set arr = Nothing