【问题标题】:Rename files in a bulk from csv file in Powerhshell从 Powershell 中的 csv 文件批量重命名文件
【发布时间】:2022-01-18 01:03:58
【问题描述】:

重命名 CSV 文件

我正在尝试编写一个脚本来使用 csv 作为索引文件来重新组织文件夹结构中的文件,但我不知道如何解决 Rename-Item 错误。

问题

  1. 是否有其他方法可以编写此脚本以便更轻松地获得相同的结果?
  2. 如何将正确的参数传递给 Rename-Item?

我的 csv 文件模板

folderName                          newName                                      oldName          
----------                          -------                                      -------          
01 Course Overview                  01_Course_Overview                           1280x720.mp4     
02 Introduction to PowerShell       01_Introduction to PowerShell                1280x720 (1).mp4 
02 Introduction to PowerShell       02_Who Is This Course For?                   1280x720 (2).mp4 
02 Introduction to PowerShell       03_What Is PowerShell?                       1280x720 (3).mp4 
02 Introduction to PowerShell       04_Windows PowerShell and PowerShell 7       1280x720 (4).mp4 

PowerShell 脚本

$csv = Import-Csv '.\index.csv' -Delimiter ';'
$newFolders = $csv.folderName | Sort-Object -Unique
$listFolders = Get-ChildItem -Directory | Select-Object Name
$listFiles = Get-ChildItem | Where {$_.extension -eq ".mp4"}

ForEach ($a in $newFolders){
    
    If ($listFolders.Name -contains $a){
        Write-Host "The Folder $a exist"
    }
    else{
        New-Item -Path $pwd.Path -Name $a -Type Directory | Out-Null
        Write-Host "The folder $a has been created"
    }

}

