none
Ordnerstruktur aus .csv anlegen RRS feed

  • Frage

  • Hallo zusammen, 

    folgendes Problem, ich habe eine .csv Datei bekommen mit knapp 60k Einträgen. Die Struktur der csv soll in Ordnern nachgebildet werden und in den tiefsten Ordner jeweils nochmal 3 Ordner. 

    Also die csv sieht so aus:

    test1;;;;;;;;;;
    ;2ordner ;;;;;;;;;
    ;o3;;;;;;;;;
    ;;;;;;;;;;
    test 2;;;;;;;;;;
    ;abc1;;;;;;;;;
    ;abc2;;;;;;;;;
    ;abc3;;;;;;;;;
    ;;aa1;;;;;;;;
    ;;aa2;;;;;;;;
    ;abc4;;;;;;;;;
    ;abc5;;;;;;;;;
    ;;;;;;;;;;
    gg1;;;;;;;;;;
    ;ggg1;;;;;;;;;
    ;;gggg1;;;;;;;;
    ;;;ggggg1;;;;;;;

    Da sollte dann so aussehen:

    test1\2ordner\A
    test1\2ordner\B
    test1\2ordner\C

    test1\o3\A
    test1\o3\B
    test1\o3\C

    test2\abc1\A
    test2\abc1\B
    test2\abc1\C

    test2\abc2\A
    test2\abc2\B
    test2\abc2\C

    test2\abc3\aa1\A
    ... usw.

    Die Ordner Struktur geht allerdings zum Teil bis zu 10 Ordner tief. 

    Das was ich bis her habe funktioniert auch echt gut mit meiner kleinen Test Datei aber sobald ich die große 60k Zeilen Datei reinlade geht gar nichts mehr und er hängt alle Ordner aneinander:

    test1\2ordner\o3\abc1\abc2\abc3\aa1\....

    $CSVPATH = 'C:\test\text4.csv'
    $ROOTFOLDER = 'C:\test\test'
    $FIXEDFOLDERS = 'A','B','C'
    # ---------------
    $content = Get-Content $CSVPATH -ReadCount 1000
    $level = 0
    $currentpath = @()
    foreach($line in $content){
        $cols = $line.replace('"','').split(';')
        if ($cols[0] -ne ""){
            $first = $cols[0]
        }else{
            0..($cols.Count-1) | %{
                if($cols[$_] -ne ""){
                    if($_ -gt $level){
                        $currentpath += $cols[$_]
                        $level = $_
                        return
                    }else{
                        $FIXEDFOLDERS | %{
                            md (Join-Path $ROOTFOLDER "$first\$($currentpath -join '\')\$_") -Force -Verbose
                        }
                        $currentpath = @($cols[$_])
                        $level = $_
                    }
                }
            }
        }
    }
    if ($level -gt 0){
        $FIXEDFOLDERS | %{
            md (Join-Path $ROOTFOLDER "$first\$($currentpath -join '\')\$_") -Force -Verbose
        }
    }



    Mittwoch, 28. August 2019 06:29

Antworten

  • Mit den Tips von Olaf: Steht in jeder Zeilde definitiv immer nur genau EIN Eintrag in einer der Spalten? Und immer wenn Spalte 1 was hat, soll ab da neu ein Verzeichnisbaum aufgebaut werden?

    Hilft jetzt wenig, aber aus welchem Konstrukt fällt so was dämliches heraus? Ich hab grad mal versucht, das in Skriptlogik abzubilden, aber das wird völlig verquer... Wir machen so was zwar sonst nie - aber das hat mich gereizt. Für Dich als Herausforderung: Ohne Kommentare und Erklärungen :-) Und das mit "A/B/C" als Unterordner noch dazu -Fingerübung auch für Dich :-)

    $list = import-csv .\ordnerliste.csv -Delimiter ';' -Header @(1..10)
    
    $currentlevel = 0
    $currentpath = 'c:\Daten\Test'
    
    foreach ( $line in $list ){
        $levelmembers = $line | Get-Member -MemberType NoteProperty
        foreach ( $levelmember in $levelmembers ){
            $levelnumber = [Int]$levelmember.name
            $levelname = $line.$levelnumber
            If ( $levelname ) {
                Switch -Regex ( $currentlevel ){
                    { $levelnumber -lt $currentlevel } {
                        For ( $i = $currentlevel; $i -gt $levelnumber; $i-- ){ $currentpath = Split-Path -Path $CurrentPath -Parent }
                        $currentlevel = $levelnumber
                    }
                    { $levelnumber -eq $currentlevel } {
                        $currentpath = Join-Path -Path $( Split-Path -Path $currentpath -Parent ) -ChildPath $levelname
                        break
                    }
                    { $levelnumber -gt $currentlevel } {
                        $currentpath = Join-Path -Path $Currentpath -ChildPath $levelname
                        $currentlevel += 1
                        break
                    }
                }
                $null = New-Item -Path $( Split-Path -Path $currentpath -Parent ) -Name $levelname -ItemType Directory -Force -ErrorAction SilentlyContinue
            }
        }
    }


    Greetings/Grüße, Martin - https://mvp.microsoft.com/en-us/PublicProfile/5000017 Mal ein gutes Buch über GPOs lesen? - http://www.amazon.de/Windows-Server-2012--8-Gruppenrichtlinien/dp/3866456956 Good or bad GPOs? My blog - http://evilgpo.blogspot.com And if IT bothers me? Coke bottle design refreshment - http://sdrv.ms/14t35cq




    Mittwoch, 28. August 2019 12:49

