Search code examples
windowspowershellget-childitemcopy-item

Powershell copying specific files from all subfolders to a single folder


I'm trying to copy all of the cover.jpg files in my music library to one folder. My attempts so far have either landed me with one file in the destination, or every desired file but also in their own folder matching the source (i.e. folders named for each album containing just the cover.jpg file).

Get-ChildItem "C:\Music" -recurse -filter *.jpg | Copy-Item -Destination "C:\Destination"

I realised that the copy-item command was simply overwriting the previous copies thus leaving me with only one file. I then tried going down the renaming route by moving the file then renaming it but of course that failed as the folder I was basing the rename off has now changed. I don't want to change the name of the file before I copy it as other programs still need the cover.jpg to function.

My question is... Does anybody know how to recursively look through each folder in my music library to find the cover.jpg file, rename it to match the parent folder (or even if possible, grandparent and parent) then copy that file to a new folder making sure to not copy or create any new folders in this destination?

As a bonus, could this check if a file already exists so that if I ran it in the future only new files will be copied?

The file structure for the library is pretty simple. \Music\Artist\Album title\cover.jpg


Solution

  • If you have a music library structure like that, the easiest way would be to use the properties Directory and Parent each FileInfo object returned by Get-ChildItem contains:

    $sourcePath  = 'C:\Music'
    $destination = 'C:\Destination'
    
    # if the destination folder does not already exist, create it
    if (!(Test-Path -Path $destination -PathType Container)) {
        $null = New-Item -Path $destination -ItemType Directory
    }
    
    
    Get-ChildItem -Path $sourcePath -Filter '*.jpg' -File -Recurse | ForEach-Object {
        $newName = '{0}_{1}_{2}' -f $_.Directory.Parent.Name, $_.Directory.Name, $_.Name
        $_ | Copy-Item -Destination (Join-Path -Path $destination -ChildPath $newName)
    }