Powershell:查找具有特定名称的文件夹,并将内容上移一级,如果存在则重命名

e37o9pze  于 2023-03-08  发布在  Shell
关注(0)|答案(2)|浏览(154)

我已经完成了前三分之二的部分,但是我在最后一部分卡住了。我有一个脚本,它搜索具有特定名称的子文件夹,并将其内容向上移动一级。我还有一个脚本,它将文件从一个地方移动到另一个地方,如果文件已经存在,则重命名它们。我现在要做的是合并这两个脚本。下面是向上移动文件的脚本:

$sourceDir="E:\Deep Storage"
$searchFolder="Draft Materials"

Get-ChildItem  -path $sourceDir -filter $searchFolder -Recurse | 
    ForEach-Object {
        Get-ChildItem -File -Path $_.FullName |
            ForEach-Object {
                Move-Item -Path $_.FullName -Destination $(Split-Path -Parent $_.PSParentPath)
            }
    }

这里有一个在重命名已经存在的东西时移动它们的方法:

$sourceDir="E:\Test1"
$targetDir="E:\Deep Storage\Test1"

Get-ChildItem -Path $sourceDir -Filter *.* -Recurse | ForEach-Object {
    $num=1
    $nextName = Join-Path -Path $targetDir -ChildPath $_.name

    while(Test-Path -Path $nextName)
    {
       $nextName = Join-Path $targetDir ($_.BaseName + "_$num" + $_.Extension)    
       $num+=1   
    }

    $_ | Copy-Item -Destination $nextName -Verbose
}

最后,我尝试将两者杂交:

$sourceDir="E:\Deep Storage"
$searchFolder="Draft Materials"

Get-ChildItem  -path $sourceDir -filter $searchFolder -Recurse | 
    ForEach-Object {
        Get-ChildItem -File -Path $_.FullName |
            ForEach-Object {
    $num=1
    $nextName = Join-Path -Path $_.FullName -Destination $(Split-Path -Parent $_.PSParentPath)

    while(Test-Path -Path $nextName)
    {
       $nextName = Join-Path -Path $_.FullName -Destination $(Split-Path -Parent $_.PSParentPath) ($_.BaseName + "_$num" + $_.Extension)    
       $num+=1   
    }

    $_ | Copy-Item -Destination $nextName
}
    }

我觉得我的思路是对的,但经过两个小时的尝试,我还是没能让它工作。
编辑:提供我给出的确切语法

$sourceDir="E:\Deep Storage\Projects"
$searchFolder="Draft Materials"
$destinationPath = "$($sourceDir)\.."

Write-Host "OPERATION: Search for Folders Named" -ForegroundColor White -BackgroundColor DarkGreen -NoNewLine;
Write-Host " '$searchFolder' " -ForegroundColor Yellow -BackgroundColor DarkGreen -NoNewLine;
Write-Host "and Move Contents Up One Level" -ForegroundColor White -BackgroundColor DarkGreen;
Write-Host "SEARCHDIR: $sourceDir" -ForegroundColor White -BackgroundColor DarkGreen;

# Get all directories in specific folders inside the source directory
$folders = Get-ChildItem -Path $sourceDir -Directory | Where-Object {$_.Name -like "$searchFolder*" -or $_.FullName -like "*\$searchFolder\*"}

foreach ($folder in $folders) {
    # Get all files in the current folder
    $files = Get-ChildItem -Path $folder.FullName

    foreach ($file in $files) {
        $destinationFile = Join-Path -Path $destinationPath -ChildPath $file.Name
        if (Test-Path $destinationFile) {
            # If a file with the same name exists in the destination directory, rename it
            $name = $file.Name
            $extension = $file.Extension
            $i = 0
            while (Test-Path $destinationFile) {
                $i++
                $name = "{0}_{1}{2}" -f ($file.BaseName, $i, $extension)
                $destinationFile = Join-Path -Path $destinationPath -ChildPath $name
            }
            Write-Host "Renaming $($file.Name) to $name"
        }
        Move-Item $file.FullName $destinationFile -Verbose -WhatIf
    }

}
3pvhb19x

3pvhb19x1#

以下是我阅读OP的帖子、代码和评论后得出的结论:

$sourcePath      = 'E:\Deep Storage\Projects'   
$searchFolder    = 'Draft Materials'

Write-Host "OPERATION: Search for Folders Named" -ForegroundColor White -BackgroundColor DarkGreen -NoNewLine;
Write-Host " '$searchFolder' " -ForegroundColor Yellow -BackgroundColor DarkGreen -NoNewLine;
Write-Host "and Move Contents Up One Level" -ForegroundColor White -BackgroundColor DarkGreen;
Write-Host "SEARCHDIR: $sourcePath" -ForegroundColor White -BackgroundColor DarkGreen;

# Get all directories in specific folders inside the source directory
$folders = (Get-ChildItem -LiteralPath $sourcePath -Directory -Recurse) | Where-Object Name -match $searchFolder

### Check selected folders
    $Folders.FullName | Out-GridView -Title 'Selected Folders'
    Read-Host 'Paused. Check selected folders in GridView. Press <enter> to continue '
###

