none
Verzeichnisse vergleichen mit PowerShell

    Frage

  • Hallo,

    an folgender Aufgabenstellung bin ich gescheitert und wir alle können an der Lösungsfindung wachsen :-)

    - Ordner A hat mehrere Unterordner und wieder Unterordner und ... - in diesem Verzeichnisbaum liegen verschiedene Dateien (irgendwo)

    - dann hab ich einen Ordner B - in diesem Ordner liegen ebenfalls Dateien (ohne Unterordner)

    - nun will ich 1. aus B eine Datei nehmen 2. mir die Bezeichnung dieser Datei anschauen 3. in Ordner A gehen 4. in A die Datei finden, die die gleiche Bezeichnung hat wie aus 2. 5. wenn in A etwas gefunden wurde, wird Datei aus A durch Datei aus B ersetzt

    $origin = "C:\Pfad\B"
    $target = "C:\Pfad\A"
    $files_origin = Get-ChildItem -File $origin
    $filenames_target = Get-ChildItem -File $target | Split-Path -leaf
    foreach ($file in $files_origin) {
        $filename = Split-Path $file -leaf
        if ($filenames_target.contains($filename)) {
            cp $file $target
        }
    }


    Ich laufe in einen Fehler:

    You cannot call a method on a null-valued expression.
    At line:7 char:9
    +     if ($filenames_target.contains($filsename)) {
    +         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
        + FullyQualifiedErrorId : InvokeMethodOnNull

    Des weiteren sind Unterordner auch noch nicht berücksichtigt :-(

    Ich bin um Rat sehr dankbar!

    Freitag, 14. September 2018 07:47

Antworten

  • Schulnote ist bisher 2+,

    Nee nee nee neee ...  das ist bisher ne 1 und wird gleich ne 1+. Wenn der Lehrer es nämlich nicht korrekt erklärt und sogar wichtige Details weglässt, darf das nicht zum Nachteil ausgelegt werden!!!!! :-P

    $origin = 'C:\Pfad\B'
    $target = 'C:\Pfad\A'
    
    $files_origin = Get-ChildItem -Path $origin -File -Recurse -Force
    $filenames_target = Get-ChildItem -Path $target -File -Recurse -Force
    
    Compare-Object -ReferenceObject $filenames_target -DifferenceObject $files_origin -PassThru -IncludeEqual |
        ForEach-Object {
            $sourceFile = Join-Path -Path $origin -ChildPath $_.Name
            Copy-Item -Path $sourceFile -Destination $_.Directory -Force 
        }

    So, ich muss jetzt los ... wenn das immernoch nicht passt, musst Du Dir bis Dienstag allein weiterhelfen ... oder einer von den anderen Kollegen hier macht weiter.

    Schönes WE!


    Best regards,

    (79,108,97,102|%{[char]$_})-join''

    Freitag, 14. September 2018 12:51

Alle Antworten

  • Anderweitig habe ich folgenden Code in nicht PowerShell gefunden, welcher passen sollte (vielleicht hilft diese Info)

    for f in B/* 
    do 
      file=${f/*\/}
      find A -type f -execdir cp "$f" . ";" 
    done

    Freitag, 14. September 2018 07:59
  • Ich würde es so machen ...
    $origin = 'C:\Pfad\B'
    $target = 'C:\Pfad\A'
    
    $files_origin = Get-ChildItem -Path $origin -File -Recurse -Force
    $filenames_target = Get-ChildItem -Path $target -File -Recurse -Force
    
    Compare-Object -ReferenceObject $files_origin -DifferenceObject $filenames_target -PassThru -IncludeEqual -ExcludeDifferent |
        Copy-Item -Destination $target -Force
      ...  bitte erst mit Testdaten probieren!  ;-)

    Best regards,

    (79,108,97,102|%{[char]$_})-join''


    • Bearbeitet BOfH_666 Freitag, 14. September 2018 08:11
    Freitag, 14. September 2018 08:05
  • twinson_999,

    willkommen im Deutschen Powershell Forum.

    ...   Code in nicht PowerShell gefunden...

    Neeee .... wir sind hier im Powershell Forum!!  ... wenn überhaupt, dann ersetzen wir cmd/batch oder allen anderen Code durch Powershell Code und nicht andersrum.  :-D  Überlicherweise ist Powershell sowieso viel mächtiger und auch einfacher zu lesen als cmd/batch.  ;-)


    Best regards,

    (79,108,97,102|%{[char]$_})-join''

    Freitag, 14. September 2018 08:15
  • Hallo BOfH_666,

    erst einmal Danke für deine Unterstützung.

    Wenn ich es auf ein Test-Verzeichnis anwende, erhalte ich folgende Mitteilung:

    Compare-Object : Cannot bind argument to parameter 'DifferenceObject' because it is null.
    At line:7 char:65
    + Compare-Object -ReferenceObject $files_origin -DifferenceObject $filenames_targe ...
    +                                                                 ~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidData: (:) [Compare-Object], ParameterBindingValidationException
        + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.CompareObjectCommand
    

    Hast du hierzu eine Idee?

    Ich würde es so machen ...

    $origin = 'C:\Pfad\B'
    $target = 'C:\Pfad\A'
    
    $files_origin = Get-ChildItem -Path $origin -File -Recurse -Force
    $filenames_target = Get-ChildItem -Path $target -File -Recurse -Force
    
    Compare-Object -ReferenceObject $files_origin -DifferenceObject $filenames_target -PassThru -IncludeEqual -ExcludeDifferent |
        Copy-Item -Destination $target -Force

      ...  bitte erst mit Testdaten probieren!  ;-)


    Best regards,

    (79,108,97,102|%{[char]$_})-join''



    Freitag, 14. September 2018 10:23
  • Ich muss noch einmal prüfen, ich hatte nur ein schlechtes Beispiel gewählt (unter A und B war kein identisches Dokument)
    Freitag, 14. September 2018 10:26
  • Ok, es werden Datein von A nach B kopiert, jedoch wird unter B nicht das passende Gegenstück/Dokument, welches sich unter einer Sub-Struktur befindet, gesucht und ersetzt (lediglich auf die selbige Ebene (wie unter A) kopiert)


    • Bearbeitet twinson_999 Freitag, 14. September 2018 10:30
    Freitag, 14. September 2018 10:28
  • Drehe ich target und origin, dann werden aus dem Ordner mit der Ordner-Struktur (und die darunter befindlichen Dokumente) in die flache Struktur (ohne Ordner) kopiert.

    Eigentlich müsste es nur noch Spiegelverkehrt angewendet werden

    Freitag, 14. September 2018 10:39
  • Häh? ... ich bin verwirrt ... von wo nach wo soll kopiert werden?  ... egal ...

    Ich erklär einfach mal die generelle Vorgehensweise und Du kannst Dir dann den Code so zusammenklöppeln, wie Du es brauchst.

    Du erstellst Dir mit den beiden Get-ChildItem Befehlen quasi zwei Tabellen. Darin enthalten sind die Eigenschaften der Dateien. Also Name (mit Endung), BaseName (ohne Endung), FullName (incl. Pfad), Length (Größe), LastWriteTime (Zeitpunkt der letzten Änderung) usw ....

    Mit Compare-Object kannst Du Diese beiden Tabellen vergleichen. Du kannst angeben, welche Eigenschaft dafür benutzt wird - im Standard ist es wohl der Name. Du kannst angeben, ob Du die Unterschiede sehen willst oder die Gemeinsamkeiten oder alles. Und Du kannst noch angeben, dass das Eingangs-Object in die Ausgabe eingeschlossen wird. Damit hast Du dann alle "hintenraus" benötigten Informationen - denke ich.

    Diese Ausgabe benutzt Du dann einfach als Basis für die entsprechenden Kopieraktionen. Lass Dir einfach mal nur alles ausgeben - dann siehst Du, womit Du weiterarbeiten kannst.

    Vielleicht musst Du auch Referenz- und Differenz-Object tauschen - es kann sein, dass ich Deine anfängliche Erklärung "falschrum" verstanden habe.  ;-)  :-D

    Best regards,

    (79,108,97,102|%{[char]$_})-join''


    • Bearbeitet BOfH_666 Freitag, 14. September 2018 10:43
    Freitag, 14. September 2018 10:42
  • Drehe ich target und origin, ........

    Eigentlich müsste es nur noch Spiegelverkehrt angewendet werden

    ... endlich mal wider jemand, der mitdenkt und selbst ein bissl rumprobiert .... großartig. ;-) :-D

    Danke.


    Best regards,

    (79,108,97,102|%{[char]$_})-join''


    • Bearbeitet BOfH_666 Freitag, 14. September 2018 10:47
    Freitag, 14. September 2018 10:46
  • Nochmals lieben Dank für die genommene Zeit.

    Wenn ich deinen Erklärrung richtig folgen konnte, beschreibt das PS das kopieren auf identische Ebene zwischen A und B.

    Leider kann ich noch keine Grafiken oder Links einfügen (als "neuer Nutzer"), sodass ich meine gerade erstellte Grafik nicht einfügen kann.


    Ich probiere es zu umschreiben:

    Unter origin liegt:
    C:\A\file111.pdf
    C:\A\file222.pdf
    C:\A\file333.pdf

    Unter target liegt:
    C:\B\ORDNER1\file111.pdf
    C:\B\ORDNER2\file222.pdf
    C:\B\file333.pdf

    Alle Dokumente unter origin sollen die Dokumente unter target ersetzen, egal ob diese auf der identischen, oder einer sub-struktur liegen.

    • Bearbeitet twinson_999 Freitag, 14. September 2018 11:26
    Freitag, 14. September 2018 11:22
  • OK ... von hinten durch die Brust ins Auge ... ich glaub, ich hab mir grad einen Knoten in meine linke Hemisphäre gemacht.  ;-) :-D ....

    Ja, da müssen wir dann eben ein bissl tricksen ... so sollte es aber flutschen:

    $origin = 'C:\Pfad\B'
    $target = 'C:\Pfad\A'
    
    $files_origin = Get-ChildItem -Path $origin -File -Recurse -Force
    $filenames_target = Get-ChildItem -Path $target -File -Recurse -Force
    
    Compare-Object -ReferenceObject $filenames_target -DifferenceObject $files_origin -PassThru -IncludeEqual -ExcludeDifferent |
        ForEach-Object {
            $sourceFile = Join-Path -Path $origin -ChildPath $_.Name
            Copy-Item -Path $sourceFile -Destination $_.Directory -Force 
        }


    Best regards,

    (79,108,97,102|%{[char]$_})-join''


    • Bearbeitet BOfH_666 Freitag, 14. September 2018 11:42
    Freitag, 14. September 2018 11:42
  • Jeden Tag eine gute Tat.

    Ich möchte mich noch nicht zu sehr freuen, aber der erste Test war erfolgreich :-)

    Ich teste weiter, freue mich aber bereits riesig, sollte es sich bewahrheiten!

    Vielen Dank soweit und nun geht es ans testen...

    Freitag, 14. September 2018 11:48
  • Schulnote ist bisher 2+, weshalb 2+; ich habe noch eine Kleinigkeit.

    Wenn ein Dokument mehrfach unter target verwendet wird, jedoch nur 1x unter origin (geht ja auch nicht anders) genannt ist, werden nicht alle Dokumente (unter target) sondern nur das zuerst gefundene ersetzt.

    Gibt es eine Möglichkeit, eine Datei, welche unter origin genannt ist prinziepell auszuschließen (-Exclude?)

    Hast du noch eine abschlißende Idee, damit ich eine 1+ vergeben kann?




    • Bearbeitet twinson_999 Freitag, 14. September 2018 12:32
    Freitag, 14. September 2018 12:15
  • Schulnote ist bisher 2+,

    Nee nee nee neee ...  das ist bisher ne 1 und wird gleich ne 1+. Wenn der Lehrer es nämlich nicht korrekt erklärt und sogar wichtige Details weglässt, darf das nicht zum Nachteil ausgelegt werden!!!!! :-P

    $origin = 'C:\Pfad\B'
    $target = 'C:\Pfad\A'
    
    $files_origin = Get-ChildItem -Path $origin -File -Recurse -Force
    $filenames_target = Get-ChildItem -Path $target -File -Recurse -Force
    
    Compare-Object -ReferenceObject $filenames_target -DifferenceObject $files_origin -PassThru -IncludeEqual |
        ForEach-Object {
            $sourceFile = Join-Path -Path $origin -ChildPath $_.Name
            Copy-Item -Path $sourceFile -Destination $_.Directory -Force 
        }

    So, ich muss jetzt los ... wenn das immernoch nicht passt, musst Du Dir bis Dienstag allein weiterhelfen ... oder einer von den anderen Kollegen hier macht weiter.

    Schönes WE!


    Best regards,

    (79,108,97,102|%{[char]$_})-join''

    Freitag, 14. September 2018 12:51
  • Super und der "Lehrer" (obwohl ich ja der jenige bin der von Dir lernt) gesteht seine Schande.

    Hat funktioniert und die 1+ steht im Notenbuch.

    Einzig die Fragestelltung wie kann ich ein Dokument nun ignorieren steht aus.

    Dir auch ein schönes Wochenende und bis Dienstag
    • Bearbeitet twinson_999 Freitag, 14. September 2018 13:22
    Freitag, 14. September 2018 13:22
  • ... (obwohl ich ja der jenige bin der von Dir lernt) ....

    ... hmmm ... Du hast angefangen mit dem Zensuren-Dingsbums ... ;-)

    Einzig die Fragestelltung wie kann ich ein Dokument nun ignorieren steht aus.

    Was für ein Dokument? ... und was meinst Du mit ignorieren?


    Best regards,

    (79,108,97,102|%{[char]$_})-join''

    Dienstag, 18. September 2018 00:03
  • Hallo noch einmal,

    ich habe leider bisher noch immer keine Möglichkeit gefunden, eine Datei, welche unter Origin genannt ist, auszuschließen.

    Hast du noch eine Idee auf Lager?

    Donnerstag, 20. September 2018 15:15
  • $files_origin = Get-ChildItem -Path $origin -File -Recurse -Force -Exclude

    Get-Help Get-ChildItem -Full.

    Es ist sehr empfehlenswert IMMER die KOMPLETTE Hilfe der cmdlets zu lesen, die Du benutzt - inclusive der Beispiele.

    Das beantwortet üblicherweise bereits alle Anfängerfragen.  ;-)


    Best regards,

    (79,108,97,102|%{[char]$_})-join''


    • Bearbeitet BOfH_666 Donnerstag, 20. September 2018 17:49
    Donnerstag, 20. September 2018 17:48