Powershell с Robocopy и передачей аргументов

Я пытаюсь написать скрипт, который использует robocopy. Если бы я просто делал это вручную, моя команда была бы такой:

robocopy c:\hold\test1 c:\hold\test2 test.txt /NJH /NJS

НО, когда я делаю это из powershell, например:

$source = "C:\hold\first test"
$destination = "C:\hold\second test"
$robocopyOptions = " /NJH /NJS "
$fileList = "test.txt"

robocopy $source $destination $fileLIst $robocopyOptions

Я получил:

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

  Started : Fri Apr 10 09:20:03 2015

   Source - C:\hold\first test\
     Dest - C:\hold\second test\

    Files : test.txt

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

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

ERROR : Invalid Parameter #4 : " /NJH /NJS "

Однако, если я изменю команду robocopy на

robocopy $source $destination $fileLIst  /NJH /NJS 

все проходит успешно.

Итак, мой вопрос: как я могу передать строку в качестве параметров команды robocopy (и, в более широком смысле, сделать то же самое для любой данной внешней команды)


person weloytty    schedule 10.04.2015    source источник


Ответы (4)


Используй массивы, Люк. Если вы укажете массив значений, PowerShell автоматически развернет их в отдельные параметры. По моему опыту, это самый надежный метод. И не требует возиться с командлетом Start-Process, что, на мой взгляд, излишне для таких задач.

Этот прием взят из лучшей статьи о поведении PowerShell в отношении внешних исполняемых файлов, которую я видел: Правильно выполненные PowerShell и внешние команды.

Пример:

$source = 'C:\hold\first test'
$destination = 'C:\hold\second test'
$robocopyOptions = @('/NJH', '/NJS')
$fileList = 'test.txt'

$CmdLine = @($source, $destination, $fileList) + $robocopyOptions
& 'robocopy.exe' $CmdLine
person beatcracker    schedule 10.04.2015
comment
Исходная ссылка в ответе мертва ... Вот обновленная ссылка: Правильно выполненные PowerShell и внешние команды - person Sharpenologist; 10.06.2019
comment
@Sharpenologist Спасибо, исправлено! - person beatcracker; 11.06.2019

Вы не можете использовать строку для передачи параметров таким образом, потому что когда вы пишете

robocopy $source $destination $fileList $robocopyOptions

PowerShell оценит последнюю переменную ($robocopyOptions) как одну строку и заключит ее в кавычки. Это означает, что robocopy получит "/NJH /NHS" (одна строка в кавычках) в своей командной строке. (Очевидно, что это не намерение.)

Подробнее о том, как обойти подобные проблемы, см. здесь:

http://windowsitpro.com/powershell/running-executables-powershell

В статье реализована следующая функция:

function Start-Executable {
  param(
    [String] $FilePath,
    [String[]] $ArgumentList
  )
  $OFS = " "
  $process = New-Object System.Diagnostics.Process
  $process.StartInfo.FileName = $FilePath
  $process.StartInfo.Arguments = $ArgumentList
  $process.StartInfo.UseShellExecute = $false
  $process.StartInfo.RedirectStandardOutput = $true
  if ( $process.Start() ) {
    $output = $process.StandardOutput.ReadToEnd() `
      -replace "\r\n$",""
    if ( $output ) {
      if ( $output.Contains("`r`n") ) {
        $output -split "`r`n"
      }
      elseif ( $output.Contains("`n") ) {
        $output -split "`n"
      }
      else {
        $output
      }
    }
    $process.WaitForExit()
    & "$Env:SystemRoot\system32\cmd.exe" `
      /c exit $process.ExitCode
  }
}

Эта функция позволит вам запустить исполняемый файл в текущем окне консоли, а также позволит вам создать массив строковых параметров для передачи ему.

Итак, в вашем случае вы можете использовать эту функцию примерно так:

Start-Executable robocopy.exe $source,$destination,$fileList,$robocopyOptions
person Bill_Stewart    schedule 10.04.2015

У меня сработало размещение параметров в отдельных аргументах. Использование Robocopy для копирования, за исключением файлов CSV.

$roboCopyPath = $env:ROBOCOPY_PATH
$otherLogsPath = [System.IO.Path]::Combine($basePath, "Logs-Other")
$atrTestResults = [System.IO.Path]::Combine($Release, $BuildNumber)
$ResultsSummary = [System.IO.Path]::Combine($basePath, "Result")

$robocopyOptions = @("/log:$otherLogsPath\robocopy.log", '/xf', '*.csv')
$CmdLine = @($atrTestResults, $ResultsSummary) + $robocopyOptions 
&$roboCopyPath $CmdLine
person noksadayu    schedule 25.11.2020

person    schedule
comment
Start-Process подходит, если вы не возражаете против отдельного окна консоли. - person Bill_Stewart; 10.04.2015
comment
используйте аргументы -NoNewWindow -PassThru -Wait, чтобы избежать отдельного окна консоли - person Anton Z; 10.04.2015
comment
IIRC, Start-Process не обновляет $LASTEXITCODE. Это может быть важно в некоторых случаях. - person Bill_Stewart; 10.04.2015