How to bulk rename files in folder such that all characters BEFORE and including "_" is removed - powershell

I've been searching online for some help on this but can't seem to find the right answer.
Everything I've come across so far helps with renaming files in batch, but only such that the files are renamed by trimming all characters AFTER a special character (in my case it's "_"). I would actually like to know how to rename all files in a folder such that I trim all characters BEFORE (and including) the underscore.
Example: I have "AB CD_2019481-1" and want the name to be "2019481-1"
I would be open to using Powershell or CMD!
Thanks in advance for any help.

If you know that there is one and only one underscore in all of the file names, you can do a -split on the underscore character, then take the right side of the split.
$Filename = 'AB CD_2019481-1'
$NewFilename = ($Filename -split '_')[1]
The -split '_' splits the string into an array based on the delimiter, underscore. Then the [1] retrieves the 2nd element from the left, which should be the right-hand side of the filename.

Try this out. With the -whatif, it's harmless. It should do what you ask. If your filename has more than one underscore, it may not do what you want. You can pipe get-item or get-childitem to it.
get-item 'AB CD_2019481-1' |
rename-item -newname { $_ -replace '.*_' } -whatif

Related

File rename key off the first underscore to the next period

How can I filter on the first underscore and the following period
Here is what I have so far but the file I'm receiving is changing, in some cases the original filename has an extra underscore. I need a way to account for that.
Get-ChildItem "\\MyFileServer\*" | Rename-Item -NewName { ($_.Name -replace '(?<=^.{3}).{5}', '.').Replace(".vfmpclmadj.", ".sa.") }
original filename
999_987895_888888_544P.44444.vfmpclmadj.000025001.20201216.175314
New filename
999.44444.sa.000025001.20201216.175314
Something like this should work.
('999_987895_888888_544P.44444.vfmpclmadj.000025001.20201216.175314' -replace '_.+?(?=\.)').Replace(".vfmpclmadj.", ".sa.")
It simply looks for an underscore plus any characters up to a period. You could make it more strict but for this example it wasn't needed. Something like this would also work but only on the first underscore. The former could potentially affect other underscores later in the string.
('999_987895_888888_544P.44444.vfmpclmadj.000025001.20201216.175314' -replace '(?<=^[^_]+)_.+?(?=\.)').Replace(".vfmpclmadj.", ".sa.")

Replace text in files within a folder PowerShell

I have a folder that contains files like 'goodthing 2007adsdfff.pdf', 'betterthing 2007adfdsw.pdf', and 'bestthing_2007fdsfad.pdf', I want to be able to rename each, eliminating all text including 2007 OR _2007 to the end of the string keeping .pdf and getting this result: 'goodthing.pdf' 'betterthing.pdf' 'bestthing.pdf' I've tried this with the "_2007", but haven't figured out a conditional to also handle the "2007". Any advice on how to accomplish this is greatly appreciated.
Get-ChildItem 'C:Temp\' -Name -Filter *.pdf | foreach { $_.Split("_2017")[0].substring(0)}
Try the following:
Get-ChildItem 'C:\Temp' -Name -Filter *.pdf |
Rename-Item -NewName { $_.Name -replace '[_ ][^.]+' } -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.
The above uses Rename-Item with a delay-bind script block and the -replace operator as follows:
Regex [_ ][^.]+ matches everything from the first space or _ char. (character set [ _]) through to the following literal . char. ([^.]+ matches one or more chars. other than (^) than .) - that is, everything from the first / _ through to the filename extension (excluding the .).
Note: To guard against file names such as _2017.pdf matching (which would result in just .pdf as the new name), use the following regex instead: '(?<=.)[_ ][^.]+'
By not providing a replacement operand to -replace, what is matched is replace with the empty string and therefore effectively removed.
The net effect is that input files named
'goodthing 2007adsdfff.pdf', 'betterthing 2007adfdsw.pdf', 'bestthing_2007fdsfad.pdf'
are renamed to
'goodthing.pdf', 'betterthing.pdf', 'bestthing.pdf'
Without knowing the names of all the potential files, I can offer this solution that is 100%:
PS> $flist = ("goodthing 2007adsdfff.pdf","betterthing 2007adfdsw.pdf","bestthing_2007fdsfad.pdf")
PS> foreach ($f in $flist) {$nicename = ($f -replace "([\w\s]+)2007.*(\.\w+)", '$1$2') -replace "[\s_].","." ;$nicename}
goodthing.pdf
betterthing.pdf
bestthing.pdf
Two challenges:
the underscore is actually part of the \w character class. So the alternative to the above is to complicate the regex or try to assume that there will always be only one '_' before the 2007. Both seemed risky to me.
if there are spaces in filenames, there is no telling if you might encounter more than one. This solution removes only the one right before 2007.
The magic:
The -replace operator enables you to quickly capture text in () and re-use it in variables like $1$2. If you have more complex captures, you just have to figure out the order they are assigned.
Hope this helps.

