Export CSV: file structure with folders as columns

Viewed 53

My question is quite similar to one posted here: Export CSV. Folder, subfolder and file into separate column

I have a file and folder structure containing possibly up to 10 folders deep and I want to run PowerShell to create a hash table that writes each file into a row, with each of the folders as a separate column, and then the filename at a dedicated column.

I start off with gci -path C:\test -file -recurse|export-csv C:\temp\out.csv -notypeinformation But this produces the standard table with some of the info I need but the directory is of course presented as one long string.

I'd like to get an output where each folder and its subfolder that houses the file to be presented as a column.

C:\Test\Folder1\Folder2\Folder3\file.txt to be presented as

Name Parent1 Parent2 Parent3 Parent4 Parent5 Parent6 Filename
file.txt Folder1 Folder2 Folder3 file.txt
image1.png Folder1 image.1png
Doc1.docx Folder1 Folder2 Folder3 Folder4 Folder5 Folder6 Doc1.docx
table3.csv Folder1 Folder2 table3.csv

As you can see there are some files which have just one folder whereas others could stored in several folders deep. I need to keep this consistent, as I want to use Power Automate and the File system connector to read the file paths using the Excel table and then parse and create the file into SharePoint using the parent/folder levels as metadata/column in the document library.

I took zett42's code from the linked question and modified it.

$allItems = Get-ChildItem C:\Test -File -Recurse | ForEach-Object {

    # Split on directory separator (typically '\' for Windows and '/' for Unix-like OS)
    $FullNameSplit = $_.FullName.Split( [IO.Path]::DirectorySeparatorChar )  

    # Create an object that contains the splitted path and the path depth.
    # This is implicit output that PowerShell captures and adds to $allItems.
    [PSCustomObject] @{ 
        FullNameSplit = $FullNameSplit
        PathDepth     = $FullNameSplit.Count
        Filename = $_.Name
    }

}

# Determine highest column index from maximum depth of all paths.
# Minus one, because we'll skip root path component.
$maxColumnIndex = ( $allItems | Measure-Object -Maximum PathDepth ).Maximum - 1

$allRows = foreach( $item in $allItems ) {

    # Create an ordered hashtable
    $row = [ordered]@{}

    # Add all path components to hashtable. Make sure all rows have same number of columns.
    foreach( $i in 1..$maxColumnIndex ) {
        $row[ "Filename" ] = $item.Filename
        $row[ "Column$i" ] = if( $i -lt $item.FullNameSplit.Count ) { $item.FullNameSplit[ $i ] } else { $null }
        
    }

    # Convert hashtable to object suitable for output to CSV.
    # This is implicit output that PowerShell captures and adds to $allRows.
    [PSCustomObject] $row
} 

I can get the filename to show as a separate column but I don't want the script to add the filename at the last column. PowerShell allrows output screenshot

Thanks

1 Answers

I've answered my own question.

Modified zett42's script, and included a few variables around splitting around just the Name of from GetChild-Item as opposed to the FullName and then of course the fixed column with just the filename in the hash table.

$allItems = Get-ChildItem C:\Test -File -Recurse | ForEach-Object {

    # Split on directory separator (typically '\' for Windows and '/' for Unix-like OS)
   # $FullNameSplit = $_.FullName.Split( [IO.Path]::DirectorySeparatorChar )
    $FullNameSplit = split-path -Path $_.FullName
    $DirNameSplit = $FullNameSplit.Split( [IO.Path]::DirectorySeparatorChar )

    # Create an object that contains the splitted path and the path depth.
    # This is implicit output that PowerShell captures and adds to $allItems.
    [PSCustomObject] @{ 
        #FullNameSplit = $FullNameSplit
        #PathDepth     = $FullNameSplit.Count
        DirNameSplit = $DirNameSplit
        PathDepth     = $DirNameSplit.Count
        Filename = $_.Name
    }

}

# Determine highest column index from maximum depth of all paths.
# Minus one, because we'll skip root path component.
$maxColumnIndex = ( $allItems | Measure-Object -Maximum PathDepth ).Maximum - 1

$allRows = foreach( $item in $allItems ) {

    # Create an ordered hashtable
    $row = [ordered]@{}

    # Add all path components to hashtable. Make sure all rows have same number of columns.
    foreach( $i in 1..$maxColumnIndex ) {
        $row[ "Filename" ] = $item.Filename
       #$row[ "Column$i" ] = if( $i -lt $item.FullNameSplit.Count ) { $item.FullNameSplit[ $i ] } else { $null }
       $row[ "Parent$i" ] = if( $i -lt $item.DirNameSplit.Count ) { $item.DirNameSplit[ $i ] } else { $null }
      #  $row[ "Column$i" ] = $item.DirNameSplit[$i]
        
    }

    # Convert hashtable to object suitable for output to CSV.
    # This is implicit output that PowerShell captures and adds to $allRows.
    [PSCustomObject] $row
} 
Related