Wilson Silva
Wilson Silva

Reputation: 1445

One Drive Migration

I'm trying to migrate a file server to One Drive the problem is that there are many folders and files with special characters like '|' , '<' etc..

And also for some reason that company used '*' for versioning like :

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

etc...

So I wrote a Powershell script that renames all the files and folders that include a special characters.

#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")}

So this works fine but for some reason I'm getting many error when renaming the folders even though it worked...

Error:

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

I also tried what this thread suggest but this didn't work for me:

Solution that didn't work

Does anyone have a clue why I'm getting this error? And How to fix it?

Thanks in advance.

Upvotes: 1

Views: 235

Answers (3)

Vasil Nikolov
Vasil Nikolov

Reputation: 757

You run 10 lines of code to rename only 1 type of match per line but effectively you run the same loop 10 times, in this case your code try to rename all folders every single time, but it errors out when it tries to rename the folder with the same newName , because Rename-Item tries to rename it even if the new name is the same as the old one, it appears to not have a validator for that.

In that case, the "cheapest" solution is to add -ErrorAction SilentlyContinue . But a more sophisticated solution would be to validate your dataset with an if statement or a more appropriate for the case switch .

Update : Regex might not be the easiest thing to deal with, so the example bellow account for the wildcard * character as well.

$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 

        }
    }
}

This way, you will run 1 loop instead of 10 and you only try to rename items that matches the pattern you provide, so you will see a significant performance increase compared to the multiline code you are using.

Upvotes: 0

Frenchy
Frenchy

Reputation: 17017

The error is normal, if you dont have reasons to rename the directory or file because the filename is ok and no character to modify, the name stays same, so an error is displayed saying you cant rename a file/directory with same name.

Despite this error, the process is not stopped and has no impact on the final result

i suggest you to set all couple key to search , new value in an object:

#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
    }
}

do samething for your files......

Upvotes: 1

Theo
Theo

Reputation: 61068

On my Windows machine I cannot have characters like that in a file or folder name, but theoretically this should work:

(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 '[:<>?/|]', '-' 
    }
}

the brackets around Get-ChildItem force it to complete the gathering before piping to rename. Otherwise, you may end up trying to rename items that were already processed

Upvotes: 1

Related Questions