Bagaimana cara menjalankan robocopy di PowerShell?


24

Saya mencoba menggunakan robocopy di dalam powershell untuk mencerminkan beberapa direktori di mesin rumah saya. Ini skrip saya:

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"
}

Script mengambil file csv dengan daftar direktori sumber dan tujuan. Ketika saya menjalankan skrip saya mendapatkan kesalahan ini:

-------------------------------------------------------------------------------
   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 !

Adakah yang harus saya lakukan untuk memperbaikinya?

Terima kasih, Mark.

Jawaban:


10

Jika variabel untuk $whatdan $optionstidak berubah, mengapa mereka variabel?

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

Ini berfungsi baik untuk saya:

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

Poin bagus - buat tetap sederhana. :)
Helvick

3
juga / detik tidak / detik / sangat penting di sini

1
Jadi Anda hanya melewatkan / Log dan berhasil :-) Gotcha adalah Anda mendapatkan Kesalahan aneh memanggil Robocopy dengan PS ketika Logfile tidak ada sebelumnya.
icnivad

6
Saya tahu ini adalah posting lama, tetapi saya pikir layak untuk mengatakan bahwa memiliki variabel-variabel ini sebagai sinyal bagi pembaca skrip yang akan datang bahwa ini dimaksudkan sebagai bagian skrip yang dapat dikonfigurasi. Alasan ini berhasil adalah karena itu terjadi untuk memperbaiki kesalahan ketik $ asli apa.
Octopus

2
Meskipun ada sesuatu yang tidak berubah, enkapsulasi variabel dapat membantu membuat skrip menjadi tidak terlalu berbelit-belit. Dan jika ternyata saya perlu referensi variabel itu lagi nanti, itu membuat skrip lebih dinamis
Kolob Canyon

20

Mempopulasikan string ke dalam parameter untuk perintah eksternal dari dalam Powershell membutuhkan beberapa lompatan hoop jika Anda ingin dapat menggunakan ekspansi variabel dan juga memiliki baris perintah yang dihasilkan dengan benar memahami parameter mana yang ingin Anda pisahkan dan mana yang tidak. Dalam contoh Anda, Anda mengirim seluruh string sebagai parameter pertama dan Robocopy memberi tahu Anda bahwa itu tidak dapat menemukan string panjang itu sebagai direktori sumber. Anda ingin seluruh string Sumber diperlakukan sebagai satu param (termasuk spasi yang mungkin ada di sana), demikian juga untuk Tujuan tetapi opsi $ what dan $ Anda akan gagal karena keduanya akan dikirimkan ke Robocopy sebagai parameter tunggal yang tidak dapat diurai.

Ada beberapa cara untuk melakukan ini dengan benar, tetapi potongan berikut didasarkan pada cara Anda tampaknya ingin keluar parameter Anda dan bekerja untuk contoh direktori tunggal yang saya gunakan.

$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

Terima kasih balasannya. Saya sudah mencoba kode Anda, tetapi saya masih mendapatkan kesalahan berikut: ERROR: Parameter # 3 tidak valid: "/ COPYALL / B / SEC / MIR"
Mark Allison

Ketika saya menjalankan kode rintisan di atas (disalin dari atas) berfungsi persis seperti yang diharapkan - khususnya semua opsi \ item apa yang dikenali sebagai parameter terpisah. Jika Anda menjalankan hanya rintisan di atas (dengan folder sumber yang ada) apakah itu berfungsi? Jika demikian maka periksa kembali Kutipan \ melarikan diri dalam kode Anda sendiri yang dimodifikasi. Parameter # 3 yang tidak valid menunjukkan bahwa versi Anda $ apa masih string tunggal bukan array parameter terpisah dalam kode yang Anda jalankan.
Helvick

2
+1. Itu pasti masalahnya di sini. Saya merasa lucu bagaimana orang-orang terus-menerus mencoba menggunakan PowerShell seolah-olah itu adalah shell berbasis teks saja ;-)
Joey

