如何使robocopy在Powershell中运行?


24

我正在尝试在Powershell中使用robocopy来镜像我的家用计算机上的某些目录。这是我的脚本:

param ($configFile)

$config = Import-Csv $configFile
$what = "/COPYALL /B /SEC/ /MIR"
$options = "/R:0 /W:0 /NFL /NDL"
$logDir = "C:\Backup\"

foreach ($line in $config)
{
 $source = $($line.SourceFolder)
 $dest = $($line.DestFolder)
 $logfile =  $logDIr 
 $logfile += Split-Path $dest -Leaf
 $logfile += ".log"

 robocopy "$source $dest $what $options /LOG:MyLogfile.txt"
}

该脚本接收带有源和目标目录列表的csv文件。当我运行脚本时,出现以下错误:

-------------------------------------------------------------------------------
   ROBOCOPY     ::     Robust File Copy for Windows                              
-------------------------------------------------------------------------------

  Started : Sat Apr 03 21:26:57 2010

   Source : P:\ C:\Backup\Photos \COPYALL \B \SEC\ \MIR \R:0 \W:0 \NFL \NDL \LOG:MyLogfile.txt\
     Dest - 

    Files : *.*

  Options : *.* /COPY:DAT /R:1000000 /W:30 

------------------------------------------------------------------------------

ERROR : No Destination Directory Specified.

       Simple Usage :: ROBOCOPY source destination /MIR

             source :: Source Directory (drive:\path or \\server\share\path).
        destination :: Destination Dir  (drive:\path or \\server\share\path).
               /MIR :: Mirror a complete directory tree.

    For more usage information run ROBOCOPY /?


****  /MIR can DELETE files as well as copy them !

任何想法我需要做些什么来解决?

谢谢马克。

Answers:


10

如果变量$what$options没有改变,为什么他们的变量?

$what = "/COPYALL /B /SEC /MIR" 
$options = "/R:0 /W:0 /NFL /NDL" 

这对我来说很好:

robocopy   $source $dest /COPYALL /B /SEC /MIR /R:0 /W:0 /NFL /NDL

好点-保持简单。:)
Helvick

3
在这里/ sec也不是/ sec /很重要

1
因此,您只是跳过了/ Log,它就起作用了:-)不可思议的是,当Logfile不存在时,使用PS调用Robocopy时会出现奇怪的错误。
icnivad

6
我知道这是一篇老文章,但我认为值得一提的是,将它们作为变量向脚本的未来读者传达了一个信号,它们应该是脚本的可配置部分。这样做的原因是,它恰好可以解决原始$ what中的错字。
章鱼

2
即使某些事情没有改变,变量封装也可以帮助减少脚本的复杂性。如果事实证明我以后需要再次引用该变量,它会使脚本更具动态性
Kolob Canyon

20

如果您希望能够使用变量扩展,并且要使生成的命令行正确了解要分隔的参数和不应该分隔的参数,则在Powershell中将字符串填充到用于外部命令的参数中需要进行一些跳跃操作。在您的示例中,您将整个字符串作为第一个参数发送,而Robocopy告诉您找不到该长字符串作为源目录。您确实希望将整个Source字符串都视为一个参数(包括其中可能包含空格),对于Destination同样如此,但是您的$ what和$ options将失败,因为它们都将作为单个参数传递给Robocopy,而不能解析。

有几种方法可以正确执行此操作,但是以下代码段是基于您似乎想要分解参数的方式,并且确实适用于我使用的单个目录示例。

$source="C:\temp\source"
$dest="C:\temp\dest"

$what = @("/COPYALL","/B","/SEC","/MIR")
$options = @("/R:0","/W:0","/NFL","/NDL")

$cmdArgs = @("$source","$dest",$what,$options)
robocopy @cmdArgs

谢谢回复。我已经尝试过您的代码,但仍然收到以下错误:错误:无效的参数#3:“ / COPYALL / B / SEC / MIR”
Mark Allison 2010年

当我运行上面的存根代码(从上面复制)时,它完全可以按预期运行-特别是所有选项\哪些项目被识别为单独的参数。如果仅运行上面的存根(存在源文件夹),它能工作吗?如果是这样,请仔细检查您自己修改后的代码中的引号\转义。无效参数#3表示您的$ what版本仍然是单个字符串,而不是您正在运行的代码中的单独参数数组。
Helvick'4

2
+1。这绝对是这里的问题。我觉得很有趣,人们如何不断尝试使用PowerShell,就像它是旧的仅基于文本的外壳程序一样;-)
Joey

@Joey您是否发现Powershell的对象模型在实践中比基于文本的对象模型更好?
Didier A.

1
@DidierA .:当然。特别是在存在对象来描述您与之交互的事物的地方,例如文件,进程,服务等。但是,即使只有本地应用程序和字符串输出,也可以使用常规的字符串运算符,例如-match-replace以及过滤/投影cmdlet与之合作。在这方面,它通常设计得很好(大多数*-Object命令是正交的,它们都可以应用于任何对象)。
乔伊,

3

从robocopy行中删除引号?

param ($configFile)

$config = Import-Csv $configFile
$what = "/COPYALL /B /SEC/ /MIR"
$options = "/R:0 /W:0 /NFL /NDL"
$logDir = "C:\Backup\"

foreach ($line in $config)
{
 $source = $($line.SourceFolder)
 $dest = $($line.DestFolder)
 $logfile =  $logDIr 
 $logfile += Split-Path $dest -Leaf
 $logfile += ".log"

 robocopy $source $dest $what $options /LOG:MyLogfile.txt
}

不,我先尝试了一下,但没有成功(类似错误),因此我将其更改为上面显示的内容。还有其他想法吗?
Mark Allison

