Frage Wie bekomme ich Robocopy in Powershell?


Ich versuche, Robocopy in Powershell zu verwenden, um einige Verzeichnisse auf meinen Home-Computern zu spiegeln. Hier ist mein Skript:

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

Das Skript nimmt eine CSV-Datei mit einer Liste von Quell- und Zielverzeichnissen auf. Wenn ich das Skript ausführe, erhalte ich folgende Fehler:

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

Irgendeine Idee, was ich tun muss, um zu beheben?

Vielen Dank, Kennzeichen.


22
2018-04-03 19:29


Ursprung




Antworten:


Wenn die Variablen für $what und $options nicht ändern, warum sind sie Variablen?

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

Das funktioniert gut für mich:

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

10
2018-04-03 23:32



Guter Punkt - behalte es einfach. :) - Helvick
auch / sec not / sec / ist hier kritisch
Also hast du einfach das / Log übersprungen und es hat funktioniert :-) Gotcha ist, dass du merkwürdige Fehler bekommst, Robocopy mit PS anrufend, wenn das Logfile nicht vorher existiert. - icnivad
Ich weiß, dass dies ein alter Beitrag ist, aber ich denke, es lohnt sich zu sagen, dass diese als Variablen ein Signal für zukünftige Leser des Skripts sind, dass diese konfigurierbare Teile des Skripts sein sollten. Der Grund, warum dies funktioniert, ist, dass es den Tippfehler im ursprünglichen $ what repariert. - Octopus
Auch wenn sich etwas nicht ändert, kann die variable Kapselung dazu beitragen, dass ein Skript weniger verschachtelt wird. Und wenn sich herausstellt, dass ich diese Variable später erneut referenzieren muss, wird das Skript dynamischer - Kolob Canyon


Das Auffüllen von Zeichenfolgen in Parametern für externe Befehle innerhalb von Powershell erfordert ein gewisses Zeilensprungverfahren, wenn Sie die variable Erweiterung verwenden und die resultierende Befehlszeile richtig verstehen können, welche Parameter getrennt werden sollen und welche nicht. In Ihrem Beispiel senden Sie die gesamte Zeichenfolge als ersten Parameter, und Robocopy sagt Ihnen, dass diese lange Zeichenfolge nicht als Quellverzeichnis gefunden werden kann. Sie möchten, dass die gesamte Source-Zeichenfolge als ein Parameter behandelt wird (einschließlich Leerzeichen, der sich dort befinden kann), ebenso wie für Destination, aber Ihre $ what- und $ -Optionen werden fehlschlagen, weil sie beide als einzelner Parameter an Robocopy übergeben werden analysiert.

Es gibt einige Möglichkeiten, dies richtig zu machen, aber das folgende Snippet basiert auf der Art und Weise, wie Sie Ihre Parameter auszubrechen scheinen und funktioniert für das Beispiel, das ich verwendet habe.

$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

19
2018-04-03 21:38



Danke für die Antwort. Ich habe Ihren Code ausprobiert, erhalte aber immer noch den folgenden Fehler: FEHLER: Ungültiger Parameter 3: "/ COPYALL / B / SEC / MIR" - Mark Allison
Wenn ich den oben genannten Stub-Code (von oben kopiert) ausgeführt wird, funktioniert es genau wie erwartet - speziell alle Optionen \ welche Elemente als separate Parameter erkannt werden. Wenn Sie nur den obigen Stub (mit einem Quellordner, der existiert) funktioniert es? Wenn dies der Fall ist, überprüfen Sie die Angebote in Ihrem eigenen modifizierten Code. Der ungültige Parameter # 3 gibt an, dass Ihre Version von $, was immer noch eine einzelne Zeichenfolge ist, kein Array von separaten Parametern in dem Code ist, den Sie ausführen. - Helvick
+1. Das ist definitiv das Problem hier. Ich finde es witzig, dass Leute ständig versuchen, PowerShell zu benutzen, als wäre es eine alte Nur-Text-basierte Shell ;-) - Joey
@Joey Hast du herausgefunden, dass das Objektmodell der Powershell in der Praxis besser funktioniert als die textbasierten? - Didier A.
@DidierA .: Definitiv. Insbesondere dort, wo Objekte existieren, um die Dinge zu beschreiben, mit denen Sie interagieren, z. Dateien, Prozesse, Dienste usw. Aber selbst wenn Sie nur native Anwendungen und String-Ausgaben haben, können Sie einfach die üblichen String-Operatoren verwenden, z. -match und -replace sowie Filter- / Projektions-Cmdlets, um damit zu arbeiten. In dieser Hinsicht ist es im Allgemeinen ziemlich gut gestaltet (die meisten *-Object Befehle sind orthogonal und sie können auf jedes Objekt angewendet werden). - Joey


