none
Bestimmte Dateien eine Ebene höher von der Quelle im Ziel kopieren

    Frage

  • Hallo,

    ich muss mehr als 10.000 Dateien (*.txt) von einer Quelle zum neuen Ziel kopieren, wobei im Ziel die Dateiobjekte mit *.txt eine Ordnerebene höher liegen sollen.

    Quelle:

    C:\temp\Quelle\*\N

    Ziel:

    C:\temp\Ziel\*\

    * - im Ordnerbereich steht für wechselnde Ordnerbezeichnungen.

    Die Lösung zum kopieren/verschieben bei bleibenden Quelle (nur eine Ebene höher) habe ich bereits.

    dir C:\temp\Quelle\*\N' -Include "*.txt" -Recurse | copy-item -Destination {$_.Directory.Parent.FullName} -Force

    dir C:\temp\Quelle\*\N' -Include "*.txt" -Recurse | move-item -Destination {$_.Directory.Parent.FullName} -Force

    Aber bei der Funktion copy-item mit einem anderen/externem Ziel und Dateien ein Ebene höher, da hänge ich irgendwie.

    Danke vorab für Eure Unterstützung

    Gruß DB


    • Bearbeitet darebo Mittwoch, 11. Juli 2018 11:16
    Mittwoch, 11. Juli 2018 09:58

Antworten

  • Es lag tatsächlich an der Powershell Version (bisher 2.x) im Einsatz.

    Jetzt geht alles.

    Hier der Lösungsansatz (funktioniert unter Powershell Version 2):

    $quelle = 'C:\Temp\Quelle' $ziel = 'C:\Temp\Ziel' gci $quelle | ?{$_.PSIsContainer} | %{ $target = "$ziel\$($_.Name)" if(!(test-Path $target)){md $target -Force | out-null}

    gci "$($_.FullName)\N" -Filter *.txt -Recurse | ?{!$_.PSIsContainer} | copy-item -Destination $target -Verbose }


    Danke und Gruß


    Freitag, 13. Juli 2018 07:59

  • $quelle = 'C:\Temp\Quelle' $ziel = 'C:\Temp\Ziel' gci $quelle | ?{$_.PSIsContainer} | %{ $target = "$ziel\$($_.Name)" if(!(test-Path $target)){md $target -Force | out-null}

    gci "$($_.FullName)\N" -Filter *.txt -Recurse | ?{!$_.PSIsContainer} | copy-item -Destination $target -Verbose }

    Nur mal noch einen Tipp: Du tust Dir selbst und im Zweifel auch allen Anderen einen riesen Gefallen, wenn Du in Scripten und speziell in Foren auf Aliasse verzichtest und besser noch Deinen Code so ausführlich wie möglich schreibst. Er lässt sich so deutlich besser lesen, verstehen und debuggen. Vernünftiges Einrücken und Formatieren hilft dabei zusätzlich. Wenn jemand anders sich den Code ansieht, hat er ja nicht die gleichen Gedanken im Kopf, wie Du beim ursprünglichen Schreiben des Codes.  ... und in 6 Monaten z.B. bist auch Du ein anderer Mensch und musst Dich dann im Zweifel wieder in Deinen eigenen Code "reindenken".  ;-)   ... ich zeig Dir mal, was ich meine.

    $quelle = 'C:\Temp\Quelle'
    $ziel = 'C:\Temp\Ziel'
    Get-ChildItem -Path $quelle |
        Where-Object {$_.PSIsContainer} |
            ForEach-Object{
                $target = "$ziel\$($_.Name)"
                if ( -not ( Test-Path -Path $target )){
                    New-Item -Path $target -ItemType Directory -Force | out-null
                }
                Get-ChildItem -Path "$($_.FullName)\N" -Filter *.txt -Recurse |
                    Where-Object {-not $_.PSIsContainer} |
                        Copy-Item -Destination $target -Verbose
            }

    Eine gute Lektüre in der Richtung ist der Powershell Best Practice & Style Guide.

    Abschließend vielelicht noch ein Wort zu Powershell v2.0: Wir haben 2018!! Wenn Du nicht shcon angefangen hast, empfehle ich dringend, endlich auf eine aktuellere Version umzusteigen ... und nicht nur ich ;-)  Windows Powershell 2.0 Deprecation.

    BTW: der von mir weiter oben gepostete Code sollte bis auf den Parameter -File auch auf PS v2.0 laufen. Hast Du's mal getestet?


    Best regards,

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






    Freitag, 13. Juli 2018 09:23

