Home > Enterprise >  Split property in array into many properties
Split property in array into many properties

Time:05-16

I use get-childitem to get files from directory structure.

Get-ChildItem $path -Recurse -include *.jpg,*.png | select-object Directory, BaseName, Extension

I get an array of objects with properties Directory, BaseName, Extension.

Like:

Directory                   BaseName       Extension
C:\dir1\dir2\dir3\dir4      file           txt

I wan't to break directory structure into multiple properties inside same array - each subdirectory level it's own property.

The end result properties should be (I can remove c:\ earlier in script):

dir1   dir2   dir3   dir4  Basename  Extension
dir1   dir2   dir3   dir4  file      txt

I used to export that to csv and import it back with delimiter to another array and than rebuilding the original array, but I think there must be an easier way!

CodePudding user response:

Here is a possible approach:

$path = 'C:\test'

$maxDepth = 0

Set-Location $path  # Set base path for Resolve-Path -Relative

# Get all files and splits their directory paths

$tempResult = Get-ChildItem $path -Recurse -include *.jpg,*.png | ForEach-Object {

    # Make directory path relative to $path
    $relPath = Resolve-Path $_.Directory -Relative

    # Create an array of directory path components, skipping the first '.' directory
    $dirNames = $relPath -replace '^\.\\' -split '\\|/'

    # Remember maximum directory depth
    $maxDepth = [Math]::Max( $dirNames.Count, $maxDepth )

    # Implicit output that PowerShell adds to $tempResult
    [PSCustomObject]@{
        dirNames = $dirNames
        fileInfo = $_ | Select-Object BaseName, Extension
    }
}

# Process $tempResult to add directory properties and file name properties

$finalResult = $tempResult.ForEach{
    $outProps = [ordered] @{}

    # Add directory properties
    for( $i = 0; $i -lt $maxDepth;   $i ) {
        $outProps[ "Dir$i" ] = if( $i -lt $_.dirNames.Count ) { $_.dirNames[ $i ] } else { $null }
    }

    # Add all fileInfo properties
    $_.fileInfo.PSObject.Properties.ForEach{ $outProps[ $_.Name ] = $_.Value } 

    # Implicit output that PowerShell adds to $finalResult
    [PSCustomObject] $outProps
}

$finalResult  # Output to console

This is done in two passes to ensure all output elements have the same number of directory properties:

  1. Iterate over all files and split their directory paths. Determine maximum directory depth (number of directory properties).
  2. Iterate over the intermediate result to create the desired objects consisting of directory properties and file name properties. This is done by first adding the properties to an ordered hashtable and then converting that hashtable to a PSCustomObject. This is easier and more efficient than using Add-Member.

Test input:

C:\test
    \subdir1
        file1.png
        file2.jpg
    \subdir2
        \subdir3
            file3.jpg

Output:

Dir0    Dir1    BaseName Extension
----    ----    -------- ---------
subdir1         file1    .png     
subdir1         file2    .jpg     
subdir2 subdir3 file3    .jpg     
  • Related