在 Powershell 5 中使用 Robocopy

Using Robocopy with Powershell 5

我将我的开发机器升级到 Powershell 5,现在在 PS2 中工作的代码在 PS5 中不工作。

我的代码使用 Robocopy 将文件从 svn 签出目录复制到工作目录。它还用于清理工作目录。

原始代码如下所示:

    $what = @("""/copy:DAT""","""/E""","/XD .svn","/XD Debug","/XF .pdb")
    $options = @("""/R:4""","""/W:5""","""/TS""","""/NS""","""/Tee""","""/NP""")
    if ($file) {
        $cmdArgs = @("""$src""", """$dest""", """$file""", $what, $options)
    }else
    {
        $cmdArgs = @("""$src""", """$dest""", $what, $options)
    }
    robocopy $cmdArgs

当命令使用 powershell 5 运行时,我得到

ERROR : Invalid Parameter #3 : "/copy:DAT /E /XD .svn /XD Debug /XF .pdb"

我明白发生了什么,它将参数视为一个单独的命令而不是单独的参数。 我试过单双引号,我试过单引号,但我仍然得到相同的结果。

如果我将选项硬编码到执行行,

robocopy $cmdArgs /COPY:DAT /E /XD .svn /XD Debug /XF .pdb /R:4 /W:5 /TS /NS /Tee /NP

那么命令就可以工作了,所以我现在有一个解决方法,但仍然宁愿使用原始的参数化结构。

我需要做什么才能让 PS5 正常工作?谢谢。

编辑:使用 Windows 10 和 PS5,我收到以下错误: 错误:无效参数 #5:“/XD .svn”

$what = @("""/PURGE""","""/E""","/XD .svn","/XD Debug","/XF .pdb")
$options = @("""/R:4""","""/W:5""","""/TS""","""/NS""","""/Tee""","""/NP""")
$cmdArgs = @("""$srcBase""","""$targetPath"""; $what) 

对于'/XD .svn',我尝试用三引号、单引号、转义引号等将其括起来。但是,没有成功。

您正在构造一个锯齿状数组。您可以通过在 运行 您包含的代码

之后查看 $cmdargs 的结果来验证这一点
""
""
"/copy:DAT"
"/E"
/XD .svn
/XD Debug
/XF .pdb
"/R:4"
"/W:5"
"/TS"
"/NS"
"/Tee"
"/NP"

这看起来不错,但如果您只访问第三个元素 $cmdArgs[2],您会发现它包含了 $what 数组的全部内容

"/copy:DAT"
"/E"
/XD .svn
/XD Debug
/XF .pdb

作为一种快速而肮脏的解决方法,请尝试以下操作:

    $what = @("""/copy:DAT""","""/E""","/XD .svn","/XD Debug","/XF .pdb")
    $options = @("""/R:4""","""/W:5""","""/TS""","""/NS""","""/Tee""","""/NP""")
    if ($file) {
        $cmdArgs = @("""$src""", """$dest""", """$file""")
        $cmdArgs += $what
        $cmdArgs += $options
    }else
    {
        $cmdArgs = @("""$src""", """$dest""")
        $cmdArgs += $what
        $cmdArgs += $options
    }
    robocopy $cmdArgs

编辑: 上面的轻微编辑,和 More on Jagged vs Multidimensional vs standard arrays here。看向底部。本质上,您构建数组的方式被解释为 @(0,1,(0,1,2,3,4),(0,1,2,3,4,5))

哇!多么痛苦,但我有一个解决方案。 我不得不使用字符串拆分方法并按空格拆分。我不得不放弃数组并创建一个字符串。

$cmdArgs = @("""$srcBase""", """$targetPath""") #still required for quoted paths
$what = "/PURGE /E /XD .svn /XD DEBUG /XF .pdb"
$options = "/R:4 /W:5 /TS /NS /Tee /NP"
robocopy $cmdArgs $what.split(' ') $options.split(' ')

PS 2.0 和更高版本之间的一些更改破坏了我的代码,但这似乎修复了它。希望这有助于将其他人从痛苦的日子中拯救出来。 :)

编辑:考虑到这一点后,我认为这是 PS 和 Robocopy 之间的问题,其中具有值的参数无法正确评估。令我感到羞耻的是,我试了很多次才尝试一个简单的字符串作为参数。

太多令人难以置信的报价!除了您的源路径和目标路径之外,您真的根本不需要它们。我发现最好的方法是创建一个格式化的字符串表达式然后执行它。

$what = "/copy:DAT /E /XD .svn /XD Debug /XF .pdb"
$options = "/R:4 /W:5 /TS /NS /Tee /NP"
$source = "C:\DataSource"
$destination = "D:\DataDestination"

$expression = [string]::Format('ROBOCOPY "{0}" "{1}" {2} {3}', $source,$Destination,$what,$options)
$rc = Invoke-Expression $expression
$rc = $LASTEXITCODE;
    Switch ($rc)
{
    0 {$msg = 'No files were copied. No failure was encountered. No files were mismatched.'}
    1 {$msg = 'All files were copied successfully.'} 
    2 {$msg = 'There are some additional files in the destination directory that are not present in the source directory. No files were copied.'}
    3 {$msg = 'Some files were copied. Additional files were present. No failure was encountered.'}
    5 {$msg = 'Some files were copied. Some files were mismatched. No failure was encountered.'}
    6 {$msg = 'Additional files and mismatched files exist. No files were copied and no failures were encountered. This means that the files already exist in the destination directory.'}
    7 {$msg = 'Files were copied, a file mismatch was present, and additional files were present.'}
    8 {$msg = 'Several files did not copy.'}
    default {$msg = 'Robocopy failed with an error'}
}
$msg
If($rc -ge 8) {Throw}