不带引号运行时输出是什么?原始输出显示源为“ P:\ C:\ Backup \ Photos \ COPYALL \ B \ SEC \ \ MIR \ R:0 \ W:0 \ NFL \ NDL \ LOG:MyLogfile.txt \”注意报价。
布赖恩

3

我有同样的问题。整个命令行被解释为第一个参数。

上面提到的任何方法都无效,包括:

invoke-expression "robocopy ""$sourceFolder"" ""$destinationFolder"" /MIR"  
invoke-expression "robocopy \`"$sourceFolder\`" \`"$destinationFolder\`" /MIR"  

当路径中有空格时,请不要删除引号:

invoke-expression "robocopy $sourceFolder $destinationFolder /MIR"  

在尝试了http://edgylogic.com/blog/powershell-and-external-commands-done-right/中的技巧之后,我终于明白了。

robocopy "\`"$sourceFolder"\`" "\`"$destinationFolder"\`" /MIR

也许我应该坚持使用蝙蝠文件。:)


您与edgylogic的链接是否已移至slai.github.io/posts/…
Henrik Staun Poulsen

1

我发现执行本机命令的最佳方法是使用&命令执行字符串列表。同样,如果希望将控制台输出包含在Powershell脚本中,则需要将输出通过管道传输到主机外。这是一个调用7Zip的示例,该示例使用从7-Zip到我编写的Amazon S3 Powershell脚本的多个参数调用:

$7ZipPath = "C:\Program Files\7-Zip\7z.exe" #Path to 7Zip executable
$FolderPath = "C:\Backup" #Folder to backup (no trailing slash!)
$FolderName = $FolderPath.Substring($FolderPath.LastIndexOf("\")+1) #grab the name of the backup folder
$TimeStamp = [datetime]::Now.ToString("yyyy-MM-dd_HHmm") #Create unique timestamp string
$strFile = [String]::Format("{0}\{1}_{2}.7z", "c:\",$FolderName,$TimeStamp) #Create filename for the zip
#7z options: add, type 7z, Archive filename, Files to add (with wildcard. Change \* to \prefix* or \*.txt to limit files), compression level 9, password, encrypt filenames, Send output to host so it can be logged.
& $7ZipPath "a" "-t7z" "$strFile" "$FolderPath\*" "-mx9" "-r" "-pPASSWORD" "-mhe" | out-host #create archive file
if($LASTEXITCODE -ne 0){ #Detect errors from 7Zip. Note: 7z will crash sometimes if file already exists
    Write-Error "ERROR: 7Zip terminated with exit code $LASTEXITCODE. Script halted."
    exit $LASTEXITCODE
}

基本上针对您的情况,我会尝试这样的事情(可能需要分别打破$ what和$ options参数):

$robocopypath = "c:\pathtofolder\robocopy.exe"
& $robocopypath "$source" "$dest" "$what" "$options" "/LOG:MyLogfile.txt"

问题是,正如您说的那样,“ $ what”和“ $ options”将作为单个参数而不是单独的参数列表发送到robocopy,并且鉴于他的示例代码,必须将其拆散,它。
赫尔维克,2010年

@如果要使用Powershell v3将逗号分隔的列表拆分为参数堆栈,则可以使用splat运算符
Zasz 2012年

0
invoke-expression "robocopy $source $dest $what $options /LOG:MyLogfile.txt"

这将插值所有变量,然后调用结果字符串。您现在所拥有的方式,似乎robocopy被所有选项的引号引起来,即robocopy“ c:\ src c:\ dst blah meh”。这被解释为单个参数。


0

这对我有用,并允许动态输入日志文件位置。&符号只是告诉PowerShell文本是我要运行的代码行。

    $source = "E:\BackupToRestore\"
    $destination = "E:\RestoreMe\"
    $logfile = "E:\robocopyLogFile.txt"    
    $switches = ("/B", "/MIR", "/XJ", "/FFT", "/R:0", "/LOG:$logfile")
    & robocopy $source $destination $roboCopyString $switches

0

向其中添加2美分,可能会对某人有所帮助...下面的代码缺少“循环”部分,我在其中读取csv以获取要复制的文件

# first we setup an array of possible robocopy status
$RobocopyErrors="NO ERRORS",
            "OKCOPY",
            "XTRA",
            "OKCOPY + XTRA",
            "MISMATCHES",
            "OKCOPY + MISMATCHES",
            "MISMATCHES + XTRA",
            "OKCOPY + MISMATCHES + XTRA",
            "FAIL",
            "OKCOPY + FAIL",
            "FAIL + XTRA",
            "OKCOPY + FAIL + XTRA",
            "FAIL + MISMATCHES& goto end",
            "OKCOPY + FAIL + MISMATCHES",
            "FAIL + MISMATCHES + XTRA",
            "OKCOPY + FAIL + MISMATCHES + XTRA",
            "***FATAL ERROR***"
#setting some variables with the date
$DateLogFile=get-date -format "yyyyddMMhh"

#this commands below one usually goes into a loop
$DateLog=get-date -format "yyyyddMMhhmmss"

#adding options and command arg as described in previous post
$options = @("/R:0","/W:0")
$cmdArgs = @("$Source","$Destination",$File,$options)

#executing Robocopy command
robocopy @cmdArgs

# We capture the lastexitcode of the command and use to confirm if all was good or not

$errorlevel=$LASTEXITCODE
# I output the status to a log file
"$DateLog`t::$($RobocopyErrors[$errorlevel])::`"$file`"`t`"$Source`" -> `"$Destination`"" | out-file "$scriptPath\Logs\$DateLogFile.log" -append
 if ($errorlevel -lt 8) {
    #error below 8 = all is good

}
else {
    # something bad happened ..  

}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.