Why is the For loop looping the incremented number multiple times? - powershell

Alright, so I'm trying to create a script that just renames files within a directory.
Within the Directory there's 2 folders and within each folder there's multiple pictures.
I'm using recurse to go through all of them.
My goal is to rename every single file with the incremented number, but this is not working, instead the script will rename files with the name number (1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,etc)
Anyone able to help with this issue? Any response is appreciated.
What Works:
If I replace what's written inside the script block with:
echo $i
it'll increment with no problem (1, 2, 3, 4, etc)
this does not work:
$targetPath | Rename-Item -NewName {$_.Directory.Name + '_' + $I}
CODE I'M WORKING WITH:
cls
$targetPath = Get-ChildItem -File -path C:\Users\Alban\Pictures\Joshua32GBBackUp -Recurse
$numberOfFiles = Get-ChildItem -File -path C:\Users\Alban\Pictures\Joshua32GBBackUp -Recurse | Measure-Object | % {$_.count}
for($i = 1 ; $i -le $numberOfFiles ; $i++ ) {
$targetPath | Rename-Item -NewName $i -WhatIf
}

You need to iterate through the files as part of the for loop too, like this:
for($i = 0 ; $i -le $numberOfFiles ; $i++ ) {
#use indexing to pick the nTh file from the list
$targetPath[$i] | Rename-Item -NewName $i -WhatIf
}
Note that I dropped your initial setting for $i down to zero, because PowerShell begins indexes at zero.
But I wouldn't do this in production, many people find the logic of a for loop too hard to understand. It would be better to iterate through the files directly and rename them that way instead, like so.
#Set initial value to zero
$i = 0
ForEach ($file in $targetPath){
$newName = "$($file.BaseName)_$i$($file.Extension)"
Rename-Item -Path $file -NewName $newName -WhatIf
$i++
}

To have the files still usable after renaming,
keep the extension and possibly a common prefix.
As Rename-Item accepts piped input no foreach is neccessary
for easier sorting I recommend leading zeroes for the counter
$Counter = 0
Get-ChildItem -File -path C:\Users\Alban\Pictures\Joshua32GBBackUp -Recurse|
Rename-Item -NewName {'File_{0:D3}{1}' -f $Script:Counter++,$_.Extension} -WhatIf
If the output looks OK, remove the trailing -WhatIf

Related

Powershell rename files whilst maintaining the original file order

I've got a set of files in the following format
I'd like to change the file names to the following format
I've used the following code:
`$i = 21
dir | ForEach-Object {$_ | Rename-Item -NewName ('00816-101998-XX-A-2-50-{0:D3} Detalj.{1}' -f $i++, $_.Extension)}`
This code starts renaming with file name A.10.11.11
How do I get it to start from the first file name i.e. 8.A.10.11.8?
Thank you!
Looking at your question, I think this is what you intend to do.
The list of current filenames should be sorted by the integer value the filenames start with.
Next you want to rename them using a counter that starts with value 21
To do this, you can use a ForEach-Object loop, but the -NewName parameter of Rename-Item can also contain a scriptblock containing the action to perform.
$i = 21
(Get-ChildItem -Path 'D:\Test' -Filter '*.pdf' -File) |
Sort-Object #{Expression = {[int]($_.Name -split ' ')[0]}} |
Rename-Item -NewName { '00816-101998-XX-A-2-50-{0:D3} Detalj{1}' -f $script:i++, $_.Extension }
P.S. The image shows the filename starts with a number followed by a space, while in the question you give an example where the number is followed by a dot .. If that is the case in you file names, change [int]($_.Name -split ' ')[0] into [int]($_.Name -split '\.')[0]
1. We need to address and increment the value of the counter $i using the $script:i scoping syntax, otherwise $i does not exist in the NewName scriptblock
2. To avoid renaming files twice, enclose the Get-ChildItem part in the code in between brackets
param(
$directory = "d:\tmp",
[regex]$rx = "(?<=8.A.10.11.)\d+",
[string]$newPrefix = "00816-101998-XX-A-2-50-"
)
<#
8..20 | ForEach-Object {
$filePath = Join-Path $directory -ChildPath "8.A.10.11.$_.pdf"
Out-File -InputObject "some text" -FilePath $filePath -Encoding default
}
#>
Get-ChildItem $directory | ForEach-Object{
Rename-Item $_.FullName -NewName "$newPrefix$((($rx.Matches($_.BaseName)).value).padleft(3,'0'))$($_.Extension)"
}

