Bulk renaming files with different extensions in order using powershell - powershell

is there a way to bulk rename items such that a folder with the items arranged in order would have their name changed into numbers with zero padding regardless of extension?
for example, a folder with files named:
file1.jpg
file2.jpg
file3.jpg
file4.png
file5.png
file6.png
file7.png
file8.jpg
file9.jpg
file10.mp4
would end up like this:
01.jpg
02.jpg
03.jpg
04.png
05.png
06.png
07.png
08.jpg
09.jpg
10.mp4
i had a script i found somewhere that can rename files in alphabetical order. however, it seems to only accepts conventionally bulk renamed files (done by selecting all the files, and renaming them such that they read "file (1).jpg" etc), which messes up the ordering when dealing with differing file extensions. it also doesn't seem to rename files with variations in their file names. here is what the code looked like:
Get-ChildItem -Path C:\Directory -Filter file* | % {
$matched = $_.BaseName -match "\((?<number>\d+)\)"
if (-not $matched) {break;}
[int]$number = $Matches["number"]
Rename-Item -Path $_.FullName -NewName "$($number.ToString("000"))$($_.Extension)"
}

If your intent is to rename the files based on the ending digits of their BaseName you can use Get-ChildItem in combination with Where-Object for filtering them and then pipe this result to Rename-Item using a delay-bind script block.
Needles to say, this code does not handle file collision. If there is more than one file with the same ending digits and the same extension this will error out.
Get-ChildItem -Filter file* | Where-Object { $_.BaseName -match '\d+$' } |
Rename-Item -NewName {
$basename = '{0:00}' -f [int][regex]::Match($_.BaseName, '\d+$').Value
$basename + $_.Extension
}
To test the code you can use the following:
#'
file1.jpg
file2.jpg
file3.jpg
file4.png
file5.png
file6.png
file7.png
file8.jpg
file9.jpg
file10.mp4
'# -split '\r?\n' -as [System.IO.FileInfo[]] | ForEach-Object {
$basename = '{0:00}' -f [int][regex]::Match($_.BaseName, '\d+$').Value
$basename + $_.Extension
}

You could just use the number of files found in the folder to create the appropriate 'numbering' format for renaming them.
$files = (Get-ChildItem -Path 'D:\Test' -File) | Sort-Object Name
# depending on the number of files, create a formating template
# to get the number of leading zeros correct.
# example: 645 files would create this format: '{0:000}{1}'
$format = '{0:' + '0' * ($files.Count).ToString().Length + '}{1}'
# a counter for the index number
$index = 1
# now loop over the files and rename them
foreach ($file in $files) {
$file | Rename-Item -NewName ($format -f $index++, $file.Extension) -WhatIf
}
The -WhatIf switch is a safety measure. With this, no file gets actually renamed, you will only see in the console what WOULD happen. Once you are content with that, remove the -WhatIf switch from the code and run again to rename all your files in the folder

Related

Batch renaming files by PowerShell?

How can I rename files in a folder that have random names and random extensions to a sequence like the example below: 0001.pdf 0002.pdf ..... 0100.png and continue.
And if possible then generate a .txt file with the names and extensions generated.
For the .txt file if not possible Powershel could be another application.
Searching I got the code below, but I can't fix it for the task I need.
Dir | Rename-Item –NewName { $_.name –replace " - ","0" }
Wrap the call to Rename-Item in ForEach-Object then maintain a counter in a variable:
$fileNumber = 1
Get-ChildItem path\to\folder\containing\random\files -File |ForEach-Object {
# Construct new file name
$newName = '{0:0000}{1}' -f $fileNumber,$_.Extension
# Perform rename
$_ |Rename-Item -NewName $newName
# Increment number
$fileNumber++
}

Rename Part of File Name

