Benutzer mit den meisten Antworten
Dateien/Verzeichnisse nach Vergleich durch „compare-object“ mit robocopy kopieren

Frage
-
Hallo Powershell Gemeinde,
folgendes Problem:
Ich möchte täglich ein script starten, dass ein Verzeichnis mit Untererzeichnissen und Dateien auf neue Verzeichnisse/Dateien überprüft . Sollten neue Verzeichnisse/Dateien gefunden werden, so sollen nur diese kopiert werden. Da es sich bei den meisten Dateien um sehr große Dateien handelt , soll dies mit robocopy gelöst werden. (Wiederaufnahme bei Abbruch).
In meinem Versuch ist vermutlich das Problem, dass die mit „compare-objekt“ gefilterten Daten nicht korrekt an robocopy übergeben werden können. Mit „copy-item“ anstelle von robocopy werden immerhin Dateien, allerdings keine Verzeichnisse kopiert.
Hier mein Versuch:
###################################################################################################### # Variablen setzen, Verzeichnisse einlesen und mit -Expandproperty für Arrayverarbeitung vorbereiten # ###################################################################################################### $Sourcepath = "\\srvatctls\IMGCBT\FUJITSU\H710\Maintenance\H710W7_Maint\Image\H710W7_M03b\test\" $Destinationpath = "c:\temp\test" $IfFilled = Test-Path "c:\temp\test\*.*" $Sourcecontent = Get-ChildItem -Recurse $Sourcepath | Select-Object -ExpandProperty fullname $Destinationcontent = Get-ChildItem -Recurse $Destinationpath | Select-Object -ExpandProperty fullname ################################################################################################################################## # Prüfen (und kopieren), ob Zielverzeichnis leer ist, da ein leeres Verzeichnis im nächsten Schritt nicht verglichen werden kann # ################################################################################################################################## If ($IfFilled -match 'False') {robocopy.exe "\\srvatctls\IMGCBT\FUJITSU\H710\Maintenance\H710W7_Maint\Image\H710W7_M03b\test" "c:\temp\test" /S /Z /XA:H /COPY:DAT /R:3 /W:3 /Reg /LOG+:"c:\temp\test\loggi.txt" /TS /FP /NP} else {} ######################################################################################### # Prüfen, ob Dateien im Zielverzeichnis vorhanden sind. Falls nicht, werden sie kopiert # ######################################################################################### {$NewFiles = Compare-Object -ReferenceObject $Sourcecontent -DifferenceObject $Destinationcontent -Property fullname -PassThru Robocopy.exe $NewFiles $Destinationpath /S /Z /XA:H /COPY:DAT /R:3 /W:3 /Reg /LOG+:"c:\temp\test\loggi.txt" /TS /FP /NP}
Weitere Frage: Da es eigentlich zwei Quellpfade sind, die überprüft werden sollen, würde ich den Aufruf für robocoy zweimal starten. Ist es auch möglich mehrere Quellpfade in eine Variable zu packen und diese an den copybefehl zu übergeben?
Danke schon mal für eure Hilfe!
Sönke
Antworten
-
Hallo Sönke,
der Quellpfad-Parameter von Robocopy kann nicht überladen werden, d.h. es ist nicht möglich mehrere Quellpfade in einer dafür vorgesehenen Datenstruktur zu speichern und so an Robocopy zu übergeben.
Ein Workaround dafür wäre aber, alle gewünschten Quellverzeichnisse in einem Array zu speichern und über eine For-Schleife darüber zu iterieren:
$firstSourcePath = "Quellverzeichnis1"; $secondSourcePath = "Quellverzeichnis2"; $sourcePaths = ($firstSourcePath, $secondSourcePath) For ($i=0; $i -lt $sourcePaths.Length; $i++) { # Hier gewünschten Code ausführen und dabei über # $sourcePaths[$i] auf aktuelles Quellverzeichnis # zugreifen bzw. an Robocopy übergeben. }
Wird das gewünschte Verhalten durch obigen Lösungsvorschlag erreicht?
Viele Grüße,
Tobias Heilig
TechNet Deployment HotlineDisclaimer:
Bitte haben Sie Verständnis dafür, dass wir hier auf Rückfragen gar nicht oder nur sehr zeitverzögert antworten können.
Bitte nutzen Sie für Rückfragen oder neue Fragen den telefonischen Weg über die TechNet Deployment Hotline: http://technet.microsoft.com/de-de/ff959330TechNet Deployment-Hotline
Telefon: 0800-6087338*
Email: msdn-technet-support@escde.net
* 16:00 – 18:00 Uhr (außer an bundeseinheitlichen Feiertagen). Kostenfrei aus dem dt. Festnetz, Mobilfunknetz ggfs. abweichend. Anrufer aus Österreich und der Schweiz können die Telefon-Hotline aus technischen Gründen über +49 721 693 7233 zum Tarif für Auslandsverbindungen des jeweiligen Telefonanbieters erreichen.
Es gelten Nutzungsbedingungen, Hinweise zu Markenzeichen sowie die allgemein gültigen Informationen zu Datenschutz und Cookies. Bitte beachten Sie auch die gesonderten Nutzungsbedingungen für die Deployment-Hotline.- Bearbeitet TechNet-Hotline Mittwoch, 19. November 2014 13:08
- Als Antwort markiert Sönke T Montag, 24. November 2014 09:26
-
Hallo Sönke!
Was ich nicht verstehe ist, wenn du schon Robocopy benutzt warum du nicht Robocopy das vergleichen auch überlässt? Genau dafür ist doch Robocopy da! Robocopy kann Verzeichnisse Synchronisieren! Vergiss Compare-Object und lass das Robocopy machen, der kann das viel besser.
Außerdem kann Robocopy mit langen Dateipfaden umgehen, PowerShell (.NET) kann das nicht!
Der folgende Befehl Kopiert nur die neuen Dateien geänderte werde Ignoriert, keine Löschvorgänge:
Robocopy <Quelle> <Ziel> /S /XC /XO /TEE /Z /LOG:"%USERPROFILE%\Desktop\robocopy.log" /SAVE:"%USERPROFILE%\Desktop\Jobfile"
PowerShell Artikel, Buchtipps und kostenlose PowerShell Tutorials + E-Books
auf der deutschsprachigen PowerShell Community
Mein 21 Teiliger PowerShell Video Grundlehrgang
Deutsche PowerShell Videos auf Youtube
Folge mir auf:
Twitter | Facebook | Google+- Als Antwort markiert Sönke T Montag, 24. November 2014 09:26
-
Du verwechselst hier Length mit count.
Du benutzt die falsche Schleife.
Du benutzt Get-ChildItem anstatt Get-Item
Du bist dir in vielen Fällen nicht bewusst, ob du einen Liste oder nur ein Element vor dir hast.
Du kannst dir bei Get-ChildItem nicht sicher sein was du zurückbekommst!
Wenn Get-ChildItem mehrere Elemente findet, dann bekommst du eine Liste, ein Array, zurück.
Wenn Get-ChildItem nur ein einziges Element findet, dann bekommst du KEINE LISTE (kein Array)!
Bei einem Array (eine Liste von Elementen), ist das etwas verwirrend, da ein Array die Eigenschaften Length und Count hat.Ein String (Text) hat auch die Eigenschaft Length mit der man die Länge des Textes messen kann.
"Hallo".Length ergibt 5
Man sollte bei einem Array immer die Eigenschaft Count benutzen.Wenn man wie hier bei $Destinationcontent nur ein Element haben möchte sollte man Get-Item anstatt Get-ChildItem benutzen. Sonst bekommt man auch hier (unbeabsichtigt) eine Liste von Elementen!
Du benutzt hier die Zählschleife For(){}. Dies ist nicht grundsätzlich falsch, aber für diese Sachen ist die ForEach(){} Schleife oder das ForEach-Object Cmdlet vorgesehen!
Bei ForEach benötigst du keinen Zähler und die Schleife Arbeitet immer zuverlässig, egal ob Get-ChildItem eine Liste oder nur ein Element mit einem Text zurück gibt!
Bei einem Vergleich mit Compare-Object müssen die verschiedenen Wurzeln der Pfade vorher entfernt werden, da sonst ALLE Dateien zurückgemeldet werden, da der Fullpath sich IMMER durch die verschiedenen Laufwerke / Wurzelpfade unterscheidet!
Das Vergleichen der Pfade wir dadurch sehr aufwändig!PowerShell Artikel, Buchtipps und kostenlose PowerShell Tutorials + E-Books
auf der deutschsprachigen PowerShell Community
Mein 21 Teiliger PowerShell Video Grundlehrgang
Deutsche PowerShell Videos auf Youtube
Folge mir auf:
Twitter | Facebook | Google+- Als Antwort markiert Sönke T Dienstag, 25. November 2014 11:29
Alle Antworten
-
Hallo Sönke,
der Quellpfad-Parameter von Robocopy kann nicht überladen werden, d.h. es ist nicht möglich mehrere Quellpfade in einer dafür vorgesehenen Datenstruktur zu speichern und so an Robocopy zu übergeben.
Ein Workaround dafür wäre aber, alle gewünschten Quellverzeichnisse in einem Array zu speichern und über eine For-Schleife darüber zu iterieren:
$firstSourcePath = "Quellverzeichnis1"; $secondSourcePath = "Quellverzeichnis2"; $sourcePaths = ($firstSourcePath, $secondSourcePath) For ($i=0; $i -lt $sourcePaths.Length; $i++) { # Hier gewünschten Code ausführen und dabei über # $sourcePaths[$i] auf aktuelles Quellverzeichnis # zugreifen bzw. an Robocopy übergeben. }
Wird das gewünschte Verhalten durch obigen Lösungsvorschlag erreicht?
Viele Grüße,
Tobias Heilig
TechNet Deployment HotlineDisclaimer:
Bitte haben Sie Verständnis dafür, dass wir hier auf Rückfragen gar nicht oder nur sehr zeitverzögert antworten können.
Bitte nutzen Sie für Rückfragen oder neue Fragen den telefonischen Weg über die TechNet Deployment Hotline: http://technet.microsoft.com/de-de/ff959330TechNet Deployment-Hotline
Telefon: 0800-6087338*
Email: msdn-technet-support@escde.net
* 16:00 – 18:00 Uhr (außer an bundeseinheitlichen Feiertagen). Kostenfrei aus dem dt. Festnetz, Mobilfunknetz ggfs. abweichend. Anrufer aus Österreich und der Schweiz können die Telefon-Hotline aus technischen Gründen über +49 721 693 7233 zum Tarif für Auslandsverbindungen des jeweiligen Telefonanbieters erreichen.
Es gelten Nutzungsbedingungen, Hinweise zu Markenzeichen sowie die allgemein gültigen Informationen zu Datenschutz und Cookies. Bitte beachten Sie auch die gesonderten Nutzungsbedingungen für die Deployment-Hotline.- Bearbeitet TechNet-Hotline Mittwoch, 19. November 2014 13:08
- Als Antwort markiert Sönke T Montag, 24. November 2014 09:26
-
Hallo,
danke, zwei Pfade als ein Quellpfad direkt an robocopy zu übergeben funktioniert wie oben angegeben!
Allerdings funktioniert das ganze nicht mehr, wenn ich den aus zwei Pfaden bestehenden Quellpfad mit compare-object vergleiche und an robocopy übergebe. (Ging ja schon mit einem Pfad wie im ersten Post nicht).
Wobei nun durch die For-Schleife das Ergebnis durch compare-object auch noch falsch ist!
Hat hierzu noch jemand eine Idee, wie ich nur die nicht im Zielverzeichnis enthaltenen Ordner/Dateien an robocopy übergeben kann?
Hier der zweite Versuch:
###################################################################################################### # Variablen setzen, Verzeichnisse einlesen und mit -Expandproperty für Arrayverarbeitung vorbereiten # ###################################################################################################### $Sourcepath = "\\srvatctls\IMGCBT\FUJITSU\H710\Maintenance\H710W7_Maint\Image\H710W7_M03b\test\"; $Sourcepath2 = "\\srvatctls\IMGCBT\HP\Z420\Image\Z420W7_05\testHP"; $Sourcepaths = ($Sourcepath, $Sourcepath2) $Destinationpath = "c:\temp\test" $IfFilled = Test-Path "c:\temp\test\*.*" $Sourcecontent = Get-ChildItem -Recurse $Sourcepaths | Select-Object -ExpandProperty fullname $Destinationcontent = Get-ChildItem -Recurse $Destinationpath | Select-Object -ExpandProperty fullname ################################################################################################################################## # Prüfen (und kopieren), ob Zielverzeichnis leer ist, da ein leeres Verzeichnis im nächsten Schritt nicht verglichen werden kann # ################################################################################################################################## If ($IfFilled -match 'False') {\\srvatctls\IMGCBT\FUJITSU\H710\Maintenance\H710W7_Maint\Image\H710W7_M03b\test\ \\srvatctls\IMGCBT\HP\Z420\Image\Z420W7_05\testHP /S /Z /B /XA:H /COPY:DAT /R:3 /W:3 /REG /UNILOG+:"c:\temp\loggi.txt" /TS /FP /NP} else {} ######################################################################################### # Prüfen, ob Dateien im Zielverzeichnis vorhanden sind. Falls nicht, werden sie kopiert # ######################################################################################### For ($i=0; $i -lt $Sourcecontent.Length; $i++) { $NewFiles = Compare-Object -ReferenceObject $Sourcecontent -DifferenceObject $Destinationcontent -Property fullname -PassThru Robocopy.exe $NewFiles[$i] $Destinationpath /S /Z /XA:H /COPY:DAT /R:3 /W:3 /REG /LOG+:"c:\temp\loggi.txt" /TS /FP /NP }
-
Hallo Sönke!
Was ich nicht verstehe ist, wenn du schon Robocopy benutzt warum du nicht Robocopy das vergleichen auch überlässt? Genau dafür ist doch Robocopy da! Robocopy kann Verzeichnisse Synchronisieren! Vergiss Compare-Object und lass das Robocopy machen, der kann das viel besser.
Außerdem kann Robocopy mit langen Dateipfaden umgehen, PowerShell (.NET) kann das nicht!
Der folgende Befehl Kopiert nur die neuen Dateien geänderte werde Ignoriert, keine Löschvorgänge:
Robocopy <Quelle> <Ziel> /S /XC /XO /TEE /Z /LOG:"%USERPROFILE%\Desktop\robocopy.log" /SAVE:"%USERPROFILE%\Desktop\Jobfile"
PowerShell Artikel, Buchtipps und kostenlose PowerShell Tutorials + E-Books
auf der deutschsprachigen PowerShell Community
Mein 21 Teiliger PowerShell Video Grundlehrgang
Deutsche PowerShell Videos auf Youtube
Folge mir auf:
Twitter | Facebook | Google+- Als Antwort markiert Sönke T Montag, 24. November 2014 09:26
-
Hallo,
danke für die Antwort, dass funktioniert! Da habe ich mich wohl zu sehr auf Powershell eingeschossen, anstatt mir noch mal die Parameter von robocopy anzuschauen!
Noch eine Frage zum Abschluss, da ich auch nach mehrmaligem lesen des Begriffs iterator folgende Zeile nicht begriffen habe:
For ($i=0; $i -lt $sourcePaths.Length; $i++)
- Wird hier mit "$i=0" die Möglichkeit abgefangen, dass keine neuen Datein vorhanden sind?
- Und mit "$sourcePaths.Length; $i++" der gesamte Quellpfad plus neue Dateien durch $i++ an robocopy übergeben?
(Nur damit ich nicht dumm sterbe)!
Sönke
-
Du verwechselst hier Length mit count.
Du benutzt die falsche Schleife.
Du benutzt Get-ChildItem anstatt Get-Item
Du bist dir in vielen Fällen nicht bewusst, ob du einen Liste oder nur ein Element vor dir hast.
Du kannst dir bei Get-ChildItem nicht sicher sein was du zurückbekommst!
Wenn Get-ChildItem mehrere Elemente findet, dann bekommst du eine Liste, ein Array, zurück.
Wenn Get-ChildItem nur ein einziges Element findet, dann bekommst du KEINE LISTE (kein Array)!
Bei einem Array (eine Liste von Elementen), ist das etwas verwirrend, da ein Array die Eigenschaften Length und Count hat.Ein String (Text) hat auch die Eigenschaft Length mit der man die Länge des Textes messen kann.
"Hallo".Length ergibt 5
Man sollte bei einem Array immer die Eigenschaft Count benutzen.Wenn man wie hier bei $Destinationcontent nur ein Element haben möchte sollte man Get-Item anstatt Get-ChildItem benutzen. Sonst bekommt man auch hier (unbeabsichtigt) eine Liste von Elementen!
Du benutzt hier die Zählschleife For(){}. Dies ist nicht grundsätzlich falsch, aber für diese Sachen ist die ForEach(){} Schleife oder das ForEach-Object Cmdlet vorgesehen!
Bei ForEach benötigst du keinen Zähler und die Schleife Arbeitet immer zuverlässig, egal ob Get-ChildItem eine Liste oder nur ein Element mit einem Text zurück gibt!
Bei einem Vergleich mit Compare-Object müssen die verschiedenen Wurzeln der Pfade vorher entfernt werden, da sonst ALLE Dateien zurückgemeldet werden, da der Fullpath sich IMMER durch die verschiedenen Laufwerke / Wurzelpfade unterscheidet!
Das Vergleichen der Pfade wir dadurch sehr aufwändig!PowerShell Artikel, Buchtipps und kostenlose PowerShell Tutorials + E-Books
auf der deutschsprachigen PowerShell Community
Mein 21 Teiliger PowerShell Video Grundlehrgang
Deutsche PowerShell Videos auf Youtube
Folge mir auf:
Twitter | Facebook | Google+- Als Antwort markiert Sönke T Dienstag, 25. November 2014 11:29