重命名多个文件夹(可以处理错误!)



我是PowerShell的新手,已经编写了以下脚本,使用ISE,试图重命名同一目录中的一堆文件夹,这些文件夹的日期格式严格为20201130到2020-11-30(只需添加短划线(这个剧本有点用,但我有三个问题。

1-运行时抛出了一堆与Rename-Item有关的错误错误:

Rename-Item : Source and destination path must be different.
At line:13 char:25
+ ... ChildItem | Rename-Item -NewName { $_.Name -replace $file, $MyNewName ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : WriteError: (D:Google Drive...Term 2testings:String 
) [Rename-Item], IOException
+ FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.Renam 
eItemCommand

2-当我用一个名为(234567890(的文件夹测试它时,它仍然有效,尽管这个文件夹的长度不等于8!

3-当发生上述重命名时,得到的名称是";1234-56-7890";这很奇怪,因为CCD_ 2应该以2个字符结尾!$file.Substring( 6 , 2 )

脚本:

$FileNameArr_All = (Get-ChildItem).Name
$i = 0
foreach($file in $FileNameArr_All){

if ( ($file -match "^d+$") -and ($file.Length -eq 8) ){

[string] $MyNewName = $file.Substring( 0 , 4 )+"-"+$file.Substring( 4 , 2 )+"-"+$file.Substring( 6 , 2 )

#the actual renamining of the item, where the error is:
Get-ChildItem | Rename-Item -NewName { $_.Name -replace $file, $MyNewName }
$message = "the item " + $file + " has been renamed : " + $MyNewName
Write-Output $message
$i ++
Write-Output $file.Length
}
}
if ($i -eq 0){
Write-Output "No mathcing items found."
}
else{
$message2 = "total of items affected: " + $i
Write-Output $message2
}

我知道这太多了,但这是我的第一篇帖子,也是我的第一个剧本,我很感激能帮助我解决任何一点
非常感谢:(

现有的答案中有很好的信息,但让我从概念上总结一下,并提供一个更精简的解决方案:

  • 您正在循环所有目录名称单独。但由于仅使用Get-ChildItem(无参数(作为Rename-Item:的输入,您试图在每次循环迭代中重命名所有

    • Get-ChildItem | Rename-Item ...所有文件和子目录发送到Rename-Item;您实际上是在尝试将所有文件重命名为其现有的名称(请参阅下一个要点(,这对于文件来说是一个安静的无操作,但会触发您在目录中看到的Source and destination path must be different错误
  • $MyNewName完整的新文件名,因此没有理由在原始目录名上使用-replace:由于$MyNewName不是现有名称的子字符串,因此$_.Name -replace $file, $MyNewName实际上是no-op-通过现有的$_.Name

    • 如果重命名单个项,只在延迟绑定脚本块({ ... }(内传递$MyNewName-而不是就足够了

但是,您可以优化您的解决方案以使用单个管道,包括使用通配符表达式匹配感兴趣目录的Get-ChildItem调用,以及使用延迟绑定脚本块插入-字符的Rename-Item。通过基于正则表达式的-replace运算符在匹配项的名称中:

# Create two sample directories
$null = New-Item -Force -Type Directory '12345678', '87654321'
Get-ChildItem -Directory -Path ('[0-9]' * 8) |
Rename-Item -NewName { $_.Name -replace '(.{4})(.{2})(.{2})', '$1-$2-$3'  } -Verbose

上面执行了所需的重命名,并且由于使用了通用$MyNewName0参数,打印了以下内容(为便于阅读,换行(:

VERBOSE: Performing the operation "Rename Directory" on target "Item: ...12345678 
Destination: ...1234-56-78".       
VERBOSE: Performing the operation "Rename Directory" on target "Item: ...87654321
Destination: ...8765-43-21".

注:

  • 如果要预览重命名操作,请在Rename-Item中使用公共-WhatIf参数。

  • 如果您需要知道是否有任何文件匹配并因此被重命名,请首先捕获变量中的Get-ChildItem调用:

    $files = Get-ChildItem -Directory -Path ('[0-9]' * 8)
    $files | Rename-Item -NewName { $_.Name -replace '(.{4})(.{2})(.{2})', '$1-$2-$3'  } -Verbose
    Write-Verbose -Verbose $(if ($files) { "$($files.Count) directories renamed." } else { 'No matching directories found.' })
    

而不是。。。

Get-ChildItem | Rename-Item -NewName { $_.Name -replace $file, $MyNewName }

尝试。。。

Rename-Item -Name $file -NewName $MyNewName

您可以让Where Object子句中的regex-match检查文件夹名称是否正好有8位数字,并仅重命名这些数字:

$i = 0
Get-ChildItem -Path 'D:Test' -Directory | 
Where-Object { $_.Name -match '^d{8}$' } | 
ForEach-Object {
$newName = $_.Name -replace '(d{4})(d{2})(d{2})', '$1-$2-$3'
Write-Host "Renaming folder $($_.FullName) to: $newName"
$_ | Rename-Item -NewName $newName -WhatIf
$i++
}
if ($i) {
Write-Host "Total of items affected: $i"
}
else {
Write-Host "No matching folder names found"
}

在这里,-WhatIf开关确保您只能看到会发生什么。实际上还没有什么东西被重命名。如果您对该输出感到满意,请从Rename Item cmdlet中删除-WhatIf开关。

此外,regex-replace通过捕获3个不同的"backreferences"中的数字并在它们之间用虚线输出,使创建新名称格式比多次使用Substring((容易得多。

如果你在任何时候都不关心写主机消息,代码可以缩短为

Get-ChildItem -Path 'D:Test' -Directory | 
Where-Object { $_.Name -match '^d{8}$' } | 
Rename-Item -NewName {$_.Name -replace '(d{4})(d{2})(d{2})', '$1-$2-$3'} -WhatIf

这个脚本的工作更加可靠,因为它使用了"获取子项"而不仅仅是文件/文件夹名称。

$i = 0
Get-ChildItem -Directory "C:UserDataTest" | ForEach-Object {
if (($_.Name) -match "^d{8}$") {
[System.String]$NewFolderName = ($_.Name).Insert(6, "-").Insert(4, "-")
Rename-Item -Path ($_.FullName) -NewName $NewFolderName
Write-Output ("the item {0} ({1}) has been renamed : {2}" -f  ($_.Name), (($_.Name).Length), $NewFolderName)
$i++
}
}
if ($i) {
Write-Output ("total of items affected: {0}" -f $i)
} else{
Write-Output "No matching items found."
}

最新更新