Alle Antworten

  • Beim ersten Überfliegen Deines Codes fällt mir auf, dass Du Deine CSV-Datei als Text-Datei behandelst. Ist das Absicht? Meistens ist es einfacher CSV-Dateien auch so zu behandeln - also wie strukturierte Daten. Das Einlesen könnte dann so aussehen:
    Import-Csv -Path 'C:\test\text4.csv' -Delimiter ';' -Header L1, L2, L3, L4, L5, L6, L7, L8, L9, L10, L11 | 
        Format-Table -AutoSize
    Ich hab die Spalten jetzt einfach mal mit L1 bis L11 benannt ... ;-)  ... probier ma!

    Live long and prosper!

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

    Mittwoch, 28. August 2019 06:51
  • Das war nicht die Lösung, das Problem ist das selbe. Allerding spuckt er jetzt noch einen Fehler mit aus:

    Method invocation failed because [Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData] does not contain a method named 'replace'.
    At C:\Users\kaiser\Desktop\Unbenannt1.ps1:9 char:5
    +     $cols = $line.replace('"','').split(';')
    +     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
        + FullyQualifiedErrorId : MethodNotFound



    Mittwoch, 28. August 2019 07:39
  • Das war nicht die Lösung, das Problem ist das selbe. Allerding spuckt er jetzt noch einen Fehler mit aus:

    Natürlich war das nicht die Lösung des Problems - so war das auch nciht gemeint. ;-)  Das könnte aber die Komplexität Deines Scriptes verringern. Die ganze String-Akrobatik, die Du benutzt, um die Text-Datei in verwendbare Stückchen zu zerlegen, sollte damit nicht mehr nötig sein. Natürlich musst Du den Rest des Scriptes dann noch daran anpassen.

    Live long and prosper!

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

    Mittwoch, 28. August 2019 08:34
  • Mit den Tips von Olaf: Steht in jeder Zeilde definitiv immer nur genau EIN Eintrag in einer der Spalten? Und immer wenn Spalte 1 was hat, soll ab da neu ein Verzeichnisbaum aufgebaut werden?

    Hilft jetzt wenig, aber aus welchem Konstrukt fällt so was dämliches heraus? Ich hab grad mal versucht, das in Skriptlogik abzubilden, aber das wird völlig verquer... Wir machen so was zwar sonst nie - aber das hat mich gereizt. Für Dich als Herausforderung: Ohne Kommentare und Erklärungen :-) Und das mit "A/B/C" als Unterordner noch dazu -Fingerübung auch für Dich :-)

    $list = import-csv .\ordnerliste.csv -Delimiter ';' -Header @(1..10)
    
    $currentlevel = 0
    $currentpath = 'c:\Daten\Test'
    
    foreach ( $line in $list ){
        $levelmembers = $line | Get-Member -MemberType NoteProperty
        foreach ( $levelmember in $levelmembers ){
            $levelnumber = [Int]$levelmember.name
            $levelname = $line.$levelnumber
            If ( $levelname ) {
                Switch -Regex ( $currentlevel ){
                    { $levelnumber -lt $currentlevel } {
                        For ( $i = $currentlevel; $i -gt $levelnumber; $i-- ){ $currentpath = Split-Path -Path $CurrentPath -Parent }
                        $currentlevel = $levelnumber
                    }
                    { $levelnumber -eq $currentlevel } {
                        $currentpath = Join-Path -Path $( Split-Path -Path $currentpath -Parent ) -ChildPath $levelname
                        break
                    }
                    { $levelnumber -gt $currentlevel } {
                        $currentpath = Join-Path -Path $Currentpath -ChildPath $levelname
                        $currentlevel += 1
                        break
                    }
                }
                $null = New-Item -Path $( Split-Path -Path $currentpath -Parent ) -Name $levelname -ItemType Directory -Force -ErrorAction SilentlyContinue
            }
        }
    }


    Greetings/Grüße, Martin - https://mvp.microsoft.com/en-us/PublicProfile/5000017 Mal ein gutes Buch über GPOs lesen? - http://www.amazon.de/Windows-Server-2012--8-Gruppenrichtlinien/dp/3866456956 Good or bad GPOs? My blog - http://evilgpo.blogspot.com And if IT bothers me? Coke bottle design refreshment - http://sdrv.ms/14t35cq




    Mittwoch, 28. August 2019 12:49
  • Was mir grad noch eingefallen ist: Man muss einen aus mehreren Unterordnern bestehenden Pfad nicht Unterordner für Unterordner erstellen. Das geht in einem Rutsch.

    Wenn Du also z.B. in D:\Sample anfangen möchtest und eine Struktur mit 5 Unterordnern erstellen möchtest, brauchst Du nicht 5 mal New-Item aufrufen. Es wird sogar noch besser - Du kannst New-Item ein Array an Ordnern mit Unterordnen verfüttern und die werden alle sozusagen in einem Rutsch angelegt.

    $OrdnerStrukturListe = @(
        'D:\sample\Subfolder1\Subfolder2\Subfolder3\and\so\on',
        'D:\sample\Subfolder1\Subfolder2\Subfolder3\or\something\like\this',
        'D:\sample\Something\Completely\New\here',
        'D:\sample\Something\Completely\New\and\there',
        'D:\sample\And\so\on\and\on\and\on'
    )
    
    New-Item -Path $OrdnerStrukturListe -ItemType Directory -Force
    Ich weiß ja nicht, wie dieses krude CSV-Konstrukt erstellt wird, aber vielleicht bekommst Du die nötige Ordnerstruktur ja auch in einem etwas leichter zu verarbeitendem Format.

    Live long and prosper!

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

    • Bearbeitet BOfH-666 Mittwoch, 28. August 2019 21:24
    Mittwoch, 28. August 2019 21:21