Rename-Item with SubString/lastIndexOf - powershell

I'm trying to rename about 500 files in a single directory. Each file is .docx format similar to the below.
Apartment_7-9_01_92.docx
Apartment_7-9_02_192.docx
etc.
I want to remove the last two/three digits before the '.', including the '_' so that I end up with
Apartment_7-9_01.docx
Apartment_7-9_02.docx
Having never really used Powershell, the research I've done so far leads me to something like the below:
Get-ChildItem -File | ForEach-Object { $_ | Rename-Item -NewName -Replace $_.Name.SubString(0, $_.lastIndexOf('_')),".docx"}
I would have thought this would take everything, including and after the last '_' and replace it with '.docx', but it's telling me the lastIndexOf method doesn't exist in this case.
Thanks

I fixed your code, but I don't think it does what you want. $_ is a fileinfo object, and $_.name is a string, and .lastindexof() is a string method. I think you want to replace a substring location after the last "_", not before it.
Get-ChildItem -File | ForEach-Object { $_ | Rename-Item -NewName (
$_.name -Replace $_.Name.SubString(0, $_.Name.lastIndexOf('_')),".docx") -whatif}
What if: Performing the operation "Rename File" on target "Item:
/Users/js/Apartment_7-9_01_92.docx Destination: /Users/js/.docx_92.docx".
What if: Performing the operation "Rename File" on target "Item:
/Users/js/Apartment_7-9_02_192.docx Destination: /Users/js/.docx_192.docx".
This seems to work, and is close to what you were trying. Just specify where the substring starts.
Get-ChildItem -File | ForEach-Object { $_ | Rename-Item -NewName (
$_.name -Replace $_.Name.SubString($_.Name.lastIndexOf('_')),".docx") -whatif}
What if: Performing the operation "Rename File" on target "Item:
/Users/js/Apartment_7-9_01_92.docx Destination:
/Users/js/Apartment_7-9_01.docx".
What if: Performing the operation "Rename File" on target "Item:
/Users/js/Apartment_7-9_02_192.docx Destination:
/Users/js/Apartment_7-9_02.docx".
There's a way to pipe directly to rename-item too, like in the docs:
Get-ChildItem -File | Rename-Item -NewName {
$_.name -Replace $_.Name.SubString($_.Name.lastIndexOf('_')),".docx"} -whatif

You could first split the BaseName on "_", then take every item except the last and rejoin back on "_". An easy way to do that is with $array[0..($array.Length - 2)]. You could also just do $array[0..2] to take the first 3 items. You can then add the Extension at the end. From here you can simply rename the FullName with Rename-Item.
$Path = "PATH/TO/FILES"
Get-ChildItem -Path $Path -File | ForEach-Object {
$items = $_.BaseName -split "_"
$newFileName = ($items[0..($items.Length - 2)] -join "_") + $_.Extension
Rename-Item -Path $_.FullName -NewName $newFileName
}

Related

Optimizing a powershell batch rename script