I am looking to batch rename part of a pdf file using a csv file. I have a csv file with two columns, name and Newname. My pdf files have a naming convention of 222222_test (for example) and are located in the C:\TEST folder. In the csv file, 222222 is in the name column and Jonathan is in the Newname column.
The folder is really going to have hundreds of pdf documents whenever I can get this to work.
$csv = Import-Csv "C:\TEST\Book1.csv"
# location of your files
$files = get-childitem "C:\TEST\*.DOCX"
foreach($item in $CSV){
foreach($file in $files){
if($item.name -eq $file.basename){
rename-item $file.fullname -NewName "$($item.newname)$($file.extension)" -Verbose
}
}
}
I am looking for a way for the 222222 (only) to be changed to Jonathan so the pdf file would be Jonathan_test. I was able to use the code when the file name is only 222222 but when the pdf is 222222_test, the code is not working.
Give this a try, remove the WhatIf if it works for your files. Else, we'll need to see some sample data from the csv.
foreach ($item in $CSV) {
foreach ($file in $files) {
if ($item.name -eq $file.basename) {
Rename-Item $file.fullname -NewName $($file.FullName -replace $item.name, $item.newname) -WhatIf
}
}
}
With hundreds of CSV rows, it pays to build up a hashtable up front that maps old names to new names.
You then only need to loop once over the file names, performing a fast hashtable lookup in each iteration.
# Initialize the hashtable.
$ht = #{}
# Fill the hashtable, with the "name" column's values as the keys,
# and the "newname" columns as the values.
Import-Csv C:\TEST\Book1.csv |
ForEach-Object {
$ht.Add($_.name, $_.newname)
}
# Loop over the files and rename them based on the hashtable
Get-ChildItem C:\TEST\*.DOCX | Rename-Item -NewName {
$prefix = ($_.BaseName -split '_')[0] # Get prefix (before "_")
$newPrefix = $ht[$prefix] # Look up the prefix in the hashtable.
if ($newPrefix) { # Replace the prefix, if a match was found.
$newPrefix + $_.Name.Substring($prefix.Length)
}
else { # No replacement - output the original name, which is a no-op.
$_.Name
}
} -WhatIf
-WhatIf previews the renaming operations; remove it to perform actual renaming.

Search and replace files and folders names with txt file support

I have many folders and inside these different files. Each folder and their children files have the same name and different extension, so in the ABC folder there are the ABC.png, ABC.prj, ABC.pgw files, in the DEF folder there are the DEF.png, DEF.prj, DEF.pgw files and so on.
With a script I have created a txt file with the list of png file names. Then I put in row 2 a new name for the name in row1, in row 4 a new name for the name in row 3, and so on.
Now I'm searching a powershell script that:
- scan all folder for the name in row 1 and replace it with name in row2
- scan all folder for the name in row 3 and replace it with name in row4 and so on
I have try with this below, but it doesn't work.
Have you some suggestions? Thank you
$0=0
$1=1
do {
$find=Get-Content C:\1\Srv\MapsName.txt | Select -Index $0
$repl=Get-Content C:\1\Srv\MapsName.txt | Select -Index $1
Get-ChildItem C:\1\newmaps -Recurse | Rename-Item -NewName { $_.name -replace $find, $repl} -verbose
$0=$0+2
$1=$1+2
}
until ($0 -eq "")
I believe there are several things wrong with your code and also the code Manuel gave you.
Although you have a list of old filenames and new filenames, you are not using that in the Get-ChildItem cmdlet, but instead try and replace all files it finds.
Using -replace uses a Regular Expression replace, that means the special character . inside the filename is regarded as Any Character, not simply a dot.
You are trying to find *.png files, but you do not add a -Filter with the Get-ChildItem cmdlet, so now it will return all filetypes.
Anyway, I have a different approach for you:
If your input file C:\1\Srv\MapsName.txt looks anything like this:
picture1.png
ABC_1.png
picture2.png
DEF_1.png
picture3.png
DEF_2.png
The following code will use that to build a lookup Hashtable so it can act on the files mentioned in the input file and leave all others unchanged.
$mapsFile = 'C:\1\Srv\2_MapsName.txt'
$searchPath = 'C:\1\NewMaps'
# Read the input file as an array of strings.
# Every even index contains the file name to search for.
# Every odd index number has the new name for that file.
$lines = Get-Content $mapsFile
# Create a hashtable to store the filename to find
# as Key, and the replacement name as Value
$lookup = #{}
for ($index = 0; $index -lt $lines.Count -1; $index += 2) {
$lookup[$lines[$index]] = $lines[$index + 1]
}
# Next, get a collection of FileInfo objects of *.png files
# If you need to get multiple extensions, remove the -Filter and add -Include '*.png','*.jpg' etc.
$files = Get-ChildItem -Path $searchPath -Filter '*.png' -File -Recurse
foreach ($file in $files) {
# If the file name can be found as Key in the $lookup Hashtable
$find = $file.Name
if ($lookup.ContainsKey($find)) {
# Rename the file with the replacement name in the Value of the lookup table
Write-Host "Renaming '$($file.FullName)' --> $($lookup[$find])"
$file | Rename-Item -NewName $lookup[$find]
}
}
Edit
If the input text file 'C:\1\Srv\MapsName.txt' does NOT contain filenames including their extension, change the final foreach loop into this:
foreach ($file in $files) {
# If the file name can be found as Key in the $lookup Hashtable
# Look for the file name without extension as it is not given in the 'MapsName.txt' file.
$find = [System.IO.Path]::GetFileNameWithoutExtension($file.Name)
if ($lookup.ContainsKey($find)) {
# Rename the file with the replacement name in the Value of the lookup table
# Make sure to add the file's extension if any.
$newName = $lookup[$find] + $file.Extension
Write-Host "Renaming '$($file.FullName)' --> '$newName'"
$file | Rename-Item -NewName $newName
}
}
Hope that helps
The problem in your snippet is that it never ends.
I tried it and it works but keeps looping forever.
I created a folder with the files a.txt, b.txt and c.txt.
And in the map.txt I have this content:
a.txt
a2.md
b.txt
b2.md
c.txt
c2.md
Running the following script I managed to rename every file to be as expected.
$0=0
$1=1
$find=Get-Content D:\map.txt | Select -Index $0
while($find) {
$find=Get-Content D:\map.txt | Select -Index $0
$repl=Get-Content D:\map.txt | Select -Index $1
if(!$find -Or !$repl) {
break;
}
Get-ChildItem D:\Files -Recurse | Rename-Item -NewName { $_.name -replace $find, $repl} -verbose
$0=$0+2
$1=$1+2
}