Is it possible to rename each file in a folder with a different name using powershell or a batch file?

I've tried looking this up but have got nowhere so far and I'm on a time limit.
Let's say I have three files that have similar clones in multiple folders:
(folder1)
image1.png
image2.png
image3.png
(folder2)
image1.png
image2.png
image3.png
I want to rename these using cmd prompt, powershell, or using a .bat to:
(folder1)
B-Sign.png
B-Gauge.png
B-Cup.png
(folder2)
G-Sign.png
G-Gauge.png
G-Cup.png
I intend to run the commands for each folder as only the front of the name is different. I want something simple.
rename-item *.png B-Sign.png
rename-item *.png B-Gauge.png
When it needs a different prefix I would just find and replace the prefix with the new one using ctrl+H in notepad.
Problem is I can't figure out, in any of these, how to automatically cycle to the next file in the folder instead of changing all of the files' names at once. Any one can help?
Yes that's very easy in PowerShell:
Get-ChildItem "C:\temp\Folder1" |
Rename-Item -NewName { "B-" + $_.Name }
The new name is a result of an Expression that Rename-Item knows to evaluate. Because the information is sent down the pipeline the Rename-Item command is run once per file, resulting in names like your example.
Also you can use the filter parameter as you described with either of the below:
Get-ChildItem "C:\temp\Folder1\*.png" |
Rename-Item -NewName { "B-" + $_.Name }
I prefer to filter using the -Filter parameter:
Get-ChildItem "C:\temp\Folder1" -Filter *.png |
Rename-Item -NewName { "B-" + $_.Name }
You can store the folder in a variable too:
$Folder = "C:\temp\Folder1"
Get-ChildItem $Folder -Filter *.png |
Rename-Item -NewName { "B-" + $_.Name }
Update:
Per comments here's an example to correlate a list of prefixes with the renames you want to do:
$Prefix = 'B-'
$NewNames =
#(
'Sign'
'Guage'
'Cup'
)
# If New names are stored ina file simply do:
# $NewNames = Get-Content <FilePath>
$Folder = "C:\temp\Test_10-30-20"
$Files = Get-ChildItem $Folder -Filter *.png
For( $i = 0; $i -lt $Files.Count; ++$i )
{
$CurrentFile = $Files[$i]
$NewName = $Prefix + $NewNames[$i] + $CurrentFile.Extension
Rename-Item $CurrentFile.FullName -NewName $NewName
}

Adding leading zeros to file name strings using PowerShell

I'm new to using PowerShell and am wondering how to simply pad number strings contained in several similar file names to have the same number of digits in each file name.
That is, I have a folder containing these 300 files:
dummy name 1.txt through dummy name 300.txt
and would simply like rename the files that have less than 3 digits in them to all have exactly 3 digits, such as:
dummy name 001.txt through dummy name 300.txt
If your files were produced sequentially and you've got name1.txt
, name2.txt, etc.,
And you want name0001.txt, name0002.txt, etc.
You can do
$j=1;
foreach ($i in Get-ChildItem "./name?.txt" -Name) {
echo $i;
$new_name = "name000" + $j + ".txt";
Rename-Item -Path $i -NewName $new_name;
$j=$j+1;
}
... Then do it again, changing $j to 10 at the start, taking a 0 off, and so on for the hundreds.
Okay for a one off and if you can then fix what's producing the files in the first place.
#TessellatingHeckler gave good answer in the comments:
gci | ren -n {[regex]::replace($_.name, '\d+', {"$args".PadLeft(3, '0')})}
I would do it like this:
$i=0;
$nameLike='dummy name'
[int]$currentid=0
#RENAME TO REMOVE THE SPACE IN THE MIDDLE
gci -File -Path "./" | where{ $_.name -like "$nameLike*"} | %{
#remove space in the middle
$newname = $_.Name.Split(' ')[0] + $_.Name.Split(' ')[1]
#convert the name into the padding you want (3)
[int]::TryParse($_.Name.Split(' ')[2].Split('.')[0],[ref]$CurrentId) | Out-Null
$newname = $newname + $CurrentId.ToString("000") + $_.Extension
Rename-Item -Path $_.FullName -NewName $newname
}
Details in here:
https://medium.com/#josegabrielortegac/powershell-renaming-files-with-powershell-e9012573647a?sk=502148e039058d84fe34608d77cd1aa2
Try this:
1..300 | %{
$source = "dummy name $_.txt"
$target = ('dummy name {0:00#}.txt' -f $_)
rename-item $source -NewName $target
}
Notes:
The outer loop is a little unconventional. Most scripters code this to resemble a java for loop.
The choice of single and double quotes is intentional. Be careful.
The code is a little inelegant, because some parts of the filename are typed in twice.
The assumption is that all 300 files exist. If not, you will get errors.
try this:
Get-ChildItem "c:\temp\" -file -Filter "*.txt" | where basename -match ". \d{1,2}$" | %{
$res=$_.BaseName -split '(.)(\d{1,2})$'
$newnamme="{0}\{1} {2:D3}{3}" -f $_.Directory, $res[0], [int]$res[2], $_.Extension
Rename-Item $_.FullName $newnamme
}