I wrote the script below to batch rename files with powershell. It is intended to remove dots (.) and every (-) that is followed by a number from the filenames. Example: text.10-1 becomes text101. However, I feel like there must be a way to do this in a line of code.
Also, I wanted it to also enter a subdirectory and do it, how do I write it?
Get-ChildItem | ForEach{ $_ | Rename-Item -NewName "$($_.BaseName.Replace(".",'')+$_.Extension)" }
Get-ChildItem | ForEach{ $_ | Rename-Item -NewName "$($_.BaseName.Replace("-1",'1')+$_.Extension)" }
Get-ChildItem | ForEach{ $_ | Rename-Item -NewName "$($_.BaseName.Replace("-0",'0')+$_.Extension)" }
Get-ChildItem | ForEach{ $_ | Rename-Item -NewName "$($_.BaseName.Replace("-2",'2')+$_.Extension)" }
Get-ChildItem | ForEach{ $_ | Rename-Item -NewName "$($_.BaseName.Replace("-3",'3')+$_.Extension)" }
Get-ChildItem | ForEach{ $_ | Rename-Item -NewName "$($_.BaseName.Replace("-4",'4')+$_.Extension)" }
Get-ChildItem | ForEach{ $_ | Rename-Item -NewName "$($_.BaseName.Replace("-5",'5')+$_.Extension)" }
Get-ChildItem | ForEach{ $_ | Rename-Item -NewName "$($_.BaseName.Replace("-6",'6')+$_.Extension)" }
Get-ChildItem | ForEach{ $_ | Rename-Item -NewName "$($_.BaseName.Replace("-7",'7')+$_.Extension)" }
Get-ChildItem | ForEach{ $_ | Rename-Item -NewName "$($_.BaseName.Replace("-8",'8')+$_.Extension)" }
Get-ChildItem | ForEach{ $_ | Rename-Item -NewName "$($_.BaseName.Replace("-9",'9')+$_.Extension)" }
Thanks
How about this? Get-childitem in parens to avoid the "modifying the loop" problem.
echo hi | set-content -1.txt,-2.txt,-3.txt
(get-childitem) | rename-item -newname { $_.name -replace '-(\d)','$1' } -whatif
What if: Performing the operation "Rename File" on target "Item: C:\users\admin\foo\-1.txt Destination: C:\users\admin\foo\1.txt".
What if: Performing the operation "Rename File" on target "Item: C:\users\admin\foo\-2.txt Destination: C:\users\admin\foo\2.txt".
What if: Performing the operation "Rename File" on target "Item: C:\users\admin\foo\-3.txt Destination: C:\users\admin\foo\3.txt".
You can do this with a single Get-ChildItem call:
(Get-ChildItem -Path 'D:\Test' -File -Recurse) | Where-Object { $_.BaseName -match '[-.]' } |
Rename-Item -NewName {'{0}{1}' -f ($_.BaseName -replace '[-.](\d)', '$1'), $_.Extension} -WhatIf
Note: I have added switch -WhatIf for safety so you can first see what would happen in the console. When you are satisfied with that, remove the -WhatIf switch and run again to actually start renaming the files.
switch -Recurse lets Get-ChildItem also find files in subfolders

How to batch rename files in PowerShell starting with padded first numbers