@ Joey Apakah Anda menemukan model objek PowerShell bekerja lebih baik dalam praktek daripada yang berbasis teks?
Didier A.

1
@DidierA .: Pasti. Terutama di mana objek ada untuk menggambarkan hal-hal yang berinteraksi dengan Anda, misalnya file, proses, layanan, dll. Tetapi bahkan ketika Anda hanya memiliki aplikasi asli dan output string Anda hanya dapat menggunakan operator string yang biasa, misalnya -matchdan -replacejuga menyaring / memproyeksikan cmdlet untuk bekerja dengan itu. Ini umumnya dirancang dengan sangat baik dalam hal itu (sebagian besar *-Objectperintah bersifat ortogonal dan semuanya dapat diterapkan ke objek apa pun).
Joey

3

Hapus kutipan dari baris robocopy?

yaitu

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
}

Tidak, saya mencobanya dulu dan tidak berhasil (kesalahan serupa), jadi saya mengubahnya ke apa yang ditunjukkan di atas. Ada ide lain?
Mark Allison

Apa hasilnya ketika Anda menjalankannya tanpa tanda kutip? Output asli Anda menunjukkan Sumber sebagai "P: \ C: \ Backup \ Foto \ COPYALL \ B \ SEC \ \ MIR \ R: 0 \ W: 0 \ NFL \ NDL \ LOG: MyLogfile.txt \" adalah apa yang menarik saya memperhatikan kutipan.
Bryan

3

Saya memiliki masalah yang sama. Seluruh baris perintah ditafsirkan sebagai argumen pertama.

Tidak ada yang disebutkan di atas yang berfungsi termasuk:

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

Meninggalkan tanda kutip tidak berfungsi ketika ada ruang di jalur:

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

Setelah mencoba trik-trik di http://edgylogic.com/blog/powershell-and-external-commands-done-right/ , akhirnya saya mengerti.

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

Mungkin saya harus terjebak dengan file bat. :)


Apakah tautan Anda ke edgylogic dipindahkan ke slai.github.io/posts/… ?
Henrik Staun Poulsen

1

Saya telah menemukan bahwa cara terbaik untuk mengeksekusi perintah asli adalah dengan menggunakan perintah & untuk mengeksekusi daftar string. Juga jika Anda ingin output konsol dimasukkan dalam transkrip powershell, Anda perlu menyalurkan output ke host. Berikut adalah contoh memanggil 7Zip dengan beberapa parameter yang diambil dari 7-Zip ke Amazon S3 Powershell Script yang saya tulis:

$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
}

Pada dasarnya untuk kasus Anda, saya akan mencoba sesuatu seperti ini (mungkin perlu memecahkan parameter $ what dan $ options secara individual):

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

Masalah dengan ini adalah bahwa ketika Anda mengatakan "$ apa" dan "$ opsi" akan dikirim ke robocopy sebagai parameter tunggal daripada daftar yang terpisah dan diberi kode sampelnya, mereka harus dihancurkan, tidak ada kemungkinan tentang saya t.
Helvick

Anda dapat menggunakan operator percikan @jika Anda menggunakan powershell v3 untuk membagi daftar yang dipisahkan koma menjadi tumpukan argumen
Zasz

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

Ini akan menginterpolasi semua variabel, lalu memanggil string yang dihasilkan. Cara Anda memilikinya sekarang, sepertinya robocopy sedang dijalankan dengan tanda kutip di sekitar semua opsi, yaitu, robocopy "c: \ src c: \ dst blah meh". Ini ditafsirkan sebagai parameter tunggal.


0

Ini bekerja untuk saya dan memungkinkan input dinamis dari lokasi file log. simbol & hanya memberi tahu PowerShell bahwa teks adalah baris kode yang ingin saya jalankan.

    $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

Menambahkan 2 sen saya ke ini karena dapat membantu seseorang ... Kode di bawah ini hilang bagian "loop" di mana saya membaca csv untuk mendapatkan file untuk disalin

# 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 ..  

}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.