Appending string to the end of all file names in PowerShell

I have files look like
data.svg
map.svg
aplicationp.svg
...
*.svg
I am trying to add -b string to the end of all files names bu using power shell rename command like
D:\icons> Dir | Rename-Item -NewName {$_.name -replace ".","-b."}
to get these
data-b.svg
map-b.svg
application-b.svg
but this is not changing anything. How can I achieve this?
Powershell's -replace operator is based on regular expressions. And since . is a wildcard in regex, what should be happening is that each character in the file name is being replaced with the resulting string. So test.txt would become -b.-b.-b.-b.-b.-b.-b in your example.
You likely want to use the Replace method of the .NET String type like this instead.
dir | Rename-Item -NewName { $_.Name.Replace('.','-b.') }
If you want to keep using -replace, you need to escape the . in your expression like this.
dir | Rename-Item -NewName { $_.Name -replace '\.','-b.' }
Both of these have a couple edge case problems that you may want to avoid. The first is narrowing the scope of your dir (which is just an alias for Get-ChildItem) to avoid including files or directories you don't actually want to rename. The second is that a simple replace in the file name doesn't account for file names that contain multiple dots. So you may want to ultimately do something like this if you only care about SVG files that may have multiple dots.
Get-ChildItem *.svg -File | Rename-Item -NewName { "$($_.BaseName)-b$($_.Extension)" }
The replace operator uses regex. Therefore your . needs to be escaped, otherwise it just stands for any character. I would generally make sure to be as specific as possible when writing regexes. The following is a possible solution
Get-ChildItem *.svg | Rename-Item -NewName { $_.name -Replace '\.svg$','-c.svg' }
The $ anchors the expression to the end of the string which makes sure it only changes the extension and not any other text inside the file names.

Rename multiple files with special characters in filenames

