Home > OS >  copy newer files without keeping folders
copy newer files without keeping folders

Time:11-19

I have a folder with a number of subfolders containing files and want to copy all files to the root folder but only overwrite if newer.

In powershell I can do -

Get-ChildItem D:\VaM\Custom\Atom\Person\Morphs\temp2\female -Recurse -file | Copy-Item -Destination D:\VaM\Custom\Atom\Person\Morphs\female

But this will overwrite all files, I only want to overwrite files if the copied file is newer.

robocopy can overwrite only older this but keeps the folder structure.

CodePudding user response:

Try this

$root = 'D:\VaM\Custom\Atom\Person\Morphs\temp2\female'
[bool]$Delete = $false

Get-ChildItem $root -Recurse -File |
    Where-Object {$_.DirectoryName -ne $root } | # Do not touch files already seated in root
    ForEach-Object {
        $rootNameBrother = Get-Item "$root\$($_.Name)" -ea 0
        if($rootNameBrother -and $rootNameBrother.LastWriteTime -lt $_.LastWriteTime) {
            # RootFile with same name exists and is Older - Copy and override
            Copy-Item -Path $_.FullName -Destination $rootNameBrother.FullName -Force
        }
        elseif ($rootNameBrother -and $rootNameBrother.LastWriteTime -ge $_.LastWriteTime) { 
            # RootFile with same name exists and is Newer or same Age
            # Delete non root File if allowed
            if($Delete) { Remove-Item $_.FullName -Force }
        }
    }

Set...

$Delete = $true

...if you wish to delete non root files that could not be copied because there already was a file with the same name and greater modiefydate in root.



You also can set the

$VerbosePreference = "Continue"
$WhatIfPreference = "Continue"

variables, just to be safe when you execute the script for the first time.



If you wish to delete all empty subfolder, you can run this:

$allFolders =`
Get-ChildItem $root -Recurse -Directory | 
ForEach-Object { 
    # Add now Depth Script Property
    $_ | Add-Member -PassThru -Force -MemberType ScriptProperty -Name Depth -Value { 
        # Get Depth of folder by looping through each letter and counting the backshlashes
        (0..($this.FullName.Length - 1) | ForEach {$this.FullName.Substring($_,1)} | Where-Object {$_ -eq "\"}).Count
    }
}

# Sort all Folder by new Depth Property annd Loop throught
$allFolders | Sort -Property Depth -Descending |
ForEach-Object {
    # if .GetFileSystemInfos() method return null, the folder is empty
    if($_.GetFileSystemInfos().Count -eq 0) { 
        Remove-Item $_.FullName -Force # Remove Folder 
    }          
}

CodePudding user response:

You can do it like this:

$source      = 'D:\VaM\Custom\Atom\Person\Morphs\temp2\female'
$destination = 'D:\VaM\Custom\Atom\Person\Morphs\female'

Get-ChildItem -Path $source -Recurse -File | ForEach-Object {
    # try and get the existing file in the destination folder
    $destFile = Get-Item -Path (Join-Path -Path $destination -ChildPath $_.Name) -ErrorAction SilentlyContinue
    if (!$destFile -or $_.LastWriteTime -gt $destFile.LastWriteTime) {
        # copy the file if it either did not exist in the destination or if this file is newer
        Write-Host "Copying file $($_.Name)"
        $_ | Copy-Item -Destination $destination -Force
    }
}
  • Related