Powershell - Rename filename by removing the last few characters - powershell

I want to remove the last 11 characters of multiple files names. For example
I have these file names:
ABCDE_2015_10_20
HIJKL_2015_10_20
MNOPQ_2015_10_20
RSTUV_2015_10_20
would like to rename them to
ABCDE
HIJKL
MNOPQ
RSTUV
I have tried using the follwing code:
Get-ChildItem 'E:\Thomson Reuters\Stage' | rename-item -newname { [string]($_.name).substring($_.name.length -14) }
Can anybody tell me where I am going wrong?

You're almost there, you just need to tell substring exactly where to start and end:
Get-ChildItem 'E:\Thomson Reuters\Stage' | rename-item -newname { $_.name.substring(0,$_.name.length-11) }
By passing two integers to substring you give it the StartIndex and Length of the string you want to capture. See here for the documentation

Just to add to the response from arco444:
Get-ChildItem 'E:\Thomson Reuters\Stage' -filter *.txt | rename-item -NewName {$_.name.substring(0,$_.BaseName.length-6) + $_.Extension -replace "_"," "}
This would rename all .txt files in the directory, remove the last 6 characters of the file name, replace any remaining underscore in the filename with a space but still retain the file extension.
So assuming these were text files you would see something like this:
ABCDE_2015_10_20.txt
HIJKL_2015_10_20.txt
MNOPQ_2015_10_20.txt
RSTUV_2015_10_20.txt
Become this:
ABCDE 2015.txt
HIJKL 2015.txt
MNOPQ 2015.txt
RSTUV 2015.txt

As you want to split the file name at the 1st underscore,
use the .split() method or -split operator with the zero based index [0].
rename changing the BaseName and keeping the Extension
Get-ChildItem 'E:\Thomson Reuters\Stage' |
Rename-Item -NewName { $_.BaseName.Split('_')[0] + $_.Extension }

Related

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.

Powershell Remove Text Between before the file extension and an underscore

I have a few hundered PDF files that have text in their file names which need to be removed. Each of the file names have several underscores in their names depending on how long the file name is. My goal is to remove the text in that exists between the .pdf file extension and the last _.
For example I have:
AB_NAME_NAME_NAME_NAME_DS_123_EN_6.pdf
AC_NAME_NAME_NAME_DS_321_EN_10.pdf
AD_NAME_NAME_DS_321_EN_101.pdf
And would like the bold part to be removed to become:
AB_NAME_NAME_NAME_NAME_DS_123_EN.pdf
AC_NAME_NAME_NAME_DS_321_EN.pdf
AD_NAME_NAME_DS_321_EN.pdf
I am a novice at powershell but I have done some research and have found Powershell - Rename filename by removing the last few characters question helpful but it doesnt get me exactly what I need because I cannot hardcode the length of characters to be removed because they may different lengths (2-4)
Get-ChildItem 'C:\Path\here' -filter *.pdf | rename-item -NewName {$_.name.substring(0,$_.BaseName.length-3) + $_.Extension}
It seems like there may be a way to do this using .split or regex but I was not able to find a solution. Thanks.
You can use the LastIndexOf() method of the [string] class to get the index of the last instance of a character. In your case this should do it:
Get-ChildItem 'C:\Path\here' -filter *.pdf | rename-item -NewName { $_.BaseName.substring(0,$_.BaseName.lastindexof('_')) + $_.Extension }
Using the -replace operator with a regex enables a concise solution:
Get-ChildItem 'C:\Path\here' -Filter *.pdf |
Rename-Item -NewName { $_.Name -replace '_[^_]+(?=\.)' } -WhatIf
-WhatIf previews the renaming operation. Remove it to perform actual renaming.
_[^_]+ matches a _ character followed by one or more non-_ characters ([^-])
If you wanted to match more specifically by (decimal) digits only (\d), use _\d+ instead.
(?=\.) is a look-ahead assertion ((?=...)) that matches a literal . (\.), i.e., the start of the filename extension without including it in the match.
By not providing a replacement operand to -replace, it is implicitly the empty string that replaces what was matched, which effectively removes the last _-prefixed token before the filename extension.
You can make the regex more robust by also handling file names with "double" extensions; e.g., the above solution would replace filename a_bc.d_ef.pdf with a.c.pdf, i.e., perform two replacements. To prevent that, use the following regex instead:
$_.Name -replace '_[^_]+(?=\.[^.]+$)'
The look-ahead assertion now ensures that only the last extension matches: a literal . (\.) followed by one or more (+) characters other than literal . ([^.], a negated character set ([^...])) at the end of the string ($).
Just to show another alternative,
the part to remove from the Name is the last element from the BaseName splitted with _
which is a negative index from the split [-1]
Get-ChildItem 'C:\Path\here' -Filter *.pdf |%{$_.BaseName.split('_\d+')[-1]}
6
10
101
as the split removes the _ it has to be applied again to remove it.
Get-ChildItem 'C:\Path\here' -Filter *.pdf |
Rename-Item -NewName { $_.Name -replace '_'+$_.BaseName.split('_')[-1] } -whatif
EDIT a modified variant which splits the BaseName at the underscore
without removing the splitting character is using the -split operator and
a RegEx with a zero length lookahead
> Get-ChildItem 'C:\Path\here' -Filter *.pdf |%{($_.BaseName -split'(?=_\d+)')[-1]}
_6
_10
_101
Get-ChildItem 'C:\Path\here' -Filter *.pdf |
Rename-Item -NewName { $_.Name -replace ($_.BaseName -split'(?=_)')[-1] } -whatif

