How to rename/rearrange file names in Windows 11? - windows

I had multiple photos saved in my computer with file names in First name_Middle Name_Last Name format. I would like to change it to Last Name, First Name, Middle Name.
For example:
From: One_Two_Three
To: Three, One, Two
I did a little research but I only found a replace-like method, but not rearranging the words.

Use the -replace regex operator:
PS ~> 'One_Two_Three' -replace '([^_]+)_([^_]+)_([^_]+)', '$3, $1, $2'
Three, One, Two
The pattern ([^_]+) will capture any sequence of non-_, and we can then "rearrange" each capture in the substitution pattern $3, $1, $2 ($1 refers to the group that captures One before the first _, etc.).
For renaming files, you'll want to reference the BaseName property on each file object:
Get-ChildItem path\to\folder\with\pictures -File -Filter *_*_*.* |Rename-Item -NewName {($_.BaseName -replace '([^_]+)_([^_]+)_([^_]+)', '$3, $1, $2') + $_.Extension}

Another method:
PS /tmp> Get-ChildItem -File -Filter *_*_*.* |
Rename-Item -WhatIf -NewName {
$w = $_.BaseName -split '_'; (($w[2], $w[0], $w[1]) -join ', ') + $_.Extension }
Output:
What if: Performing the operation "Rename File" on target "Item: /tmp/One_Two_Three.jpg Destination: /tmp/Three, One, Two.jpg".
Remove -WhatIf to do real renaming

Related

Batch Replace Character in File Names

I have about 600 video files with the $ special character in the title.
I want to batch replace this with a letter s.
I found the powershell code online below and it works fine with replacing letters with other letters but fails when trying to replace the $ special character
get-childitem -recurse | rename-item -newname { $_.name -replace "",""}
I tried using the code below and it ends up adding an s to the end of the file type instead of replacing the $
get-childitem -recurse | rename-item -newname { $_.name -replace "$","s"}
$hortvid.mp4 becomes $hortvid.mp4s instead of shortvid.mp4
Any ideas on how to get this to work correctly?
Just use \ escape character:
When running line in the directory:
get-childitem -recurse | rename-item -newname { $_.name -replace "\$","s"}
input file:
$hortvid.mp4
output file is renamed:
shortvid.mp4
$ is used for specify variable in powershell. And a string with double quote is evaluate in powershell like this :
$variable1="Hello"
$variable2="$variable1 world"
$variable2
if you dont want evaluate a character into a double quote string, you can backslash you caractere like the proposed solution of #lww. Or simply, you can use simple quote.
Like this :
Get-ChildItem -recurse | Rename-Item -Newname { $_.Name -replace '$', 's'}

How to recursively truncate filenames in powershell?

I need to truncate filenames to 35 characters (including extension) so I run this script and it worked for the directory it self (PowerShell, Windows 10).
Get-ChildItem *.pdf | rename-item -NewName {$_.name.substring(0,31) + $_.Extension}
Then I wanted to apply the same script including subdirectories:
Get-ChildItem -Recurse -Include *.pdf | Rename-Item -NewName {$_.Name.substring(0,31) + $_.Extension}
This script gave me an error like this for each file:
Rename-Item : Error in input to script block for parameter 'NewName'. Exception when calling "Substring" with the arguments "2": "The index and length must reference a location in the string. Parameter name: length"
On line: 1 Character: 62
+ ... *.pdf | Rename-Item -NewName {$_.Name.substring(0,31) + $_.Extension}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (C:\User\prsn..._file_name_long.pdf:PSObject) [Rename-Item], ParameterBindingException
+ FullyQualifiedErrorId : ScriptBlockArgumentInvocationFailed,Microsoft.PowerShell.Commands.RenameItemCommand
I tried this one but it doesn't go on subdirectories:
Command to truncate all filenames at 255 characters
I found this one but it doesn't have an answer:
https://superuser.com/questions/1188711/how-to-recursively-truncate-filenames-and-directory-names-in-powershell
I don't think you can use $_ that way. I think you have to wrap it in a ForEach loop in order to get the references to work that way. Once that's done, you'll have to specify the path of the file you want to rename as well:
Something like:
Get-ChildItem -Recurse -Include *.pdf -File |
ForEach-Object{
Rename-Item -Path $_.FullName -NewName ( $_.BaseName.SubString(0, 31) + $_.Extension )
}
Notice I used parenthesis instead of curly braces. If you use a script block it may not evaluate. There are other ways to make it happen, but I think using parens is the most obvious.
Notice I used $_.BaseName instead of name. Base name doesn't include the extension. though I don't know how your sub-string works out I left it in for you decide.
You can combine this with #Mathias's answer or some modification of it. That might give you a better or more reliable way to derive the new file name. I haven't tested it, but it might look something like:
Get-ChildItem -Recurse -Include *.pdf -File |
ForEach-Object{
Rename-Item -Path $_.FullName -NewName ( ($_.Name -replace '(?<=^.{35}).*$') + $_.Extension )
}
Use the -replace regex operator to remove anything after the first 35 chars - it will simply ignore any string that doesn't have at least 35 characters and return it as-is:
$_.Name -replace '(?<=^.{35}).*$'
The correct error message is
Exception calling "Substring" with "2" argument(s): "Index and length must refer to a location within the string.
The reason is that the second argument is greater than the length of the file name. e.g. "abc".Substring(0,4) throws.
Answer
$renameTarget = dir -File -Recurse *.pdf | ? { $_.Name.Length -gt 35 }
$renameTarget | Rename-Item -NewName {
$_.name.substring(0, 31) + ".pdf"
}
or
dir *.pdf -File -Recurse | Rename-Item -NewName {
$_.name.substring(0, [Math]::Min($_.BaseName.length, 31)) + ".pdf"
}