Powershell change extension

I have a problem with change extension of a file. I need to write a script which is replicating data, but data have two files. Filename is not a string, so we can't use normal -replace
I need to get from
filename.number.extension
this form
filename.number.otherextension
We try to use a split, but this command show us things like below
filename
number
otherextension
Thanks for any ideas,
[System.IO.Path]::ChangeExtension("test.old",".new")
You probably want something like the -replace operator:
'filename.number.extension' -replace 'extension$','otherextension'
The $ is regular expression syntax meaning end of line. This should ensure that the -replace does not match "extension" appearing elsewhere in the filename.
A simple Utility Function
<#
# Renames all files under the given path (recursively) whose extension matches $OldExtension.
# Changes the extension to $NewExtension
#>
function ChangeFileExtensions([string] $Path, [string] $OldExtension, [string] $NewExtension) {
Get-ChildItem -Path $Path -Filter "*.$OldExtension" -Recurse | ForEach-Object {
$Destination = Join-Path -Path $_.Directory.FullName -ChildPath $_.Name.Replace($OldExtension, $NewExtension)
Move-Item -Path $_.FullName -Destination $Destination -Force
}
}
Usage
ChangeFileExtensions -Path "c:\myfolder\mysubfolder" -OldExtension "extension" -NewExtension "otherextension"
But it can do more than just this. If you had the following files in the same folder as your script
example.sample.csv
example.txt
mysubfolder/
myfile.sample.csv
myfile.txt
this script would rename all the .sample.csv files to .txt files in the given folder and all subfolders and overwrite any existing files with those names.
# Replaces all .sample.csv files with .txt extensions in c:\myfolder and in c:\myfolder\mysubfolder
ChangeFileExtensions -Path "c:\myfolder" -OldExtension "sample.csv" -NewExtension "txt"
If you don't want it to be recursive (affecting subfolders) just change
"*.$OldExtension" -Recurse | ForEach-Object
to
"*.$OldExtension" | ForEach-Object
This could work:
Get-ChildItem 'C:\Users\Administrator\Downloads\text files\more text\*' *.txt | rename-item -newname { [io.path]::ChangeExtension($_.name, "doc") }
You can remove the last item with the the [0..-1] slice and add the new extension to that
(("filename.number.extension" -split "\.")[0..-1] -join '.') +".otherextension"

Rename-Item : add unique numeric sequence to prevent duplicate file names

I need a way to rename files in a directory that would result in an error with a simple Rename-Item. The files need the same 10 digit code followed by 4 digit place holder (numbers only please).
Current file names:
01_img_0028.JPG
01_img_0029.JPG
02_img_0028.JPG
02_img_0029.JPG
Considering the files above, renaming the files with a split (using the 4 digit in the original name) would fail because there will be files with the same name:
B0000000000.0028.JPG
B0000000000.0029.JPG
B0000000000.0028.JPG
B0000000000.0029.JPG
Does anyone have an idea to get around this? The 4 digits can be any sequence of numbers but it would be great if we could make the end result look like:
B0000000000.0001.JPG
B0000000000.0002.JPG
B0000000000.0003.JPG
B0000000000.0004.JPG
Here is my current code that will rename all unique files and the first of duplicates, but error out on files that would then be duplicate names:
$jpgToRename = GCI -Path $pathToRename -Filter '*.jpg' -R
foreach ($jpg in $jpgToRename) {
$splitPath = $jpg.FullName.Split("\\")
$newName = -join ($splitPath[7], ".", $jpg.BaseName, ".PC_850.jpg")
Rename-Item $jpg.FullName -NewName $newName
}
Using a counter here would keep this simple for your need:
$jpgToRename = GCI -Path $pathToRename -Filter '*.jpg' -R
$counter = 1
foreach($jpg in $jpgToRename){
$splitPath = $jpg.FullName.Split("\\")
$formattedCounter = $counter.ToString("0000")
$newName = -Join($splitPath[7], ".",$formattedCounter, $jpg.BaseName, ".PC_850.jpg")
Rename-Item $jpg.FullName -NewName $newName
$counter++
}