Incremental Counter Prefix in Text File

I'm trying to create a PowerShell script that will scan a folder and its subfolders for videos and create a playlist file.
Playlist Format:
DAUMPLAYLIST
1*file*%filename%
2*file*%filename%
3*file*%filename%
4*file*%filename%
..and so on
So far my script successfully formats everything correctly except for the first incremental number. I can't figure out how to program PowerShell to add a counter prefix before each object.
My script's format.
DAUMPLAYLIST
*file*%filename%
*file*%filename%
*file*%filename%
*file*%filename%
..and so on
My script:
$formats = #("*.avi","*.mp4","*.flv","*.mpg","*.wmv","*.mpeg","*.mov","*.h265","*.mkv","*.asf","*.WebM","*.m4a","*.lnk","*.h264")
$dir = Split-Path $MyInvocation.MyCommand.Path
Add-Content 01.dpl DAUMPLAYER
gci D:\Video\01\ -Include $formats -Recurse |
ForEach-Object -Process { "*file*" + $_ } |
Add-Content .\01.dpl
Simply add a counter to your loop:
$i = 0
Get-ChildItem 'D:\Video\01' -Include $formats -Recurse |
ForEach-Object { "{0}*file*{1}" -f $i, $_.Name; $i++ } |
Add-Content .\01.dpl
Another option is to collect the file list in a variable and process that list with a for loop:
$files = Get-ChildItem 'D:\Video\01' -Include $formats -Recurse
for ($i = 0; $i -lt $files.Count; $i++) {
"{0}*file*{1}" -f $i, $files[$i].Name | Add-Content .\01.dpl
}
The format operator (-f) also allows you to define specific number formats, for instance leading zeroes ({0:d3}).

How to rename files using a list file?

I have 100s of files that I would like to rename in a specific manner according to a correlated list. Rather than repeating the same cmdlets, as below, I would like to point the cmdlet to a couple of list files (below) containing the old and new names, say old.txt and new.txt. How do I do this using PowerShell?
Example:
Rename-Item -Path "E:\MyFolder\old1.pdf" -NewName new1.pdf
Rename-Item -Path "E:\MyFolder\old2.tif" -NewName new2.pdf
Rename-Item -Path "E:\MyFolder\old3.pdf" -NewName new3.pdf
List Files:
old.txt =
old1.pdf
old2.tif
old3.pdf
new.txt =
new1.pdf
new2.tif
new3.pdf
To avoid misalignment between the entries in old.txt and new.txt files, you could also put the files into a CSV file:
renames.csv =
old1.pdf,new1.pdf
old2.tif,new2.tif
old3.pdf,new3.pdf
Now you can use Import-Csv to import your "translation sets":
$Renames = Import-Csv '.\renames.csv' -Header "OldName","NewName"
foreach($File in $Renames) {
Rename-Item $File.OldName $File.NewName
}
Simply read your two files into two lists and process them like this:
$old = Get-Content 'old.txt'
$new = Get-Content 'new.txt'
Set-Location '$:\MyFolder'
for ($i = 0; $i -lt $old.Count; $i++) {
Rename-Item $old[$i] $new[$i]
}
So just for yucks, here is the one-liner version. It does depend on you being in the C:\MyFolder dir when you run it but that could easily be changed to a variable:
Get-Content new.txt -PipelineVariable NewName |
Foreach {$oldNames = Get-Content old.txt;$i=0} {Get-ChildItem $oldNames[$i++]} |
Rename-Item -NewName {$NewName} -WhatIf