Entfernen Sie die Zitate aus der Robocopy-Zeile?

d.h.

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
}

3
2018-04-03 19:46



Nein, ich habe das zuerst versucht und es hat nicht funktioniert (ähnliche Fehler), also habe ich es auf das oben gezeigte geändert. Irgendwelche anderen Ideen? - Mark Allison
Was ist die Ausgabe, wenn Sie es ohne Anführungszeichen ausführen? Ihre ursprüngliche Ausgabe, die die Quelle als "P: \ C: \ Sicherung \ Fotos \ COPYALL \ B \ SEC \ \ MIR \ R: 0 \ W: 0 \ NFL \ NDL \ LOG: MyLogfile.txt \" zeigte, zeichnete meine Aufmerksamkeit auf die Zitate. - Bryan


Ich hatte das gleiche Problem. Die gesamte Befehlszeile wurde als erstes Argument interpretiert.

Nichts oben erwähnt funktionierte einschließlich:

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

Das Angeben der Anführungszeichen funktioniert nicht, wenn ein Leerzeichen im Pfad vorhanden ist:

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

Nach dem Versuch, die Tricks in http://edgylogic.com/blog/powershell-and-external-commands-done-right/Ich habe es endlich verstanden.

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

Vielleicht hätte ich mit Fledermaus-Dateien weitermachen sollen. :)


2
2017-07-16 21:06





Ich habe festgestellt, dass der beste Weg, einen nativen Befehl auszuführen, ist, den Befehl & zu verwenden, um eine Liste von Zeichenfolgen auszuführen. Wenn Sie möchten, dass die Konsolenausgabe in einem Powershell-Transkript enthalten ist, müssen Sie die Ausgabe an den Out-Host übergeben. Hier ist ein Beispiel für den Aufruf von 7Zip mit mehreren Parametern aus a 7-Zip zu Amazon S3 Powershell Script dass ich geschrieben habe:

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

Grundsätzlich würde ich für Ihren Fall so etwas versuchen (müssen die Parameter $ what und $ options einzeln ausbrechen):

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

1
2018-04-04 19:08



Das Problem dabei ist, dass "$ what" und "$ options" als einzelne Parameter an Robocopy gesendet werden und nicht an eine Liste separater Parameter. Wenn man seinen Beispielcode angibt, müssen sie ausbrechen es. - Helvick
Sie können den Splat-Operator verwenden @ Wenn Sie Powershell v3 verwenden, um eine kommagetrennte Liste in einen Argument-Stack aufzuteilen - Zasz


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

Dies interpoliert alle Variablen und ruft dann die resultierende Zeichenfolge auf. Wie Sie es jetzt haben, sieht es so aus, dass robocopy mit den Anführungszeichen um alle Optionen herum aufgerufen wird, d. H. Robocopy "c: \ src c: \ dst blah meh". Dies wird als ein einzelner Parameter interpretiert.


0
2018-05-01 13:42





Dies funktionierte für mich und ermöglicht eine dynamische Eingabe des Speicherortes der Protokolldatei. Das Symbol & teilt PowerShell einfach mit, dass der Text eine Codezeile ist, die ich ausführen möchte.

    $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
2017-10-22 17:23





Addieren Sie meine 2 Cent dazu, wie es jemandem helfen kann ... Der folgende Code fehlt der "Schleife" Teil, wo ich ein CSV lesen, um die Dateien zu kopieren

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

}

0
2018-04-18 07:53