Trying to remove the first few characters from a large number of files in the same directory, but having trouble with special characters in the filenames. I also need to use a wildcard to specify what text to remove since that text may contain a one or two digit number.
I'm a novice using v2.0.1.1.
an example filename is
(2) S17- 22429 E1_[49946,12147]_composite_image.jpg
I need to remove the initial number in parenthesis along with the following space. the number in parenthesis may be one or two digits, hence the need for a wildcard.
Resulting filename should be:
S17- 22429 E1_[49946,12147]_composite_image.jpg
All files will contain coordinates separated by "," in square brackets, and all will be .jpg, but everything else in the final names names will vary.
Been reading through various articles on bits and pieces of what is going wrong, have tried code below.
Issue seems to be with square brackets and maybe the comma, but only techniques I can find (``[, etc.) tell you how to deal with them in the search string, not in the portion of the string you are uninterested in. -literalpath does not seem to help, either.
dir | rename-item -NewName { ($_.name) -Replace("\(*\) ","")}
And have tried various alterations to this basic code.
Runs through every file, but all with:
Rename-Item : Cannot rename because item at 'Microsoft.PowerShell.Core\FileSystem::C:\...\(2) S17- 22429 E1_[49946,12147]_composite_image.jpg' does not exist.
At line:1 char:19
+ dir | rename-item <<<< -NewName { ($_.name) -Replace("\(*\) ","")}
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
No need for powershell complex scripts, you can do in simple CMD.
This will rename files with 1 length number:
for %a in ("(?) *.*") do ren "%a" "////*.*"
And this for a 2 length number:
for %a in ("(??) *.*") do ren "%a" "/////*.*"
you might be tempted to do:
for %a in ("(*) *.*") do ren "%a" "////*.*"
but then you will end up filenames with spaces at the beginning if they have 2+ length numbers.
How it works ?
Let's first see the rename:
So if you have this filename: (2) S17- 22429 E1_[49946,12147]_composite_image.jpg, what we want to do is:
ren "(?) S17- 22429 E1_[49946,12147]_composite_image.jpg" "////*.*";
The ? question mark means any one length character.
The * asterisk means any many characters.
The / means discard this one character.
so (2) S17- 22429 E1_[49946,12147]_composite_image.jpg => S17- 22429 E1_[49946,12147]_composite_image.jpg
for the 2 length numbers, you will need two ?? and five ///// like this:
ren "(??) S17- 22429 E1_[49946,12147]_composite_image.jpg" "/////*.*";
We use the space after the ) so the pattern is matched more strict.
Then we use:
for %a in (`condition`) do `command`
it iterates for every file in condition and then execute the command. %a is a special wildcard that you can use on the command to get the filename.
so basically, what we do is for each file, rename discarding the first 4 or 5 charaters, and we use the ? in the condition so we get all files that matches the pattern.
and voila, you can also adapt as your needs.
Looks like the Rename-Item has problems with the special characters indeed. When Cmdlets fail you it is often a good idea to look for object methods. Try this one. It works for me on PS 5.1
gci *.jpg | % {
$_.MoveTo("$($_.DirectoryName)\$($_.Name -replace '\(.*\) ','')")
}
Works for me if I do:
Get-ChildItem -Path 'D:\' -Filter '*.jpg' |
ForEach-Object { $_ | Rename-Item -NewName ($_.Name -replace '^\(\d+\)\s*', '')}
This is assuming the filename always starts with a number between the brackets. If it can be any character (or even nothing) between these brackets, do ($_.Name -replace '^\(.*\)\s*', '')
EDIT
Apparently, renaming multiple files through the pipeline needs the syntax for Rename-Item to be a script block, as shown in the fourth example in the docs.
If you do this:
Get-ChildItem -Path 'D:\' -Filter '*.jpg' | Rename-Item -NewName { $_.Name -replace '^\(\d+\)\s*', '' }
It works.
So, you almost got it right except for two things:
you've added round brackets to the -replace parameter
you've added the regex quantifier * directly after the opening bracket, so basically your regex asked for zero or more ( characters instead of whatever is between the brackets in the file name
Hope that helps

Q: Powershell - read and report special characters from file

I've got a huge directory listing of files, and I need to see what special characters exist in the file names - specifically nonstandard characters like you'd get using ALT codes.
I can export a directory listing to a file easily enough with:
get-childitem -path D:\files\ -File -Recurse >output.txt
What I need to do however, is pull out the special characters, and only the special characters from the text file. The only way I can think to easily quantify everything "special" (since there are a ton of possibilities in the that character set) would be to compare the text against a list of characters I'd want to keep, stored in a joined variable (a-z, 0-9, etc)
I can't quite figure out how to pull out the "good" characters, leaving only the special ones. Any ideas on where to start?
I take "special" characters to be anything that falls outside US ASCII.
That basically means any character with a numerical value of 128 or more, easy to inspect in a Where-Object filter:
Get-ChildItem -File -Recurse |Where-Object {
$_.Name.ToCharArray() -gt 127
}
This will return all files containing "special" characters in their name.
If you want to extract the special characters themselves, per file, use ForEach-Object:
Get-ChildItem -File -Recurse |ForEach-Object {
if(($Specials = $_.Name.ToCharArray() -gt 127)){
New-Object psobject -Property #{File=$_.FullName;Specials=$(-join $Specials)}
}
}
Look at piping your results to Select-String. With Select-String you can specify a list of regex values to search for.