基于 PowerShell 中的电子表格批量重命名文件的建议?

Recommendations for batch renaming files based on a spreadsheet in PowerShell?

我们办公室最近从一个研究项目管理系统迁移到另一个。我们收到了一大堆数据 tables,其中包含个别研究文件的人行横道。最终结果是数千个文件夹,每个文件夹包含一到数百个文档,所有文档都有一个非常通用的名称(例如 Document_1234)。我们有一个数据 table 电子表格,告诉我们每个文件最初的名称(例如 Document_1234 = Study Protocol 2020-05-01)。使用人行横道非常痛苦。我想做的是遍历这些文件夹,检查每个文件名,如果电子表格中的文件名匹配(例如,将其称为第 1 列),则将其替换为相应的原始文件名(来自第 2 列)。虽然文件是按顺序编号的,但它们是唯一的——所有文件夹中的所有文件都列在同一个人行横道电子表格中,因此我必须遍历电子表格的每一行,以查找包含需要重命名的文件的每个单独文件夹。数据位于安全的网络共享驱动器上。

可以访问 PowerShell,但仅此而已(锁定公司环境,未安装其他脚本语言。)

脚本大部分工作正常,但有一些我无法弄清楚的错误。

具体来说:

  1. 名称冲突 - 脚本在小型测试目录上运行良好,但在完整数据集的较大副本上不会自动递增文件名。我要么看到文件存在错误,要么根本没有错误。
  2. 错误 - Try/Catch 块实际上并未捕获所有错误。如果我让它捕获名称冲突,它就会错过非法文件名,反之亦然。我尝试将错误推送到单独的散列中以供后续跟进,但效果并不一致。
  3. 完成 - 在我的数据测试副本上尝试 运行 这会导致大量文件未重命名。没有错误来解释原因。手动搜索未重命名的特定文件的数据集显示集合中存在 key/value 对,但我无法确定这是代码错误还是数据错误。任何建议都会有所帮助。
# path to target folder
$path = $args[0];
# csv file listing CURRENT filename, NEW filename
# source file lists 'filename.ext, newfilename' (no extension)
$source = $args[1];
# hash to store current/new names
$hash = @{}
# hash to store errors
$errorhash = @{};
# import the csv file and loop through each line to populate hash
foreach ($item in (Import-Csv -Path $source)) {
    $hash[$item.CURRENT] = $item.NEW
    }
# look in the $path directory for files with these names
foreach ($file in (Get-ChildItem -Path $path -File -Recurse)) {
    # does the directory have a matching file?
    if ($hash.ContainsKey($file.Name)) {
        Try {
            # check whether we can just rename the file. can we?
            # counter
            $num = 1;
            # variables for new name, file path, extension, and new name including path
            $newname = $hash[$file.Name];
            $filepath = Split-Path -Path $file.FullName;
            $ext = $file.Extension;
            # i need to check whether the renamed file already exists
            # feels unnecessary to use 2 lines, but does not seem to work if combined in one line
            $newfull = $newname+$ext;
            $foo = Join-Path -Path $filepath -ChildPath $newfull;
            # check if the file exists, and if so, increment file name by appending counter
            while(Test-Path -Path $foo) {
                # filename collision errors here are not caught in the Try: never gets pushed to the hash?
                $newname = $hash[$file.Name] + "_$num";
                $newfull = $newname+$ext;
                $foo = Join-Path -Path $filepath -ChildPath $newfull;
                $num+=1;
                }
            # now that we have verified the filename doesn't already exist, rename the file
            $file | Rename-Item -NewName ('{0}{1}' -f $newname, $ext) -ErrorAction Continue
            }
        Catch {
            # error check: take the offending file name and add it to a new hash of errors
            $k = $file.FullName;
            $errorhash.Add($k, $hash[$file.Name]);
            }
        }
    }
# before we stop, write the hash of errors to a file
$errorhash.GetEnumerator() | Select-Object -Property Key,Value | Export-Csv -Path error.csv -NoTypeInformation

由于这是一个关于使用通用名称批量重命名文件的问题,请执行以下操作:

从 Excel,将(至少两个重要的列)保存为 CSV 文件

这个文件可能看起来像这样(从你的问题我收集只列出了 BaseNames):

"genericname","originalname"
"Document_1234","Study Protocol 2020-05-01"
"Document_1235","Working Protocol 2020-05-21"

接下来,在 PowerShell 中导入该 CSV 并从中创建一个查找哈希表,其中每个键来自 'genericname' 列,每个对应的值来自 'originalname' 列

# create a lookup Hashtable
$lookup = @{}
# import the CSV file and loop through to build up the $lookup hash
foreach ($item in (Import-Csv -Path 'D:\Test\filenames.csv')) {
    $lookup[$item.genericname] = $item.originalname
}

现在,获取文件并测试是否可以找到它们的 BaseName 作为哈希键之一

foreach ($file in (Get-ChildItem -Path 'X:\Path\To\The\RootFolder' -File -Recurse)) {
    # if the lookup hash has a Key for the file's BaseName
    if ($lookup.ContainsKey($file.BaseName)) {
        # rename the file with the value stored in the Hashtable
        $file | Rename-Item -NewName ('{0}{1}' -f $lookup[$file.BaseName], $file.Extension)
    }
}