Powershell rename filename by replacing n characters in ascending order - powershell

I've got a number of files in the following format
I'd like to replace the 3 characters after 60- in ascending order.
I have used the following code to remove the first 28 characters
get-childitem * | rename-item -newname{string.substring(28)}
Then rename using the following
$i = 1
dir | ForEach-Object {$_ | Rename-Item -NewName ('00092-100221-XX-A-233-60-{0:D3} {1}{2}' -f $i++, $.BaseName, $.Extension)}
However I end up losing the original file order. Is there a way I can rename these files by keeping the original file order and also maybe less time consuming?

You can do all in one step, thus preserving the original file order:
$script:i = 1
Get-ChildItem | Rename-Item -NewName {
'00092-100221-XX-A-233-60-{0:D3}{1}' -f $script:i++, $_.Name.SubString(28)
}
(Note that I excplicitly specified the scope for $i, otherwise the value wouldn't be increased.)

Related

Rename a sequence of files to a new sequence, keeping the suffix

I need help to create a command in PowerShell to rename a sequence of files with this format:
001.jpg
001_1.jpg
002.jpg
002_1.jpg
003.jpg
003_1.jpg
into a new sequence that can start with a number such as 9612449, but keeping intact the suffixes, so new sequence would be:
9612449.jpg
9612449_1.jpg
9612450.jpg
9612450_1.jpg
9612451.jpg
9612451_1.jpg
Assuming that 9612449 is an offset to be added to the existing numbers that make up the first _-separated token or all of the base file names:
# Simulate a set of input files.
$files = [System.IO.FileInfo[]] (
'001.jpg',
'001_1.jpg',
'002.jpg',
'002_1.jpg',
'003.jpg',
'003_1.jpg'
)
# The number to offset the existing numbers by.
$offset = 9612449 - 1
# Process each file and apply the offset.
$files | ForEach-Object {
# Split the base name into the number and the suffix.
$num, $suffix = $_.BaseName -split '(?=_)', 2
# Construct and output the new name, with the offset applied.
'{0}{1}{2}' -f ($offset + $num), $suffix, $_.Extension
}
The above yields the output shown in your question.
Applied to a real file-renaming operation, you'd do something like:
Get-ChildItem -LiteralPath . -Filter *.jpg |
Rename-Item -NewName {
$num, $suffix = $_.BaseName -split '(?=_)', 2
'{0}{1}{2}' -f ($offset + $num), $suffix, $_.Extension
} -WhatIf
Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.

Renaming pdf files in sequential order using powershell

I have a large number of pdf's that need renamed in sequential order. These were originally scanned into a single document, then extracted as separate files. When extracted, the name becomes "444026-444050 1", "444026-444050 2", etc. I am trying to rename all the files to match the document number ("444026-444050 1" would become "444026").
I found the following line of code that I can use in Powershell, but it seems that anything over 9 files there is a problem! Once I try it with 10 files, only the first file is saved correctly. The rest become jumbled (file 444027 has the contents of file 444035, then file 444028 has 444027, and 444029 has 444028, etc.)
I imagine there is some sort of problem with a loop, but am having difficulty fixing it.
Can someone help?
thanks
Dir *.pdf | ForEach-Object -begin { $count=26 } -process { rename-item $_ -NewName "4440$count.pdf"; $count++ }
Alright. Let's see if this makes everybody happy. Maybe you should try this with a backup copy of the files.
# make some test files in a new folder
# 1..20 | foreach {
# if (! (test-path "44026-44050 $_.pdf")) {
# echo "44026-44050 $_" > "44026-44050 $_.pdf" }
# }
# rename and pad the first 9 old filenames with a 0 before the last digit for sorting
# is it less than 100 files?
1..9 | foreach {
ren "44026-44050 $_.pdf" "44026-44050 0$_.pdf" -whatif
}
# make dir complete first with parentheses for powershell 5
# pad $count to 2 digits
# take off the -whatif if it looks ok
(dir *.pdf) | foreach { $count = 1 } {
$padded = $count | foreach tostring 00
rename-item $_ -newname 4440$padded.pdf -whatif; $count++ }
The order in which Dir (which is an alias for Get-ChildItem) retrieves the items does not appear to be strictly guaranteed. Furthermore, if it is sorting it's probably sorting them as strings and "444026-444050 10" comes before "444026-444050 2" as strings. It might be worth inserting SortObject into your pipeline and using Split to get at the sequence number you care about:
Dir *.pdf | Sort-Object -Property {[int]$_.Name.Split()[1].Split(".")[0]} | ForEach-Object -begin { $count=26 } -process { rename-item $_ -NewName "4440$count.pdf"; $count++ }
The key part is this new pipeline stage inserted after Dir and before ForEach-Object:
Sort-Object -Property {[int]$_.Name.Split()[1].Split(".")[0]}
This says to sort the output of Dir according to the whatever comes between the first space and the subsequent period, comparing those things as integers (not strings). This ensures that your results will be ordered and that you'll get them in numeric order, not lexicographic order.

Rename file - delete all characters AFTER 2nd underscore

I need to replace the time\date stamp that's included in the filename after 2nd underscore (needs to be in the same format yyyyMMddHHmmss)
example file: 123456_123456_20190716163001.xml
sometimes the file in question gets created with an additional character which invalidates the file, in this case I need to replace this with the current timestamp.
example: 123456_123456_current Timestamp here.xml
The file should never exceed 32 characters(including extension)
I found a script but it deletes everything after the 1st underscore not the 2nd and I'm struggling to find a way to replace the text with the current timestamp.
Get-ChildItem c:\test -Filter 123456_123456*.xml | Foreach-Object -Process {
$NewName = [Regex]::Match($_.Name,"^[^_]*").Value + '.xml' $_ | Rename-Item -NewName $NewName
}
timestamp after 2nd underscore to be updated to the current timestamp if original file exceeds 32 characters
123456_123456_current Timestamp here.xml
this takes advantage of the way a [fileinfo] object is structured. the .BaseName is easy to get to & use .Split() on. then one can use -join to put it back into one basename & finally add the extension onto the basename.
# fake reading in a file info object
# in real life, use Get-ChildItem or Get-Item
$FileObject = [System.IO.FileInfo]'123456_123456_current Timestamp here.xml'
$NewName = -join (($FileObject.BaseName.Split('_')[0,1] -join '_'), $FileObject.Extension)
$NewName
output = 123456_123456.xml
Sticking with the regex theme, you can do the following:
$CurrentTime = Get-Date -Format 'yyyyMMddHHmmss'
$RegexReplace = "(.*?_.*?_).*(\..*)"
Get-ChildItem c:\test -Filter 123456_123456*.xml |
Rename-Item -NewName {$_.Name -replace $RegexReplace,"`${1}$CurrentTime`${2}"}
If duplicate file names are a concern, you can build in an increment to $CurrentTime.
$CurrentTime = Get-Date -Format 'yyyyMMddHHmmss'
$RegexReplace = "(.*?_.*?_).*(\..*)"
Get-ChildItem c:\test -Filter 123456_123456*.xml |
Rename-Item -NewName {
$NewName = $_.Name -replace $RegexReplace,"`${1}$CurrentTime`${2}"
if (test-path $NewName) {
$CurrentTime = [double]$CurrentTime + 1
$NewName = $_.Name -replace $RegexReplace,"`${1}$CurrentTime`${2}"
}
$NewName
}
Explanation:
$RegexReplace contains the regex expression that will need to be matched for the ideal rename operation to happen. The regex mechanisms are explained below:
.*?_.*?_: Matches a minimal number of characters (lazy matching) followed by an underscore and then another minimal number of characters followed by an underscore.
.*: Greedily matches any characters
\.: Literally matches the dot character (.).
(): The parentheses here represent capture groups with the first set being 1 and the second set being 2. These are later referenced as ${1} and ${2} in the -replace operation.
Since Rename-Item -NewName supports delayed script binding, we can just pipe Get-ChildItem output directly to it. The current pipeline object is $_.
The -replace operation uses the variable $CurrentTime, which must be expanded in order for a successful outcome. For that reason, we use double quotes around the replacement. Since we do not want capture groups ${1} and ${2} expanded, we backtick escape them.

Rename files, keep old incremented file order

I have used this to rename and increment file names with PowerShell:
$nr = 1
DIR | % { Rename-Item $_ -NewName ('File{0}.jpg' -f $nr++) }
It works but it seem it is renaming the files in the order of creation date.
I have 500 files each bulked in folders of 100 pics each, all with the order 1-100. The results would be 'picturename'1-500.jpg.
So I need to be able to tell what the first number will be:
'screenshot (9).jpg'
'screenshot (10).jpg'
'screenshot (11).jpg'
etc
I need to rename them to:
'picture109.jpg'
'picture110.jpg'
'picture111.jpg'
etc
Any suggestions how to do this?
Why not sort the results of dir before renaming the files to ensure you have the appropriate order ?
$nr = 1
dir | sort Name | % { Rename-Item $_ -NewName ('File{0}.jpg' -f $nr++) }
With PS complete syntax :
$nr = 1
Get-ChildItem | Sort-Object Name | % { Rename-Item $_ -NewName ('File{0}.jpg' -f $nr++) }

Powershell renaming a specific Character

I've been batch renaming .las files in powershell with a simple script:
cd "C:\Users\User\desktop\Folder"
Dir | Rename-Item -NewName {$_.name-replace "-", "" }
Dir | Rename-Item -NewName {$_.name-replace "_", "" }
Dir | Rename-Item -NewName {$_.BaseName+ "0.las"}
This has been working great, but I need to modify it to account for a different naming convention.
The files start out in this format: 123_45-67-890-12W_0
and get converted to 123456789012W00.las
Occasionally the number after the W will be non zero, and I need to carry that on as the last digit, eg. 123_45-67-890-12W_2 needs to go to 123456789012W02
I'm not sure how to use if statements and to select a specific digit in powershell format, which is how I would approach this problem. Does anyone have some ideas on how to go about this?
Thanks
You can use a regular expression to achieve this:
Get-ChildItem "C:\Users\User\desktop\Folder" | ForEach-Object {
#capture everything we need with regex
$newName = $_.Name -replace "(\d{3})_(\d{2})-(\d{2})-(\d{3})-(\d{2})(\w)_(\d)",'$1$2$3$4$5$6$7'
#insert 0 before last digit and append file extension
$newName = $newName.Insert(($newName.Length - 1), "0") + ".las"
#rename file
Rename-Item $_.FullName -NewName $newName
}
You can use the substring method to get all but the last character in the basename, then concatenate the zero, then use substring again to get the basename's last character, then finish off with the .las extension:
Dir | Rename-Item -NewName {($_.BaseName).substring(0,$_.BaseName.length - 1) + "0" + ($_.BaseName).substring($_.BaseName.length -1,1) + ".las"}
# ^^^^This gets everything but the last charcter^^^ ^^^^^^^^^^This gets the last character^^^^^^^^^^