单盘迁移

One Drive Migration

我正在尝试将文件服务器迁移到 One Drive 问题是有很多文件夹和文件带有特殊字符,例如“|” , '<' 等..

而且出于某种原因,该公司使用“*”进行版本控制,例如:

'*' => v.1
'**' => v.2

等...

所以我写了一个 Powershell 脚本来重命名所有包含特殊字符的文件和文件夹。

#Files
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace(":","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("<","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace(">","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("?","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("/","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("|","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("**********","10")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*********","9")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("********","8")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*******","7")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("******","6")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*****","5")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("****","4")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("***","3")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("**","2")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*","1")}


#Directories
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace(":","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("<","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace(">","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("?","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("/","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("|","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("**********","10")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*********","9")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("********","8")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*******","7")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("******","6")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*****","5")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("****","4")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("***","3")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("**","2")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*","1")}

所以这工作正常,但由于某种原因,我在重命名文件夹时遇到很多错误,即使它工作正常...

错误:

 … curse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*", …
     |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Source and destination path must be different.

我也试过这个帖子 suggest 但这对我不起作用:

有人知道我为什么会收到此错误吗?以及如何修复它?

提前致谢。

这个错误是正常的,如果你没有理由重命名目录或文件,因为文件名是可以的,没有字符可以修改,名称保持不变,所以会显示一个错误,说你不能重命名一个file/directory同名。

尽管出现此错误,但过程并未停止,对最终结果没有影响

我建议您将所有键设置为搜索,对象中的新值:

#add your template to replace
$r = @{
    ":" = "-"
    "<" = "-"
    "**********" = "10";
    "*********" = "9";
    "********" = "8"
    }

$Folders=Get-ChildItem -Directory -path -Recurse

foreach($folder in $Folders){
    $newname = $folder.Name

    foreach($k in $r.Keys){
         $newname = $newname.Replace($k,$r.$k) 
    }

    #rename only if original name and newname are differents
    if(!$newname.equals($folder.Name)){
        Rename-Item -Path $folder.FullName -NewName $newname
    }
}

对你的文件做同样的事情......

您 运行 10 行代码每行仅重命名一种匹配类型,但实际上您 运行 相同的循环 10 次,在这种情况下,您的代码尝试重命名所有文件夹时间,但是当它尝试重命名具有相同 newName 的文件夹时出错,因为 Rename-Item 尝试重命名它,即使新名称与旧名称相同,它似乎没有一个验证器。

在这种情况下,“最便宜”的解决方案是添加 -ErrorAction SilentlyContinue 。但更复杂的解决方案是使用 if 语句或更适合案例 switch .

的语句来验证您的数据集

更新:Regex 可能不是最容易处理的事情,因此下面的示例也说明了通配符 * 字符。

$allFolders=Get-ChildItem -Directory -Recurse

foreach($folder in $allFolders){
    
    switch -Regex ($folder.Name){
        '[:<>?\|]'{
            $newName=$folder.Name.replace("[:<>?\|]","-")
            Rename-Item -Path $folder.FullName -NewName $newName 
        }
        '\*'{
            $regexFormat = '\*'
            $matchNumber=[regex]::Matches($folder.Name, $regexFormat) | ForEach-Object { $_.value }

            $newName=$folder.Name.replace("*",$matchNumber.Count)
            Rename-Item -Path $folder.FullName -NewName $newName 

        }
    }
}

这样,您将 运行 1 次循环而不是 10 次循环,并且您只尝试重命名与您提供的模式相匹配的项目,因此与您使用的多行代码相比,您将看到显着的性能提升.

在我的 Windows 机器上,我不能在文件或文件夹名称中使用这样的字符,但理论上这应该可行:

(Get-ChildItem -File) | ForEach-Object {
    $_ | Rename-Item -NewName {
        # replace the '*' by the number of consecutive asterikses found
        $name = $_.Name
        $match = ([regex] '(\*+)').Match($name)
        while ($match.Success) {
            $name = $name -replace [regex]::Escape($match), $match.Length
            $match = $match.NextMatch()
        } 
        # finally replace the other special characters by a hyphen
        $name -replace '[:<>?/|]', '-' 
    }
}

Get-ChildItem 周围的括号强制它在管道重命名之前完成收集。否则,您最终可能会尝试重命名已处理的项目