Powershell add suffix to filenames, based on prefix

I have a directory that consists of a number of text files that have been named:
1Customer.txt
2Customer.txt
...
99Customer.txt
I am trying to create powershell script that will rename the files to a more logical:
Customer1.txt
Customer2.txt
...
Customer99.txt
The prefix can be anything from 1 digit to 3 digits.
As I am new to powershell, I really don't know how I can achieve this. Any help much appreciated.
The most straigth forward way is a gci/ls/dir
with a where matching only BaseNames starting with a number with a
RegEx and piping to
Rename-Item and building the new name from submatches.
ls |? BaseName -match '^(\d+)([^0-9].*)$' |ren -new {"{0}{1}{2}" -f $matches[2],$matches[1],$_.extension}
The same code without aliases
Get-ChildItem |Where-Obect {$_.BaseName -match '^(\d+)([^0-9].*)$'} |
Rename-Item -NewName {"{0}{1}{2}" -f $matches[2],$matches[1],$_.extension}
Here is one way to do it:
Get-ChildItem .\Docs -File |
ForEach-Object {
if($_.Name -match "^(?<Number>\d+)(?<Type>\w+)\.\w+$")
{
Rename-Item -Path $_.FullName -NewName "$($matches.Type)$($matches.Number)$($_.Extension)"
}
}
The line:
$_.Name -match "^(?<Number>\d+)(?<Type>\w+)\.\w+$")
takes the file name (e.g. '23Suppliers.txt') and perform a pattern match on it, pulling out the number part (23) and the 'type' part ('Suppliers'), naming them 'Number' and 'Type' respectively. These are stored by PowerShell in its automatic variable $matches, which is used when working with regular expressions.
We then reconstruct the new file using details from the original file, such as the file's extension ($_.Extension) and the matched type ($matches.Type) and number ($matches.Number):
"$($matches.Type)$($matches.Number)$($_.Extension)"
I'm sure there's a nicer way to do this with regex, but the following is a quick first go at it:
$prefix = "Customer"
Get-ChildItem C:\folder\*$prefix.txt | Rename-Item -NewName {$prefix + ($_.Name -replace $prefix,'')}

How do I replace substrings that start with 'X' and end with '.tif'?

I have a string that includes both data and the names of image files, delineated by tabs
The names of the image files are 41 characters long and end with the file extension .tif (example: X1126225548817153725411111_PPPPP_00333.tif)
I would like to remove the substrings that match the following criteria, but I'm not sure which string tricks to use
You can try the following to rename these files:
get-childitem "YourDirectory\*.tif" |
foreach { $newName = ($_.BaseName).TrimStart("X")
Rename-Item $_.FullName $newName }
Basename removes the file extension, and TrimStart("X") removes the leading "X".
I figured it out. I was using the wrong wildcard for regular expressions
Here's the code:
PS C:\Users\mharper> $data[1] -Replace "X......................................tif\`t" , ""\`
-Replace "\`t\`t" , "`t"

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^^^^^^^^^^