Search code examples
powershellrollbackcopy-item

Move File to new location where Parent Folder Name Matches


Problem

I am working on a rollback feature in my application in which I copy the files from a backup/rollback directory to a destination folder. As simple as that sounds, this is where it gets complicated. Due to all the files sharing the same or similar name, I used the parent folder as the anchor to help enforce unique locations.

I want to essentially recursively search a directory and wherever a folder name matches a parent directory of an object, paste a copy of the object into that folder, overwriting whatever file(s) share a name with said object.

A more visible way to represent this would be:

$Path = C:\Temp\MyBackups\Backup_03-14-2017
$destination = C:\SomeDirectory\Subfolder
$backups = GCI -Path "$Path\*.config" -Recursive

foreach ($backup in $backups) {
    Copy-Item -Path $backup -Destination $destination | Where-Object {
        ((Get-Item $backup).Directory.Name) -match "$destination\*"
    }
}

However, the above doesn't work and none of my research is finding anything remotely similar to what I'm trying to do.

Question

Does anyone know how to Copy an Item from one location to another in which the parent folder of the copied item matches a folder in the destination using PowerShell?


Solution

  • Enumerate the backed-up files, replace the source base path with the destination base path, then move the files. If you only want to replace existing files, test if the destination exists:

    Get-ChildItem -Path $Path -Filter '*.config' -Recursive | ForEach-Object {
        $dst = $_.FullName.Replace($Path, $destination)
        if (Test-Path -LiteralPath $dst) {
            Copy-Item -Path $_.FullName -Destination $dst -Force
        }
    }
    

    If you want to restore files that are missing in the destination make sure to create missing directories first:

    Get-ChildItem -Path $Path -Filter '*.config' -Recursive | ForEach-Object {
        $dst = $_.FullName.Replace($Path, $destination)
        $dir = [IO.Path]::GetDirectoryName($dst)
        if (-not (Test-Path -LiteralPath $dir -PathType Container)) {
            New-Item -Type Directory -Path $dir | Out-Null
        }
        Copy-Item -Path $_.FullName -Destination $dst -Force
    }