I'm a PowerShell newbie so please be gentle! I'm looking to bulk rename a collection of files, then pad the first digits so that they play in order on my devices.
For example, I have a folder full of mp3s ABCDEF_S3L1_010221_GHIJK.mp3 through ABCDEF_S3L49_210921_GHIJK.mp3
I'm trying to rename them as 01-lesson.mp3 through 49-lesson.mp3 where the digit after the L is the prefix but I trip up with the padding for lessons 1-9 so they play out of order, i.e. 01 then 10, 11, 12 etc. I've tried using variations of .PadLeft and {0:D2} but keep getting errors such as:
Rename-Item: The filename, directory name, or volume label syntax is incorrect.
My code works without the initial padding:
PS G:\Temp\MP3s> Get-ChildItem -Path *.mp3 | Rename-Item
-NewName {$_.Name -replace '(^ABCDEF_S3L)(\d{1,2})_(\d{6})_(GHIJK)', '$2-lesson'}`
You can use -match and by doing so capture the number behind the L in $matches[1], which can be formatted like you want:
Get-ChildItem -Path 'D:\Test' -Filter '*.mp3' -File |
# apply better filename filter and capture the number after the 'L' in $matches[1]
Where-Object { $_.BaseName -match '^\w+_S\dL(\d+)_\d+_\w+' } |
Rename-Item -NewName { ('{0:D2}-lesson{1}' -f [int]$matches[1], $_.Extension) }
Cheating and going to powershell 7 with the scriptblock replace. You just have to workout where the 2nd group match is within the $_ match object, which turns out to be $_.groups[2].value. Then you can use .padleft(2,'0') on it.
# echo hi | set-content ABCDEF_S3L1_010221_GHIJK.mp3,
# ABCDEF_S3L49_210921_GHIJK.mp3
Get-ChildItem -Path *.mp3 |
% { $_.Name -replace '(^ABCDEF_S3L)(\d{1,2})_(\d{6})_(GHIJK)',
{ $a = $_ } }
.mp3
.mp3
$a
Groups : {0, 1, 2, 3, 4}
Success : True
Name : 0
Captures : {0}
Index : 0
Length : 25
Value : ABCDEF_S3L49_210921_GHIJK
Get-ChildItem -Path *.mp3 |
rename-item -newname {
$_.Name -replace '(^ABCDEF_S3L)(\d{1,2})_(\d{6})_(GHIJK)',
{ $_.groups[2].value.padleft(2,'0') + '-lesson' } } -whatif
What if: Performing the operation "Rename File" on target
"Item: C:\Users\js\foo\ABCDEF_S3L1_010221_GHIJK.mp3
Destination: C:\Users\js\foo\01-lesson.mp3".
What if: Performing the operation "Rename File" on target
"Item: C:\Users\js\foo\ABCDEF_S3L49_210921_GHIJK.mp3
Destination: C:\Users\js\foo\49-lesson.mp3".

How can i concatenate a string to a file name in Powershell?

I have the following in powershell to rename
$version = "2.1.1.1"
But i want to make a copy or rename in the same directory as
myprogram_2.1.1.1.exe
The below doesnt work
Rename-Item -Path "C:\myprogram.exe" -NewName "myprogram.exe" + $version
Any help with this ?
Try this:
$version = "2.1.1.1"
$NewName = (Get-Item "C:\myprogram.exe").Basename + "_" + $version + (Get-Item "C:\myprogram.exe").Extension
Rename-Item -Path "C:\myprogram.exe" -NewName "$NewName"
Try this:
Rename-Item -Path "c:\myprogram.exe" -NewName "myprogram${version}.exe"
When including a variable in a double-quoted string without trailing spaces, you can use ${variable} to enclose it.
You can simply do this:
Rename-Item -Path "C:\myprogram.exe" -NewName "myprogram_$version.exe"
Or:
$version = '2.1.1.1'
dir myprogram.exe | rename-item -newname { $_.BaseName + $version + $_.Extension } -whatif
What if: Performing the operation "Rename File" on target "Item:
C:\Users\js\myprogram.exe Destination:
C:\Users\js\myprogram2.1.1.1.exe".

Powershell rename multiple files

Example "rename multiple files" gives us this:
Get-ChildItem *.txt | Rename-Item -NewName { $_.Name -replace '.txt','.log' }
But I need something like this:
Get-ChildItem *.txt | Rename-Item -NewName { $_.Name -replace '.txt','someArray[$i]' }
How can I do that ?
Simple. Take the quotes off and add a $:
EDIT: Ok, here's my guess. I don't know what $textfile is, or what result you want exactly. [^.jpg] just means any character except those 4.
get-childitem *.jpg |
Foreach {$i=0} {Rename-Item $_ -NewName ($_.name -replace 'jpg', $textfile[$i++]) -whatif}

Powershell Move Item in bulk fail

I'm trying to rename file based on pattern and then move them to a new folder
$ltmpPath = "D:somepath\Temp\"
$ldstPath = "D:\OtherPath\Folder\"
get-childItem $ltmpPath | rename-item -newname { $_.name -replace "(^[a-z]+)(\d\d\d\d)\.pdf", "sg`${2}14.pdf"
get-childItem $ltmpPath | Where-Object { $_.name -match "(^sg)(\d\d\d\d\d\d)\.pdf"} | move-item -Destination $ldstPath -WhatIf
All it does is copying every file to a file D:\OtherPath\Folder instead of D:\OtherPath\Folder\sgxxxxxx.pdf.
What if: Performing the operation "Move File" on target "Item: D:somepath\Temp\sg311014.pdf Destination: D:\OtherPath\Folder\".