Alle Antworten

  • HI;

    sehr quick und sehr dirty

    $Dateien=Get-childItem -Path "D:\Test\von" -Recurse|select name,Fullname 
    
    $Textdatei="D:\Test\nach"
    $nichtTextdatei="D:\Test\nach\Excel\"
    
    foreach ($item in $Dateien)
    {
    
    
    if ($item.name -like "*.txt")
    {
      Copy-Item -path $item.fullname -Destination $Textdatei
    }
    
    if ($item.name -notlike "*.txt")
    {
      $zieldatei=$nichtTextdatei + $item.Name
      copy-item  -Path $item.FullName -Destination $zieldatei
    
        
    }
    
    }


    Toni

    Mittwoch, 11. Juli 2018 10:42
  • Hallo,

    danke für den Lösungsansatz. Leider ist das noch nicht die Lösung.

    Deine Lösung kopiert alle *.txt Dateien in einen Zielordner. Die *.txt Dateien sollen aber im Ziel nur einen Ordner höher vom Quellordner rutschen.

    Beispiel:

    Quellen:

    C:\temp\Quelle\1\N
    C:\temp\Quelle\2\N
          bis
    C:\temp\Quelle\10000\N

    Ziel:

    C:\temp\Ziel\1
    C:\temp\Ziel\2
          bis
    C:\temp\Ziel\10000

    Wobei die Ordnernamen mit Zahlen nur als Beispiel dienen sollen. Diese Ordnernamen sind in der Praxis willkürlich/unterschiedlich benannt.

    Hoffe ich habe mich verständlich ausgedrückt.

    Danke.

    DB





    • Bearbeitet darebo Mittwoch, 11. Juli 2018 11:13
    Mittwoch, 11. Juli 2018 11:07
  • Nun, C:\temp\Quelle\1\N zu C:\temp\Ziel\1\ ist für mich nicht eine Ebene höher sondern ein ganz anderer Ordner.
    Wenn ich eine Ebene höher kopieren möchte gebe ich als Ziel ".." an.
    ".." ist immer der übergordnete Ordner:

    copy-item "C:\temp\Quelle\1\N" -destination "C:\temp\Quelle\1\N\.."

    Oder wenn ich es abkürzen möchte:

    set-location -path "C:\temp\Quelle\1\N"
    copy-item -filter "*.txt" -destination ".."

    • Bearbeitet bfuerchau Mittwoch, 11. Juli 2018 11:17
    Mittwoch, 11. Juli 2018 11:15
  • Ja, der Zielbereich liegt wo anders. Daher fehlt mir hier der Lösungansatz

    Deshalb hatte ich es versucht verständlich zu beschreiben.

    Mittwoch, 11. Juli 2018 11:19
  • Diese Antwort verstehe ich nicht:

    "Deine Lösung kopiert alle *.txt Dateien in einen Zielordner. Die *.txt Dateien sollen aber im Ziel nur einen Ordner höher vom Quellordner rutschen."

    Gib doch die richtige Ebene des Zielordners an. Schau dir die Doku dazu an:
    https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/copy-item?view=powershell-6

    copy-item -path "C:\temp\Quelle\1\N" -filter "*.txt" -destination ""C:\temp\Ziel\1"

    oder

    copy-item -path "C:\temp\Quelle\1\N" -filter "*.txt" -destination ""C:\temp\Ziel"

    Mittwoch, 11. Juli 2018 11:28
  • Noch ein Versuch der Erklärung.

    Es gibt einen Quellbereich:

    C:\temp\Quelle\*\N

    * - steht für wechselnde Ordner (z.B. GUID)

    Bsp:

    C:\temp\Quelle\0A519B3F-17C1-4264-88B7-550D47ECC903\N\*.*
    C:\temp\Quelle\0A0554C4-7CD2-48D6-AB9B-5ACAA2E8B227\N\*.*
    C:\temp\Quelle\0CBCA949-9E83-4119-B3CD-5B3BFB9D8488\N\*.*
    C:\temp\Quelle\EB6B5212-1DEE-4FA7-B7D7-D32606B32D4D\N\*.*

    usw.

    In dem letzten Ordner befinden sich jeweils unterschiedliche Dateien/Dateitypen. Es sollen nur die .txt Dateien vom Quell- zum Zielbereich kopiert werden. Die Struktur des Quellbereiches soll nicht verändert werden.

    Aktuell ist der Zielbereich leer. Der Zielbereich soll schlussendlich nach der Kopieraktion fast die ähnliche Struktur wie der Quellbereich haben. Der Zielbereich liegt speichermäßig aber völlig woanders und die Dateien sollen eine Ebene höher rutschen. Zum Testen habe ich daher den nachfolgenden Bereich gewählt.

    C:\temp\Ziel\*\

    * - steht für wechselnde Ordner aus der Quelle (z.B. GUID)

    Bsp.:

    C:\temp\Ziel\0A519B3F-17C1-4264-88B7-550D47ECC903\*.txt
    C:\temp\Ziel\0A0554C4-7CD2-48D6-AB9B-5ACAA2E8B227\*.txt
    C:\temp\Ziel\0CBCA949-9E83-4119-B3CD-5B3BFB9D8488\*.txt
    C:\temp\Ziel\EB6B5212-1DEE-4FA7-B7D7-D32606B32D4D\*.txt
    usw.

    Ich hoffe jetzt ist es klarer beschrieben.







    • Bearbeitet darebo Mittwoch, 11. Juli 2018 12:08
    Mittwoch, 11. Juli 2018 11:54
  • Da wirst Du wohl mit den Pfaden was basteln müssen ... sowas könnte ein Ansatz sein:

    $SourceRoot = 'C:\Quelle'
    $DestinationRoot = 'C:\Ziel'
    Get-ChildItem -Path $SourceRoot -Filter *.txt -Recurse -File |
        ForEach-Object {
            $DestinationPath = $_.DirectoryName.Substring($SourceRoot.Length)
            $Target = Split-Path -Path (Join-Path -Path $DestinationRoot -ChildPath $DestinationPath)
            If(-not (Test-Path -Path $Target)){
                New-Item -Path $Target -ItemType Directory
            }
            Copy-Item -Path $_.FullName -Destination $Target
        }

    Probier ma

    Edit: Ziel-Verzeichnis-Erstellung hinzugefügt ... (hatte ich vergessen ;-)  )


    Best regards,

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




    • Bearbeitet BOfH_666 Donnerstag, 12. Juli 2018 12:06
    Mittwoch, 11. Juli 2018 15:24
  • Habe den Powershell Ansatz gerade getestet. Erhalte aber folgende Fehlermeldung:

    Get-ChildItem : Es wurde kein Parameter gefunden, der dem Parameternamen "File" entspricht.
    Bei Zeile:3 Zeichen:61
    + Get-ChildItem -Path $SourceRoot -Filter *.txt -Recurse -File <<<<  |
        + CategoryInfo          : InvalidArgument: (:) [Get-ChildItem], ParameterBindingException
        + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

    Darüber hinaus müsste ich bei der Quellangabe ($SourceRoot) überlegen bis zu welcher Tiefe und eventuellen Platzhalter (*) die Angabe erfolgen soll. Da ja ein Teil des Quellpfades unbekannt ist.

    z.B.: $SourceRoot = 'C:\temp\Quelle\*\N'

    Gruß

    Donnerstag, 12. Juli 2018 13:27
  • Erhalte aber folgende Fehlermeldung:

    Get-ChildItem : Es wurde kein Parameter gefunden, der dem Parameternamen "File" entspricht.

    Dann ist Deine Powershell zu alt ... lass es einfach weg, 'geht auch ohne ... das hätte man auch mal selbst debuggen können :-/

    Darüber hinaus müsste ich bei der Quellangabe ($SourceRoot) überlegen bis zu welcher Tiefe und eventuellen Platzhalter (*) die Angabe erfolgen soll. Da ja ein Teil des Quellpfades unbekannt ist.

    z.B.: $SourceRoot = 'C:\temp\Quelle\*\N'

    Das kannst Du ja machen, wie Du gerne magst und brauchst. Der Code ist nur ein Vorschlag, wie die "Mechanik" funktionieren könnte - für Deine Zwecke und Umgebung anpassen musst Du ihn dann schon selbst.  ;-)

    Best regards,

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


    Donnerstag, 12. Juli 2018 13:43
  • Moin,

    wie schon genannt sind es Hilfen und Hinweise.

    Eine Mischung daraus wird dir sicher helfen können und muss an deine Umgebung angepasst werden!

    Viel Erfolg!


    Toni

    Freitag, 13. Juli 2018 05:45
  • Es lag tatsächlich an der Powershell Version (bisher 2.x) im Einsatz.

    Jetzt geht alles.

    Hier der Lösungsansatz (funktioniert unter Powershell Version 2):

    $quelle = 'C:\Temp\Quelle' $ziel = 'C:\Temp\Ziel' gci $quelle | ?{$_.PSIsContainer} | %{ $target = "$ziel\$($_.Name)" if(!(test-Path $target)){md $target -Force | out-null}

    gci "$($_.FullName)\N" -Filter *.txt -Recurse | ?{!$_.PSIsContainer} | copy-item -Destination $target -Verbose }


    Danke und Gruß


    Freitag, 13. Juli 2018 07:59
  • Dann markier doch bitte auch noch die Lösung.Danke

    Toni

    Freitag, 13. Juli 2018 08:25

  • $quelle = 'C:\Temp\Quelle' $ziel = 'C:\Temp\Ziel' gci $quelle | ?{$_.PSIsContainer} | %{ $target = "$ziel\$($_.Name)" if(!(test-Path $target)){md $target -Force | out-null}

    gci "$($_.FullName)\N" -Filter *.txt -Recurse | ?{!$_.PSIsContainer} | copy-item -Destination $target -Verbose }

    Nur mal noch einen Tipp: Du tust Dir selbst und im Zweifel auch allen Anderen einen riesen Gefallen, wenn Du in Scripten und speziell in Foren auf Aliasse verzichtest und besser noch Deinen Code so ausführlich wie möglich schreibst. Er lässt sich so deutlich besser lesen, verstehen und debuggen. Vernünftiges Einrücken und Formatieren hilft dabei zusätzlich. Wenn jemand anders sich den Code ansieht, hat er ja nicht die gleichen Gedanken im Kopf, wie Du beim ursprünglichen Schreiben des Codes.  ... und in 6 Monaten z.B. bist auch Du ein anderer Mensch und musst Dich dann im Zweifel wieder in Deinen eigenen Code "reindenken".  ;-)   ... ich zeig Dir mal, was ich meine.

    $quelle = 'C:\Temp\Quelle'
    $ziel = 'C:\Temp\Ziel'
    Get-ChildItem -Path $quelle |
        Where-Object {$_.PSIsContainer} |
            ForEach-Object{
                $target = "$ziel\$($_.Name)"
                if ( -not ( Test-Path -Path $target )){
                    New-Item -Path $target -ItemType Directory -Force | out-null
                }
                Get-ChildItem -Path "$($_.FullName)\N" -Filter *.txt -Recurse |
                    Where-Object {-not $_.PSIsContainer} |
                        Copy-Item -Destination $target -Verbose
            }

    Eine gute Lektüre in der Richtung ist der Powershell Best Practice & Style Guide.

    Abschließend vielelicht noch ein Wort zu Powershell v2.0: Wir haben 2018!! Wenn Du nicht shcon angefangen hast, empfehle ich dringend, endlich auf eine aktuellere Version umzusteigen ... und nicht nur ich ;-)  Windows Powershell 2.0 Deprecation.

    BTW: der von mir weiter oben gepostete Code sollte bis auf den Parameter -File auch auf PS v2.0 laufen. Hast Du's mal getestet?


    Best regards,

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






    Freitag, 13. Juli 2018 09:23