Batch renaming files by PowerShell? - 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++
}

Related

Bulk renaming files with different extensions in order using 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

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
}

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

How do I most efficiently move, rename files and log this action?

I have the following CSV list (in reality 1000s of lines):
needle,code
123456,AB
121212,BB
33333333,CVV
And I have a directory (C:\old_files) containing PDF files (again, 1000s in reality):
dsadsadsa.343222.dsads23213jkjl.saddsa.pdf
dsadsadsa.123456.dsads23213jkjl.saddsa.pdf
dsadsadsa.111111.dsads23213jkjl.saddsa.pdf
dsadsadsa.33333333.dsads23213jkjl.saddsa.pdf
dsadsadsa.33333333.fsdgdsfdsfdsf.dsad.pdf
For each needle in the CSV:
I have to see if there is a PDF containing that needle (there might be 0 or more matches)
If there is a match, I have to
make a copy of the file into a separate folder (D:\new_files)
rename the copied file by prepending the respective code to the name
write an entry into the log.
For the example, I have a match for 123456 and 2 for 33333333, so I have to move a copy of these files into D:\new_files and rename them into:
AB.dsadsadsa.123456.dsads23213jkjl.saddsa.pdf
CVV.dsadsadsa.33333333.dsads23213jkjl.saddsa.pdf
CVV.dsadsadsa.33333333.fsdgdsfdsfdsf.dsad.pdf
The logfile would look like (format needle,code,oldfilepath,newfilepath):
123456,AB,C:\old_files\dsadsadsa.123456.dsads23213jkjl.saddsa.pdf,D:\new_files\AB.dsadsadsa.123456.dsads23213jkjl.saddsa.pdf
33333333,CVV,C:\old_files\dsadsadsa.33333333.dsads23213jkjl.saddsa.pdf,D:\new_files\CVV.dsadsadsa.33333333.dsads23213jkjl.saddsa.pdf
33333333,CVV,C:\old_files\dsadsadsa.33333333.fsdgdsfdsfdsf.dsad.pdf,D:\new_files\CVV.dsadsadsa.33333333.fsdgdsfdsfdsf.dsad.pdf
It is important that I only loop over the files in the directory once, because iterating through all files in a ForEach loop for each needle takes way too long. So with thanks to this forum I'm building a hashtable first:
$pairs = #{}
Import-CSV .\data.csv | ForEach-Object { $pairs[$_.needle] = $_.code+"." }
Get-ChildItem "C:\old_files" | Rename-Item -NewName { "D:\new_files\" + $pairs[$_.Name.Split('.')[1]] + $_.Name }
My first problem here: I am unable to move the file into the new folder.
Q1 How do I properly copy a file from C:\old_files into D:\new_files and rename it?
My second problem: I don't understand how I can add code to the above code.
Q2 How can I create the logfile for each match (and therefore: copied and renamed file)?
You need to actually check if you have a match before copying the matching file.
Get-ChildItem "C:\old_files" | ForEach-Object {
$n = ($_.Name -split '.')[1]
if ($pair[$n]) {
$oldname = $_.FullName
$newname = Join-Path 'C:\new_files' ($pair[$n] + $_.Name)
Copy-Item $oldname $newname
}
}
Do the logging after the copy operation:
Copy-Item $oldname $newname
if ($?) {
# log success information here
} else {
# log error information here
}

Powershell script to copy and rename files in a loop

I have a number of files with extension .psa in my Prevalidation folder and I want to:
copy them one by one into my working folder
rename the .psa file to psaload.csv
run a set of commands against the file to load it to my db
and then delete the csv file from my working folder.
This will be repeated for all the .psa files I have on my source folder.
So, the question is how do I execute the set of commands in a loop over as many .psa files as present.
Here's my piece of code testing for only one file in my Prevalidation folder -
Copy-Item C:\Downloads\PreValidation\*.psa C:\Downloads\Validation\WIP
Rename-Item 'C:\Downloads\Validation\WIP\abc 1234.psa' 'psaload1.csv'
Get-Content C:\Downloads\Validation\WIP\psaload1.csv | ForEach-Object { $_.replace("\,"," ") } | Set-Content C:\Downloads\Validation\WIP\psaload.csv
Remove-Item C:\Downloads\Validation\WIP\psaload1.csv
<run the psaload.csv to load to my db>
This is what I intend to do -
Consider multiple .psa files in my C:\Downloads\Prevalidation folder.
For each C:\Downloads\PreValidation\*.psa
BEGIN LOOP
Copy-Item C:\Downloads\PreValidation\aaaa.psa C:\Downloads\Validation\WIP\aaaa.psa
Rename-Item 'C:\Downloads\Validation\WIP\aaaa.psa' 'psaload1.csv'
Get-Content C:\Downloads\Validation\WIP\psaload1.csv | ForEach-Object { $_.replace("\,"," ") } | Set-Content C:\Downloads\Validation\WIP\psaload.csv
Remove-Item C:\Downloads\Validation\WIP\psaload1.csv
END LOOP
I am looking for the syntax to run these set of commands for each files one by one as present in my /prevalidation folder.
Since all the other answers were quite horrible code and not very idiomatic PowerShell, here is my take (though untested):
# Get all .psa files
Get-ChildItem C:\Downloads\PreValidation\*.psa |
ForEach-Object {
# Load the file's contents, replace commas with spaces
(Get-Content $_) -replace ',', ' ' |
# and write it to the correct folder and file name
Out-File C:\Downloads\WIP\psaload.csv
# I guess you'd run whatever you're doing against the file here,
# not after the loop
Remove-Item C:\Downloads\WIP\psaload.csv
}
You can use foreach with Get-Item to do the loop. Get-Item will return a FileInfo
object that you can use to get the file name (and other info) from. So you could do something like:
foreach($file in (Get-Item .\*.psa))
{
Copy-Item $file.FullName "C:\Downloads\Validation\WIP\$($file.Name)";
}
etc.
Try this:
$a = Get-Item .\*.psa
foreach($file in $a)
{
Copy-Item $file.FullName "C:\Downloads\Validation\WIP\$($file.Name.replace(".psa",".psload.csv)";
remove-item $file
}