Powershell - 查找包含文本的文件并将它们复制到新文件夹,重命名重复项

Powershell - find files containing text and copy them to new folder, rename duplicates

我正在用 Powershell 编写应用程序。该应用程序用于通过文件名中的字符串在源位置查找文件。必须将找到的文件复制到新位置。

我预计可能会有重复,并且必须在文件名末尾添加一个数字。

最后搜索到的字符串必须替换为新字符串(但我已经知道了)

我找到了一个脚本,它完全符合我的要求,但适用于位置上的所有文件,但不适用于搜索精确的字符串。我试过写一个,但有重复的问题...帮助已确定!

#### Function to check if duplicates exist and copy files ####

function fcopy ($SourceDir,$DestinationDir)
{
    Get-ChildItem $SourceDir -Recurse | Where-Object { $_.PSIsContainer -eq $false } | ForEach-Object ($_) {
        $SourceFile = $_.FullName
        $DestinationFile = $DestinationDir + $_
        if (Test-Path $DestinationFile) {
            $i = 0
            while (Test-Path $DestinationFile) {
                $i += 1
                $DestinationFile = $DestinationDir + $_.basename + $i + $_.extension
            }
        } else {
            Copy-Item -Path $SourceFile -Destination $DestinationFile -Verbose -Force
        }
        Copy-Item -Path $SourceFile -Destination $DestinationFile -Verbose -Force
    }
}

##### Call fcopy function ######
    
 fcopy -SourceDir $source -DestinationDir $destination

您可以使用下面的功能。如果目标文件夹中已存在具有重复名称的文件,它将复制与 -Filter 模式匹配的文件并在其名称后附加序列号:

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, DefaultParameterSetName = 'ByPath')]  # add support for -WhatIf switch
    Param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0, ParameterSetName = 'ByPath')]
        [Alias("Source")]
        [ValidateScript({Test-Path -Path $_ -PathType Container})]
        [string]$Path,

        [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0, ParameterSetName = 'ByLiteralPath')]
        [ValidateScript({Test-Path -LiteralPath $_ -PathType Container})]
        [string]$LiteralPath,

        [Parameter(Mandatory = $true, Position = 1)]
        [string]$Destination,

        [Parameter(Mandatory = $false)]
        [string]$Filter = '*',  # by default, filter allows any file pattern

        [switch]$Recurse
    )
    # create the destination path if it does not exist
    if (!(Test-Path -Path $Destination -PathType Container)) {
        Write-Verbose "Creating folder '$Destination'"
        $null = New-Item -Path $Destination -ItemType 'Directory' -Force
    }
    # get a list of file FullNames in this source folder
    if ($PSCmdlet.ParameterSetName -eq 'ByLiteralPath') {
        $sourceFiles = @(Get-ChildItem -LiteralPath $LiteralPath -Filter $Filter -File -Recurse:$Recurse)
    }
    else {
        $sourceFiles = @(Get-ChildItem -Path $Path -Filter $Filter -File -Recurse:$Recurse)
    }
    foreach ($file in $sourceFiles) {
        # get an array of all filenames (names only) of the files with a similar name already present in the destination folder
        $destFiles = @((Get-ChildItem $Destination -File -Filter "$($file.BaseName)*$($file.Extension)").Name)
        # for PowerShell version < 3.0 use this
        # $destFiles = @(Get-ChildItem $Destination -Filter "$baseName*$extension" | Where-Object { !($_.PSIsContainer) } | Select-Object -ExpandProperty Name)

        # construct the new filename
        $newName = $file.Name
        $count = 1
        while ($destFiles -contains $newName) {
            $newName = "{0}({1}){2}" -f $file.BaseName, $count++, $file.Extension
        }
        # use Join-Path to create a FullName for the file
        $newFile = Join-Path -Path $Destination -ChildPath $newName
        Write-Verbose "Copying '$($file.FullName)' as '$newFile'"

        $file | Copy-Item -Destination $newFile -Force
    }
}

# you can change the folder paths, file pattern to filter etc. here
Copy-Unique -Path 'D:\Test' -Destination 'D:\Destination' -Filter '*.ps1' -Recurse