Powershell renaming a specific Character - powershell

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

Related

PowerShell - Why is this not renaming my files?

I have been looking around for a way to quickly and easily rename hundreds os files in one go.
something where I only have to change smalle parts for it to be reused somewhere else.
So i ended up starting to make this script. shown below...
the output should come out like this:
Show Title - SXX.EXXX - Episode title - [release year]
the raw files all looks like this:
XXX Episode title [release year]
It does not work right now. and i haven't been able to see why yet.
Whenever i run it, it does nothing. but i do not get any error message.
$ShowTitle = "My Title -"
$SeasonNumber = "02"
# Getting all child files (In ALL subfolders)
$files = Get-Childitem –Path Get-Location -Recurse |
Where-Object { $_.Name -match $_.Name } |
# Insert a ' - ' between the episode number and the episode text.
Rename-Item -NewName {$_.BaseName.insert(5,'-') + $_.Extension} |
# Append title and season number to the beginning of the file.
Rename-Item -NewName { $ShowTitle + "S" + $SeasonNumber + ".E" + $_.Name} |
# Makes a "-" between episode title and year of release.
Rename-Item -NewName { $_.Name -replace '\[', '- [' }
it worked on a smaller scale before. like this:
$files = Get-Childitem –Path "C:\Users\user\Videos\Series\show\Season x" -Recurse |
Where-Object { $_.Name -match 'show title' } |
Rename-Item -NewName { $_.Name -replace '\[', '- [' }
But i would like to do all the steps above in one go.
Can someone give me a hint so I can find the right answer to my little problem?
Thank you in advance.
You've got a lot of bugs here.
Get-Childitem –Path Get-Location -Recurse
This doesn't make sense. You're looking for a file or folder in the current directory with the literal name Get-Location. Like C:\Get-Location\. If you want to get the files in the current directory, you just don't specify the -Path parameter: Get-ChildItem -Recurse.
Where-Object { $_.Name -match $_.Name } is kind of nonsense code? The right hand side of the -match operator is going to be treated as a regular expression. That means . means "any character", square brackets and parentheses have special meaning, and so on. It's often going to always be true, but I can't imagine that you actually want to do what that says. It's very possible to construct a valid filename that doesn't match a regular expression with the same string value. For example '[01] File.avi' -match '[01] File.avi' is false.
Second, the -NewName parameter takes a string, while {$_.BaseName.insert(5,'-') + $_.Extension} is a ScriptBlock. That may work because some parts of Powershell allow that, but idiomatically I would say that it's wrong because it will not work consistently. A better option would be to use a string with embedded subexpressions like -NewName "$($_.BaseName.Insert(5,'-'))$($_.Extension)"
Finally, Rename-Item doesn't pass any output to the pipeline without the -PassThru parameter. You'd only process the first item and then I imagine the system would complain of an empty pipeline or only the first Rename-Item would do anything.
Try something like this:
$ShowTitle = "My Title -"
$SeasonNumber = "02"
# Getting all child files (In ALL subfolders)
$files = Get-Childitem -Recurse |
Where-Object { $_.Name -match 'some value or delete this command if you want all files' } |
# Insert a ' - ' between the episode number and the episode text.
Rename-Item -NewName "$($_.BaseName.Insert(5,'-'))$($_.Extension)" -PassThru |
# Append title and season number to the beginning of the file.
Rename-Item -NewName "$($ShowTitle)S$($SeasonNumber).E$($_.Name)" -PassThru |
# Makes a "-" between episode title and year of release.
Rename-Item -NewName "$($_.Name -replace '\[', '- [')" -PassThru

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.

Retain initial characters in file names, remove all remaining characters using powershell

I have a batch of files with names like: 78887_16667_MR12_SMITH_JOHN_713_1.pdf
I need to retain the first three sets of numbers and remove everything between the third "_" and "_1.pdf".
So this: 78887_16667_MR12_SMITH_JOHN_713_1.pdf
Becomes this: 78887_16667_MR12_1.pdf
Ideally, I'd like to be able to just use the 3rd "_" as the break as the third set of numbers sometimes includes 3 characters, sometimes 4 characters (like the example) and other times, 5 characters.
If I used something like this:
Get-ChildItem Default_*.pdf | Rename-Item -NewName {$_.name -replace...
...and then I'm stuck: can I state that everything from the 3rd "" and the 6th "" should be replaced with "" (nothing)? My understanding that I'd include ".Extension" to also save the extension, too.
You can use the -split operator to split your name into _-separated tokens, extract the tokens of interest, and then join them again with the -join operator:
PS> ('78887_16667_MR12_SMITH_JOHN_713_1.pdf' -split '_')[0..2 + -1] -join '_'
78887_16667_MR12_1.pdf
0..2 extracts the first 3 tokens, and -1 the last one (you could write this array of indices as 0, 1, 2, -1 as well).
Applied in the context of renaming files:
Get-ChildItem -Filter *.pdf | Rename-Item -NewName {
($_.Name -split '_')[0..2 + -1] -join '_'
} -WhatIf
Common parameter -WhatIf previews the rename operation; remove it to perform actual renaming.
mklement0 has given you a good and working answer. Here is another way to do it using a regex.
Get-ChildItem -Filter *.pdf |
ForEach-Object {
if ($_.Name -match '(.*?_.*?_.*?)_.*(_1.*)') {
Rename-Item -Path $_.FullName -NewName $($Matches[1..2] -join '') -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 to rename a file, only removing the first instance of the character

I have a large list of names and certain filed tied to each name such as:
First_Last_DOB_RT_... and so on. What I want to do is add a -x to the beginning of the filename. However, let's say the first and last name was: Susy_Sample. In this case simply using the
Dir | Rename-Item -NewName {$_.name -replace "S","-x S"}
will end up converting each instance of S to -x S when I only want the beginning of the file to start with -x. How would can I do that?
Simply replace the beginning of the string with -x:
dir | Rename-Item -NewName { $_.Name -replace '^', '-x ' }
Another option is to concatenate -x with the name as #PetSerAl suggested:
dir | Rename-Item -NewName { '-x ' + $_.Name }