PowerShellでロボコピーを実行するにはどうすればよいですか?


24

powershell内で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"
}

スクリプトは、ソースディレクトリと宛先ディレクトリのリストを含む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をスキップしただけでうまくいきました:-) Gotchaは、Logfileが事前に存在しない場合にPSでRobocopyを呼び出すと奇妙なエラーが発生することです。
icnivad

6
これが古い投稿であることは知っていますが、これらを変数として持つことは、スクリプトの将来の読者にとって、これらがスクリプトの構成可能な部分であることを示すシグナルであると言う価値があると思います。これが機能する理由は、元の$ whatのタイプミスを修正するためです。
タコ

2
何かが変わっていなくても、変数のカプセル化はスクリプトの複雑さを軽減するのに役立ちます。そして、それが参照するIの必要性が判明した場合、変数再び後に、それはスクリプトがよりダイナミックになること
Kolobキャニオン

20

Powershell内から外部コマンドのパラメーターに文字列を入力するには、変数展開を使用したい場合にフープジャンプが必要で、結果のコマンドラインで分離するパラメーターと分離しないパラメーターを適切に理解する必要があります。この例では、文字列全体を最初のパラメーターとして送信しており、Robocopyは、その長い文字列をソースディレクトリとして見つけることができないことを通知しています。Destinationの場合と同様に、Source文字列全体を1つのパラメーター(そこにあるスペースを含む)として扱いますが、$ whatおよび$ optionsは両方とも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

返信いただきありがとうございます。コードを試してみましたが、まだ次のエラーが表示されます。エラー:無効なパラメーター#3: "/ COPYALL / B / SEC / MIR"
Mark Allison

上記のスタブコード(上記からコピー)を実行すると、期待どおりに機能します。具体的には、すべてのオプション\アイテムが個別のパラメーターとして認識されます。上記のスタブを(存在するソースフォルダーで)実行するだけで機能しますか?その場合は、変更したコードでQuotes \ escapingを再確認してください。無効なパラメーター#3は、実行中のコード内の$ whatのバージョンが、個別のパラメーターの配列ではなく単一の文字列であることを示しています。
ヘルビック

2
+1。それは間違いなくここの問題です。PowerShellを古いテキスト専用ベースのシェルであるかのように常に使用しようとする方法が面白いと思います;-)
Joey

@Joey powershellのオブジェクトモデルは、テキストベースのものよりも実際にうまく機能することを発見しましたか?
ディディエA.

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
}

いいえ、私は最初にそれを試しましたが、うまくいきませんでした(同様のエラー)ので、上に示したものに変更しました。他のアイデアはありますか?
マークアリソン

引用符なしで実行すると、出力はどうなりますか?「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にパイプする必要があります。ここに、私が書いた7-ZipからAmazon S3 Powershellスクリプトへの複数のパラメーターを使用して7Zipを呼び出す例を示します。

$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に送信され、サンプルコードが与えられると、それらを分割する必要があることです。それ。
ヘルヴィック

あなたはスプラット演算子を使用することができ@ますが、コンマは引数スタックにリストを分離分割する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

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

}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.