Как запустить robocopy в powershell?

24

Я пытаюсь использовать robocopy внутри powershell для зеркалирования некоторых каталогов на моих домашних машинах. Вот мой сценарий:

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 !

Любая идея, что мне нужно сделать, чтобы исправить?

Спасибо, Марк.

Марк Эллисон
источник

Ответы:

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
также / сек нет / сек / здесь критично
1
Итак, вы просто пропустили / Log, и это сработало :-) Считается, что вы получаете странные ошибки при вызове Robocopy с PS, когда Logfile не существует заранее.
13
6
Я знаю, что это старый пост, но я думаю, что стоит сказать, что наличие этих переменных является сигналом для будущих читателей сценария, что они должны быть настраиваемыми частями сценария. Причина, по которой это работает, заключается в том, что это происходит, чтобы исправить опечатку в оригинальном $ what.
Осьминог
2
Даже если что-то не меняется, инкапсуляция переменных может помочь сделать скрипт менее запутанным. И если позже выясняется, что мне нужно снова обратиться к этой переменной, это сделает сценарий более динамичным
Колоб Каньон,
20

Заполнение строк в параметры для внешних команд из Powershell требует некоторого скачка обруча, если вы хотите иметь возможность использовать расширение переменных, а также чтобы полученная командная строка правильно понимала, какие параметры вы хотите разделить, а какие - нет. В вашем примере вы отправляете всю строку в качестве первого параметра, и Robocopy сообщает вам, что не может найти эту длинную строку в качестве исходного каталога. Вы хотите, чтобы вся исходная строка рассматривалась как один параметр (включая пробелы, которые там могут быть), также как и для Destination, но ваши параметры $ what и $ потерпят неудачу, поскольку они оба будут доставлены в 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
Helvick
источник
Спасибо за ответ. Я попробовал ваш код, но все равно получаю следующую ошибку: ОШИБКА: Неверный параметр # 3: "/ COPYALL / B / SEC / MIR"
Марк Эллисон,
Когда я запускаю приведенный выше код заглушки (скопированный сверху), он работает точно так, как ожидалось - в частности, все параметры \ какие элементы распознаются как отдельные параметры. Если вы запускаете только вышеупомянутую заглушку (с исходной папкой, которая существует), это работает? Если так, то дважды проверьте Кавычки \ экранирование в вашем собственном измененном коде. Недопустимый параметр # 3 указывает, что ваша версия $, которая по-прежнему представляет собой одну строку, а не массив отдельных параметров в коде, который вы запускаете.
Хелвик
2
+1. Это определенно проблема здесь. Мне смешно, что люди постоянно пытаются использовать PowerShell, как если бы это была старая текстовая оболочка ;-)
Joey
@Joey Считаете ли вы, что объектная модель powershell лучше работает на практике, чем текстовая?
Дидье А.
1
@DidierA .: Определенно. Особенно там , где объекты существуют , чтобы описать вещи , с которыми вы общаетесь, например , файлы, процессы, услуги и т.д. Но даже если у вас есть только встроенные приложения и строковые выходов вы можете просто использовать обычные строковые операторы, например , -matchи -replaceтак же , как фильтрация / проекционные командлеты работать с этим. Как правило, он достаточно хорошо разработан (большинство *-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
}
Bryan
источник
Нет, сначала я попробовал, и это не сработало (аналогичные ошибки), поэтому я изменил его на то, что показано выше. Есть другие идеи?
Марк Эллисон
Какой вывод при запуске без кавычек? Ваш исходный вывод с источником в виде "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/… ?
Хенрик Стаун Поульсен
1

Я обнаружил, что лучший способ выполнить нативную команду - использовать команду & для выполнения списка строк. Также, если вы хотите, чтобы вывод консоли был включен в стенограмму powershell, вам нужно будет направить вывод в out-host. Вот пример вызова 7Zip с несколькими параметрами, взятыми из сценария Powershell 7-Zip в Amazon S3, который я написал:

$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 как отдельные параметры, а не как список отдельных параметров, и, учитывая его пример кода, их придется разбивать, Это.
Хелвик
Вы можете использовать оператор splat, @если вы используете powershell v3 для разбиения списка через запятую в стек аргументов
Zasz
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
BriGuy
источник
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 ..  

}
galadriann
источник