ForEach ($folder in $folders)
{
    # Get all files in the current folder
    $filesToCopy   = $folder | Get-ChildItem -File
    # Get list of names for exising files in target (parent folder)
    $targetPath    = $folder.Parent.FullName
    $filesInTarget = (Get-ChildItem -LiteralPath $targetPath -File).Name

    ForEach ($file in $filesToCopy)
    {
        If ($file.Name -notIn $filesInTarget)
        {
            $file | Move-Item -Destination $targetPath -Verbose -WhatIf
        }
        Else
        {
            $i = 0
            Do
            {
                $newName = '{0}_{1}{2}' -f ($file.BaseName, $i++, $file.Extension)
            } Until ( $newName -notIn $FilesInTarget )

            Write-Host ('Renaming "{0}" to "{1}"...' -f $file.Name , $newName)

            $file | Move-Item -Destination (Join-Path $targetPath $newName) -Verbose -WhatIf
        }
    }
    # Delete (hopefully empty) folder
    If (!($folder | Get-ChildItem -Force))
    {
        $folder | Remove-Item -WhatIf
    }
    Else
    {
        Write-Host ('Items still exist in "{0}". Folder not deleted.' -f $folder.FullName)
    }
}

*语法选择:对于具有Path/LiteralPath参数集(gci、Copy、Move、Rename等)的任何cmdlet,System.IO.FileSystemInfo | <Cmdlet>语法可以成功处理<Cmdlet> -Path (System.IO.FileSystemInfo).FullNaame表单中失败的项目,因为其名称中的特殊字符需要-LiteralPath参数。

在许多情况下,将-Path替换为-LiteralPath(或其别名:-lp)也可以。但是管道格式在扫描代码时读起来“更干净”(IMHO),如果你刚刚学习PowerShell,提醒你尽可能考虑管道化,避免中间变量。为了笑一笑,下面是上面代码的一个版本,使用ForEach-Object尽可能多地管道化项目:

(Get-ChildItem -LiteralPath $sourcePath -Directory -Recurse) |
     where Name -match $searchFolder |
 ForEach-Object {
     # Get list of names for exising files in target (parent folder)
     $targetPath    = $_.Parent.FullName
     $filesInTarget = (Get-ChildItem -LiteralPath $targetPath -File).Name

     $_ | Get-ChildItem -File | ForEach-Object {
         If ($_.Name -notIn $filesInTarget)
         {
             $_ | Move-Item -Destination $targetPath -Verbose -WhatIf
         }
         Else
         {
             $i = 0
             Do
             {
                 $newName = '{0}_{1}{2}' -f ($_.BaseName, $i++, $_.Extension)
             } Until ( $newName -notIn $FilesInTarget )

             Write-Host ('Renaming "{0}" to "{1}"...' -f $_.Name , $newName)

             $_ | Move-Item -Destination (Join-Path $targetPath $newName) -Verbose -WhatIf
         }
     }
     # Delete (hopefully empty) folder
     If (!($_ | Get-ChildItem -Force))
     {
         $_ | Remove-Item -WhatIf
     }
     Else
     {
         Write-Host ('Items still exist in "{0}". Folder not deleted.' -f $_.FullName)
     }
 }
knpiaxh1

knpiaxh12#

请尝试以下操作:

$sourcePath = "C:\temp\test\Test"
$destinationPath = "$($sourcePath)\.."

# Get all files in the source directory
$files = Get-ChildItem -Path $sourcePath

foreach ($file in $files) {
    $destinationFile = Join-Path -Path $destinationPath -ChildPath $file.Name
    if (Test-Path $destinationFile) {
        # If a file with the same name exists in the destination directory, rename it
        $name = $file.Name
        $extension = $file.Extension
        $i = 0
        while (Test-Path $destinationFile) {
            $i++
            $name = "{0}_{1}{2}" -f ($file.BaseName, $i, $extension)
            $destinationFile = Join-Path -Path $destinationPath -ChildPath $name
        }
        Write-Host "Renaming $($file.Name) to $name"
    }
    Move-Item $file.FullName $destinationFile
}

这不会删除原始位置,而是将所有内容从sourcePath移动到父位置。要删除原始位置,只需在末尾添加:

Remove-Item -Path $sourcePath -Force -Confirm:$false

更新1:

$sourcePath = "C:\temp\test\Test"
$destinationPath = "$($sourcePath)\.."

# Get all directories in specific folders inside the source directory
$folders = Get-ChildItem -Path $sourcePath -Directory | Where-Object {$_.Name -like "Folder1*" -or $_.FullName -like "*\Folder2\*"}

foreach ($folder in $folders) {
    # Get all files in the current folder
    $files = Get-ChildItem -Path $folder.FullName

    foreach ($file in $files) {
        $destinationFile = "$($folder.FullName)\.."
        if (Test-Path $destinationFile) {
            # If a file with the same name exists in the destination directory, rename it
            $name = $file.Name
            $extension = $file.Extension
            $i = 0
            while (Test-Path $destinationFile) {
                $i++
                $name = "{0}_{1}{2}" -f ($file.BaseName, $i, $extension)
                $destinationFile = Join-Path -Path $destinationPath -ChildPath $name
            }
            Write-Host "Renaming $($file.Name) to $name"
        }
        Move-Item $file.FullName $destinationFile
    }

}

相关问题