我是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
上面执行了所需的重命名,并且由于使用了通用$MyNewName
0参数,打印了以下内容(为便于阅读,换行(:
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."
}