The behaviour I would expect from the code below is:
Grab a list of the files in the source directory.
Loop through and copy each file to the backup destination, only if it does not already exist.
if (!(Test-Path C:\Folder\Destination)) { New-Item -ItemType Directory -Force -Path C:\Folder\Destination } $originalfiles = Get-ChildItem -Path "C:\Folder\Source" $originalfiles foreach ($file in $originalfiles) { Write-Host Write-Host File Name: -ForegroundColor DarkYellow Write-Host $file.Name Write-Host File Path: -ForegroundColor DarkYellow Write-Host $file.FullName $src = $file.FullName $dest = "C:\Folder\Destination\$($file.Name)" Copy-Item $src $dest }
I would have thought that the Copy-Item cmdlet defaults to NOT overwrite, unless you specify the -Force flag. This is the behaviour I have seen in the past when I originally encountered situations where I did want to overwrite.
Also, I thought it may be the introduction of the foreach loop but I tried the copy command, on it's own, with hardcoded paths for a single file, and it is still the same.
Should I restart my IDE, or is it a mistake I have overlooked?
5 Answers
When in doubt, read the documentation.
-ForceIndicates that this cmdlet copies items that can't otherwise be changed, such as copying over a read-only file or alias.
The default behavior for Copy-Item is to replace existing items. The -Force switch is only to enforce replacement if for instance the destination file has the readonly attribute set.
You can use -Confirm to get prompted before Copy-Item performs the operation, or you can use -WhatIf to see what the cmdlet would do.
Old one, but I found a short expression that does that:
Copy-Item (Join-Path $dir_from "*") $dir_to -Exclude (Get-ChildItem $dir_to) It copies all files from $dir_from to $dir_to but not (the -Exclude part) the files with names that are already in $dir_to
It seems to be the expected behaviour of Copy-Item to copy an item to the destination even if it already exists in destination. I suggest to test, if the destination file path exists and only copy the file if it does not yet exist.
$destinationPath = 'C:\tryout\destination'; if (!(Test-Path $destinationPath)) { New-Item -ItemType Directory -Force -Path $destinationPath; } $sourcePath = 'C:\tryout\source'; $originalfiles = Get-ChildItem -Path $sourcePath; $originalfiles; foreach ($file in $originalfiles) { Write-Host; Write-Host File Name: -ForegroundColor DarkYellow; Write-Host $file.Name; Write-Host File Path: -ForegroundColor DarkYellow; Write-Host $file.FullName; $src = $file.FullName; $dest = "C:\tryout\destination\$($file.Name)"; if (!(Test-Path $dest)) { Copy-Item $src -Destination $dest; } } 1Here is a version of your code to copy files recursively only when they don't exist in target location. It creates subfolders if needed. It doesn't create empty folders; if you need them, remove -File from Get-ChildItem.
$srcDirPath = "C:\SourceDir" $destDirPath = "C:\DestinationDir" # Get list of files from source dir recursively. It doesn't list hidden files by default # Remove where{} if you don't need to exclude files by name, in this sample I exclude all README.md in any folders $fileList = Get-ChildItem -Path $srcDirPath -File -Recurse | where{$_.Name -ne 'README.md'} # get source dir path just in case to exactly match Get-ChildItem paths $fullSrcDirPath = (Get-Item -Path $srcDirPath).FullName foreach($file in $fileList) { # build full destination file path $destFilePath = $destDirPath + $file.FullName.Remove(0, $fullSrcDirPath.Length) # proceed only if file doesn't exist in destination if(-not (Test-Path "$destFilePath")) { # Copy-Item can't create subfolders, so create subfolder if it doesn't exist # Get full destination folder path for current file $curDestDir = Split-Path $destFilePath -Parent if(-not (Test-Path "$curDestDir")) { # create subfolder(s) # $res here suppresses output $res = New-Item -Path "$curDestDir" -ItemType "directory" } Copy-Item -Path $file.FullName -Destination "$destFilePath" } } Something quick if you're worried about overwriting:
function mycopy { if (! (test-path $args[1])) { copy $args[0] $args[1] } else { 'file exists' } } 1