Назад | Перейти на главную страницу

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

Я пытаюсь использовать 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 !

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

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

Заполнение строк в параметры для внешних команд из Powershell требует некоторого прыжка, если вы хотите иметь возможность использовать расширение переменных, а также чтобы полученная командная строка правильно понимала, какие параметры вы хотите разделять, а какие нет. В вашем примере вы отправляете всю строку в качестве первого параметра, и Robocopy сообщает вам, что он не может найти эту длинную строку в качестве исходного каталога. Вы действительно хотите, чтобы вся исходная строка рассматривалась как один параметр (включая пробелы, которые могут быть там), аналогично для пункта назначения, но ваши параметры $ 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

Если переменные для $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

Удалить кавычки из строки 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
}

У меня такая же проблема. Вся командная строка интерпретировалась как первый аргумент.

Ничего из упомянутого выше не работало, в том числе:

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

Может, мне следовало остановиться с файлами bat. :)

Я обнаружил, что лучший способ выполнить собственную команду - это использовать команду & для выполнения списка строк. Также, если вы хотите, чтобы вывод консоли был включен в расшифровку стенограммы PowerShell, вам необходимо направить вывод на внешний хост. Вот пример вызова 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"

Добавление моих 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 ..  

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

Это будет интерполировать все переменные, а затем вызвать результирующую строку. В том виде, в каком он у вас есть сейчас, похоже, что robocopy вызывается с кавычками вокруг всех параметров, то есть robocopy "c: \ src c: \ dst blah meh". Это интерпретируется как единственный параметр.

Это сработало для меня и позволяет динамически вводить местоположение файла журнала. символ & просто сообщает 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