Reputation: 361
I've got this function, that copy files to an directory and rename the duplicates. It's works very well. But, for any repeated file that was found, it popups the window with the replace, or keep files and rename.
Function Sync-FileArchive
{
[CmdletBinding(SupportsShouldProcess)]
[Alias('sfa')]
Param
(
[Parameter(Mandatory = $true, Position = 0)]
[string]$SourceFiles,
[Parameter(Mandatory = $true, Position = 1)]
[string]$Destination
)
$Counter = 0
Get-ChildItem -Path $SourceFiles |
ForEach{
Try
{
If(Test-Path -Path $Destination\$PSItem)
{
$Counter++
Write-Warning -Message "$($PSItem.Name) already exits. Renaming destination file."
Rename-Item -Path $Destination\$PSItem -NewName "$($PSItem.Basename)_$Counter$($PSitem.Extension)" -Force
}
Else
{
Write-Verbose -Message "$($PSItem.Name) does not exist. Copying file." -Verbose
Copy-Item -Path $PSItem.Fullname -Destination $Destination
}
}
Catch {$PSItem.Exception.Message}
}}
Is there a way to select by default the "Copy, but keep both files" and don't show the window?
Upvotes: 1
Views: 777
Reputation: 61178
For this you can use below function
function Copy-Unique {
# Copies files to a destination. If a file with the same name already exists in the destination,
# the function will create a unique filename by appending '(x)' after the name, but before the extension.
# The 'x' is a numeric sequence value.
[CmdletBinding(SupportsShouldProcess)] # add support for -WhatIf switch
Param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[Alias("Path")]
[ValidateScript({Test-Path -Path $_ -PathType Container})]
[string]$SourceFolder,
[Parameter(Mandatory = $true, Position = 1)]
[string]$DestinationFolder,
[Parameter(Mandatory = $false, Position = 2)]
[string]$Filter = '*',
[switch]$Recurse
)
# create the destination path if it does not exist
if (!(Test-Path -Path $DestinationFolder -PathType Container)) {
Write-Verbose "Creating folder '$DestinationFolder'"
New-Item -Path $DestinationFolder -ItemType 'Directory' -Force | Out-Null
}
# get a list of file FullNames in this source folder
$sourceFiles = @(Get-ChildItem -Path $SourceFolder -Filter $Filter -File | Select-Object -ExpandProperty FullName)
foreach ($file in $sourceFiles) {
# split each filename into a basename and an extension variable
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($file)
$extension = [System.IO.Path]::GetExtension($file) # this includes the dot
# get an array of all filenames (names only) of the files with a similar name already present in the destination folder
$allFiles = @(Get-ChildItem $DestinationFolder -File -Filter "$baseName*$extension" | Select-Object -ExpandProperty Name)
# for PowerShell version < 3.0 use this
# $allFiles = @(Get-ChildItem $DestinationFolder -Filter "$baseName*$extension" | Where-Object { !($_.PSIsContainer) } | Select-Object -ExpandProperty Name)
# construct the new filename
$newName = $baseName + $extension
$count = 1
while ($allFiles -contains $newName) {
$newName = "{0}({1}){2}" -f $baseName, $count, $extension
$count++
}
# use Join-Path to create a FullName for the file
$newFile = Join-Path -Path $DestinationFolder -ChildPath $newName
Write-Verbose "Copying '$file' as '$newFile'"
Copy-Item -Path $file -Destination $newFile -Force
}
if ($Recurse) {
# loop though each subfolder and call this function again
Get-ChildItem -Path $SourceFolder -Directory | Select-Object -ExpandProperty Name | ForEach-Object {
$newSource = (Join-Path -Path $SourceFolder -ChildPath $_)
$newDestination = (Join-Path -Path $DestinationFolder -ChildPath $_)
Copy-Unique -SourceFolder $newSource -DestinationFolder $newDestination -Filter $Filter -Recurse
}
}
}
and use it like
Copy-Unique -SourceFolder 'D:\Code\PowerShell' -DestinationFolder 'D:\Test' -Recurse -Verbose # -WhatIf
Upvotes: 1