Powershell Rename File Regular Expression

I have in a folder a lot of .pdf files with the naming format of whatevername space random code starting with U.pdf and I want to remove whatever is the naming before U.
Example Name Format:
Alex U153569.pdf -> should be renamed to U153569.pdf
This is what I have so far:
foreach ($test in $testpdf) {
Get-ChildItem -Filter *.pdf | Rename-Item -NewName { $_.name -Replace ????????? }
}
What should be the correct one?
This should work:
$_.name -Replace '.*\s(?=U)'
Without testing you should be able to use the split operator (no need for a regular expression). You can split on a space as below and index into the second split [1]
$testpdf = Get-ChildItem *.pdf
foreach ($test in $testpdf) {
Rename-Item $test.name -NewName (($test.name -split " ")[1])
}

mass rename of files with different prefixes in a folder

File names
In the above picture is an example of the file structure.
I have looked at many cmd lines for mass renaming but they all have either the same prefix or the same amount of characters.
Is there a way to rename multiple files with different prefixes but keep the text and file type. so 111 tiger.txt to tiger.txt and 32133_lion.txt to lion.txt.
This is relatively easy in PowerShell. The key is using a regex match to strip off the leading digits and '_' and space.
C:>type .\rd\doit.ps1
[cmdletbinding()]
Param()
Get-ChildItem "C:\src\t\rd" |
ForEach-Object {
$_.Name -match "\d*[_ ]*(.*)" | Out-Null
if ($matches[1] -ne $null) {
if ($_.Name -ne $matches[1]) {
Rename-Item $_.FullName $matches[1] -WhatIf
}
}
}
When you believe that correct renaming will be done, remove the -WhatIf from the Rename-Item command.
C:>.\rd\doit.ps1
What if: Performing the operation "Rename File" on target "Item: C:\src\t\rd\123dog.txt Destination: C:\src\t\rd\dog.txt".
What if: Performing the operation "Rename File" on target "Item: C:\src\t\rd\124cat.txt Destination: C:\src\t\rd\cat.txt".

How can I bulk rename files in PowerShell?

I'm trying to do the following:
Rename-Item c:\misc\*.xml *.tmp
I basically want to change the extension on every files within a directory to .tmp instead of .xml. I can't seem to find a straight forward way to do this in PowerShell.
From example 4 in the help documentation of Rename-Item retrieved with the command:
get-help Rename-Item -examples
Example:
Get-ChildItem *.txt| Rename-Item -NewName { $_.Name -replace '\.txt','.log' }
Note the explanation in the help documentation for the escaping backslash in the replace command due to it using regular expressions to find the text to replace.
To ensure the regex -replace operator matches only an extension at the end of the string, include the regex end-of-string character $.
Get-ChildItem *.txt | Rename-Item -NewName { $_.Name -replace '\.txt$','.log' }
This takes care of the case mentioned by #OhadSchneider in the comments, where we might have a file named lorem.txt.txt and we want to end up with lorem.txt.log rather than lorem.log.log.
Now that the regex is sufficiently tightly targeted, and inspired by #etoxin's answer, we could make the command more usable as follows:
Get-ChildItem | Rename-Item -NewName { $_.Name -replace '\.txt$','.log' }
That is, there is no need to filter before the pipe if our regex sufficiently filters after the pipe. And altering the command string (e.g. if you copy the above command and now want to use it to change the extension of '.xml' files) is no longer required in two places.
This works well too when you're in the desired directory.
Dir | Rename-Item –NewName { $_.name –replace "old","new" }
The existing answers suggest the -replace operator, but what if the file is called a.xml.xml? Both .xml substrings will be replaced and the end result would be a.tmp.tmp. Fortunately, there's a .NET method for this:
Dir *.xml | rename-item -newname { [io.path]::ChangeExtension($_.name, ".tmp") }
(Manish Kumar was close with GetFileNameWithoutExtension but this is more elegant and probably a bit more efficient, not that it overly matters in this case)
Here's another variant that will work.
dir *.xml | Rename-Item -NewName {$_.BaseName + ".tmp"}
$_.BaseName will do the "base" name without the (last) extension.
a shortened version using the alias would be:
ls *.xml | ren -new {$_.BaseName + ".tmp"}
dir -Recurse | where-object -FilterScript {$_.Extension -eq ".xml"} | Rename-Item -NewName {[System.IO.Path]::GetFileNameWithoutExtension($_.fullname) + ".tmp"}
use -WhatIf to evaluate the result first
Even easier - remember that the replace search string is a regular expression,
dir *.xml | rename-item -newname {$_.name -replace "xml$","tmp"}
The "$" represents end-of-string, so the characters "xml" must be the last three chars of the filename.
This seems to work and is a pythonic i.e simple is better than complex (https://www.python.org/dev/peps/pep-0020/) way of doing it (once you are in the directory):
$files = Get-ChildItem -file -Filter *.xml;
ForEach ($file in $files)
{
$n = $file.Basename
Copy-Item -Path $file -Destination "$n.tmp"
Remove-Item "$n.xml"
}

Resources