ForEach ($b in $csv){
    
    If ($listFiles.Name -contains $b.oldName){
        Write-Host "File $($b.oldName) exist"
        Write-Host "Renaming file to: "$($b.newName)"
        
        #Rename-Item $($b.oldName) -NewName $($b.newName)
        #Write-Host "Moving file to: "$($b.folderName)"
        #Move-Item .\$($b.newName) -Destination .\$($b.folderName)
    }
    else{
        Write-Host "File $($b.oldName) doesn't exist" `n
    }
    
}

执行重命名项目时出错

No D:\Downloads\Pluralsight\_PowerShell_Essentials\01_Powershell_Getting_Started\Temp\indexfiles.ps1:30 caractere:9
+         Rename-Item $($b.oldName) -NewName $($b.newName)
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (D:\Downloads\Pl...280x720 (2).mp4:String) [Rename-Item], ArgumentException
    + FullyQualifiedErrorId : RenameItemArgumentError,Microsoft.PowerShell.Commands.RenameItemCommand

【问题讨论】:

  • 你能给我们看看你的 csv 样本吗?
  • @AbrahamZinala 我在帖子中添加了 csv 文件模板。

标签: powershell csv


【解决方案1】:

这里有一个如何做到这一点的示例,这主要是一个测试用例,它将按照您在 CSV 上向我们展示的那样创建文件,并将它们移动到基于 folderName 列的新文件夹中。

代码将在当前目录中查找文件,然后使用该文件夹中的真实文件Set-Location (cd) 对其进行测试。

如果您不确定代码是否有效,您可以将-WhatIf 开关添加到Rename-ItemMove-Item

注意,我已从 newName 列中删除了 ?,因为它在 Windows 上是无效字符。详情请见this answer

# Go to a temporary folder for testing
Set-Location path/to/temporaryfolder/here

# Here you would use:
# $csv = Import-Csv path/to/csv.csv
$csv = @'
folderName                          newName                                      oldName
01 Course Overview                  01_Course_Overview                           1280x720.mp4
02 Introduction to PowerShell       01_Introduction to PowerShell                1280x720 (1).mp4
02 Introduction to PowerShell       02_Who Is This Course For                    1280x720 (2).mp4
02 Introduction to PowerShell       03_What Is PowerShell                        1280x720 (3).mp4
02 Introduction to PowerShell       04_Windows PowerShell and PowerShell 7       1280x720 (4).mp4
'@ -replace '  +',',' | ConvertFrom-Csv

# Create test files, this part is only for testing the code
$csv.foreach({ New-Item $_.oldName -ItemType File })

foreach($line in $csv)
{
    if(-not (Test-Path $line.folderName))
    {
        # Create the Folder if it does not exist
        New-Item $line.folderName -ItemType Directory -Verbose
    }
    Rename-Item -LiteralPath $line.oldName -NewName $line.newName
    Move-Item -LiteralPath $line.newName -Destination $line.folderName
}

【讨论】:

  • @chrispaiva 我猜这可能是因为您的文件名称中可能包含无效字符。查看我的更新,使用-LiteralPath 而不是-Path。希望它有效
  • 真的很好,更容易接近圣地亚哥,但我仍然遇到一些错误,我猜这是因为文件名的名称中有特殊字符。 MODO DETALHADO: Realizando a Operação "Renomear Arquivo" no destino "Item: D:\Downloads\Pluralsight_PowerShell_Essentials\01_Powershell_Getting_Started\Teste\1280x720 (3).mp4 Destino: D:\Downloads\Pluralsight_PowerShell_Essentials\01_Powershell_Getting_Started\Teste\03 PowerShell?”。
  • @chrispaiva 看到我上面的评论和使用-LiteralPath 的更新。它应该与它一起工作
  • 即使使用 -Literalpah 我也有错误,但因为像 这样的特殊字符? 我需要在 csv 中更正它或在 powershell 中替换它,然后更新 csv 以获得名称没有那些字符。感谢您的及时回复和帮助。
  • @chrispaiva 是的 ? 是一个无效字符,我绝对不建议在文件或文件夹上使用它。请参阅此答案以获取无效字符列表:stackoverflow.com/a/31976060/15339544。我很确定如果您从 CSV 中删除它们,脚本应该可以正常工作,只要原始文件也没有特殊字符
【解决方案2】:

如果我理解正确,您的真实 CSV 文件包含的文件夹和/或文件名包含无效字符,例如 ?

要解决此问题,您可以选择先从 CSV 文件中删除这些字符,或者确保在创建文件夹或重命名文件之前删除它们。
对于这两个选项,您都可以使用这个小辅助函数:

function Remove-InvalidNameChars {
    param(
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
        [String]$Name,

        [ValidateSet('File', 'Path')]
        [string]$Type ='File'
    )

    if ($Type -eq 'File') {
        $invalidChars = [IO.Path]::GetInvalidFileNameChars() -join ''
    }
    else {
        $invalidChars = [IO.Path]::GetInvalidPathChars() -join ''
    } 
    # build a regex string from the invalid characters
    $removeThese = "[{0}]" -f [RegEx]::Escape($invalidChars)
    # output the name with invalid characters removed
    $Name -replace $removeThese
}

方法一:从CSV文件中删除无效字符,使用清理后的数据:

$sourcePath = 'D:\Test'
$csvFile    = Join-Path -Path $sourcePath -ChildPath 'index.csv'
$csvData    = Import-Csv -Path $csvFile -Delimiter ';'
foreach ($item in $csvData) {
    $item.folderName = Remove-InvalidNameChars -Name $item.folderName -Type Path
    $item.newName    = Remove-InvalidNameChars -Name $item.newName -Type File
}
$csvData | Export-Csv -Path $csvFile -Delimiter ';' -Force  # rewrite the CSV file if you like

# now use the cleaned-up data in $csvData for the rest of the code:
foreach ($item in $csvData) {
    # create the output folder if this does not already exist
    $targetPath = Join-Path -Path $sourcePath -ChildPath $item.folderName
    $null = New-Item -Path $targetPath -ItemType Directory -Force
    # move and rename the file if found
    $sourceFile = Join-Path -Path $sourcePath -ChildPath $item.oldName
    if (Test-Path -Path $sourceFile -PathType Leaf) {
        $targetFile = Join-Path -Path $targetPath -ChildPath $item.newName
        Move-Item -Path $sourceFile -Destination $targetFile
    }
}

方法 2: 保留 csv 数据原样,并确保在重命名/移动时删除无效字符:

$sourcePath = 'D:\Test'
$csvFile    = Join-Path -Path $sourcePath -ChildPath 'index.csv'
$csvData    = Import-Csv -Path $csvFile -Delimiter ';'
foreach ($item in $csvData) {
    # create the output folder if this does not already exist
    $targetPath = Join-Path -Path $sourcePath -ChildPath (Remove-InvalidNameChars -Name $item.folderName -Type Path)
    $null = New-Item -Path $targetPath -ItemType Directory -Force
    # move and rename the file if found
    $sourceFile = Join-Path -Path $sourcePath -ChildPath (Remove-InvalidNameChars -Name $item.oldName -Type File)
    if (Test-Path -Path $sourceFile -PathType Leaf) {
        $targetFile = Join-Path -Path $targetPath -ChildPath (Remove-InvalidNameChars -Name $item.newName -Type File)
        Move-Item -Path $sourceFile -Destination $targetFile
    }
}

注意Move-Item可以同时将文件移动到新的目的地并重命名,所以你不需要Rename-Item


附:我注意到在您的示例 CSV 中,newName 文件名没有扩展名..
如果在现实生活中是这种情况,您还需要添加这些。

为此,将Move-Item 行更改为:

Move-Item -Path $sourceFile -Destination ([IO.Path]::ChangeExtension($targetFile, [IO.Path]::GetExtension($sourceFile)))

【讨论】:

  • 感谢您的贡献西奥。正则表达式是这里正在研究的另一门科学。 :-)
猜你喜欢
  • 1970-01-01
  • 2017-12-10
  • 1970-01-01
  • 1970-01-01
  • 2010-11-19
  • 2013-08-20
  • 2013-12-19
相关资源
最近更新 更多