Replacing only part of the file name in Powershell - powershell

I got a problem with powershell and some pdfs names
So there is a bunch of them:
2021_01_21_Aneks_nr2.pdf
2021_11_31_Aneks_nr3.pdf
2021_05_04_Aneks_nr4.pdf
I need to replace "_" with "-" but only near date.
Output should look like this:
2021-05-04_Aneks_nr4.pdf
I'm new to programming and couldn't find solution in internet.
I was using this code :
Get-Childitem | foreach { rename item $_ $_.Name.Replace("_","-") }
But it works on all "_" so I cant use it in this scenario.
Thanks for help! :)

Using the -replace operator instead of the dot net method you can use regex. And there you can specify to replace only underlines between digits:
Get-ChildItem |
ForEach-Object {
Rename-Item -Path $_.FullName -NewName $($_.Name -replace '(?<=\d)_(?=\d)', '-')
}

Here you go
#Loop through files
get-childitem [path] | ForEach-Object {
#match pattern
$null = $_.name -match '\d{4}_\d{2}_\d{2}'
#get matching pattern
$pattern = $matches[0]
#replace _ with -
$replace = $pattern -replace '_','-'
#build new name
$newName = $_.name -replace $pattern,$replace
#rename file
rename-item -Path $_.fullname -NewName $newName
}
It matches the current name of the file for the pattern '\d{4}_\d{2}_\d{2}', gets the matching string, replaces _ with - and finally build the new name by replacing the matching string with the updated version.

Related

How to add a symbol in a middle of a file name in PS

I have modified several thousand files with a various things requested by the owners.
Now, I need to add one final thing and I am not 100% on how to do it.
Scenario is as follows - all files have a 10 digit number at the start, I need to add a hyphen after the number. String is a variable but it is always the same length.
1234567890abcdefgh.xls would be an example
I have used GCI to make changes to symbols and static parts but not sure how to call for insertion in a specific place of a file (after the 10th character of a variable string)
Any ideas would be most welcome!
You can use the $matches you get from the capturing groups of a -match comparison:
(Get-ChildItem -Path 'X:\WhereTheFilesAre' -File) |
Where-Object { $_.BaseName -match '^(\d{10})([^-].*)' } |
Rename-Item -NewName { '{0}-{1}{2}' -f $matches[1], $matches[2], $_.Extension }
or by using the Substring() method:
(Get-ChildItem -Path 'X:\WhereTheFilesAre' -File) |
Where-Object { $_.BaseName -match '^\d{10}[^-]' } |
Rename-Item -NewName { $_.Name.Substring(0,10) + '-' + $_.Name.Substring(10) }
or use the regex -replace operator:
(Get-ChildItem -Path 'X:\WhereTheFilesAre' -File) |
Where-Object { $_.BaseName -match '^\d{10}[^-]' } |
Rename-Item -NewName { $_.Name -replace '^(\d{10})', '$1-' }
You can use string.Insert() to insert a string into another at a specific offset:
PS ~> '1234567890abcdefgh.xls'.Insert(10, '-')
1234567890-abcdefgh.xls
To apply to all files in a directory, you could do something like this:
Get-ChildItem -File |Where-Object Name -match '^\d{10}[^-]' |Rename-Item -NewName { $_.Name.Insert(10, '-') }
The regular expression pattern ^\d{10}[^-] will only match file names that start with 10 digits followed by something other than a hyphen (to avoid renaming files that already comply with the naming convention)

Replace Part of a File Name in Powershell

I have files that look like this:
2020-0517-example.pdf
2020-0412-example.pdf
2020-0607-example.pdf
I would like to rename the files to:
2020-0723-example.pdf
2020-0723-example.pdf
2020-0723-example.pdf
I would basically be replacing the dates to today's date while keeping the year and the suffix.
If you want to add a bit of sanity checking to make sure you are dealing with dates, you can use pattern matching and then rename the partial date:
$date = Get-Date -Format MMdd
Get-ChildItem -Path <filepath> -File |
Where Basename -match '^(?:19|20)\d\d-(?:0[1-9]|1[012])\d\d-' |
Rename-Item -NewName { $_.Name -replace '(?<=^\d{4}-)\d{4}',$date } -whatif
Alternatively, you can parse the date string first to verify it using TryParseExact:
$date = Get-Date -Format MMdd
Get-ChildItem -Path <filepath> -File |
Where Name -match '^\d{4}-\d{4}-' | Foreach-Object {
if ([datetime]::TryParseExact($_.Name.Substring(0,9),'yyyy-MMdd',[System.Globalization.CultureInfo]::InvariantCulture,[System.Globalization.DateTimeStyles]::None,[ref]0)) {
$FileParts = $_.Name -split '-',3
Rename-Item -Path $_ -NewName ($FileParts[0],$date,$FileParts[2] -join '-') -WhatIf
}
}
You will need to remove the -WhatIf parameter for the rename operation to complete.
Explanation:
Using -split '-',3, we ensure that we are left with no more than three array elements. This provides a predictable number of indexes for putting the file name back together. [0] will be the year. [1] will be the month-day. [2] will be the remainder of the file name.
Please see the following for the -replace and -match regex details:
Regex -Match
Regex -Replace
You could split by "-" and stitch together with String.Format:
$filename = "2020-0517-example.pdf"
$today = Get-Date
$arr = $filename.Split("-")
$newname = "{0}-{1:MMdd}-{2}" -f $arr[0], $today, $arr[2]

PowerShell bulk replacing a specific character and rename file extension

I need to bulk rename files in a file share that
contain a specific character, namely a tilde ~ and
have the file extension in capital letters or none at all.
The goal would be to replace the tilde with a simple -, keep the file extension, if there is one, but transform it into lowercase letters.
I've had success with the first part of the script that finds the files
$PATH = "\\<Fileservername>\<Folder>\"
$pattern = "*~*"
Get-ChildItem $PATH -Recurse | where {$_.Name -like $pattern}
What I'm struggling with is the second part of the script the renaming.
I've found two topics here:
Powershell renaming a specific Character
PowerShell Regex Bulk Replace Filenames
I haven't been able to adapt those solutions to my need plus there may be additional steps to take in order to convert the given file name from capital letters to lowercase letters or skip this if the file has no file extension.
An example would be to rename ACUJLH~H to ACUJLH-H and KYA3BM~Q.PDF to KYA3BM-Q.pdf.
Here's my contribution. I have added the -File switch to the Get-ChildItem cmdlet so it will look for files only and will not try and handle directory names.
Also, I have changed the replace pattern to ~+ so files that have repeating tildes will be replaced with a single - character. (KYA3BM~~~~Q.PDF becomes KYA3BM-Q.pdf)
$path = "D:\Code\PowerShell\StackOverflow"
$pattern = "*~*"
Get-ChildItem $path -Recurse -File | Where-Object {$_.Name -like $pattern} |
ForEach-Object {
$directory = $_.DirectoryName # or [System.IO.Path]::GetDirectoryName($_.FullName) or use Split-Path $_.FullName -Parent
$filename = $_.BaseName -replace '~+', '-' # or [System.IO.Path]::GetFileNameWithoutExtension($_.Name) -replace '~+', '-'
$extension = $_.Extension # or [System.IO.Path]::GetExtension($_.Name)
if (![string]::IsNullOrEmpty($extension)) { $filename += $extension.ToLower() }
$newname = Join-Path -Path $directory -ChildPath $filename
Rename-Item -LiteralPath $_.FullName -NewName $newName -Force
}
You will need to filter files those meets your criteria. Then using ForEach-Object compare for extensions and build new file names for every found item. Finally, using Rename-Item cmdlet you make the change.
$PATH = '\\<Fileservername>\<Folder>\'
Get-ChildItem $PATH -Recurse -Include '*~*' | ForEach-Object {
[String]$Extension = [System.IO.Path]::GetExtension($_)
[String]$NewFileName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name) -replace '~','-'
if ($Extension){ $NewFileName += $Extension.ToLower() }
Rename-Item $_.FullName $(Join-Path ([System.IO.Path]::GetDirectoryName($_)) $NewFileName) -Force
}

Programmatically edit file names to remove leading text

I have a variety of files with names in the directory that look like this:
first_file_123456.jpg
5 * second_file_246531 (2).jpg
What I am looking to do is lay my hands on a PowerShell script that can take these files and rename them like this:
123456.jpg
246531 (2).jpg
I am looking to strip the last underscore and all text leading up to it to rename my files so they can match item numbers in my enterprise resource planning system. This system is much older (2004 technology) so automating from that side is out.
What i have tried to wire up so far and does not seem to work properly is as follows:
Get-ChildItem -Recurse -filter *_* | `
Foreach-Object {
$oldName = $_.Name
$pos = $oldName.LastIndexOf("_")
$newName = $oldName.Substring($pos + 1)
if (Test-Path $newName) {
# This is where I get lost - if it runs into a duplicate file name
# how can I make the name unique
}
#write-host $_.fullname
write-host $oldName renamed To: $newName | Out-File renamelog.txt
#rename-item $_.FullName -NewName $newName
}
I commented out the commands that actually do something to see what the output is.
Enumerate your files, filter for filenames containing an underscore, then rename them with everything up to and including the last underscore removed.
$re = '^.*_'
Get-ChildItem 'C:\some\folder' |
Where-Object { $_.Name -match $re } |
Rename-Item -NewName { $_.Name -replace $re }
Here's a short demo that uses the LastIndexOf and Substring methods:
$name = "first_file_123456.jpg"
$indexOfLastUnderscore = $name.LastIndexOf("_")
$newName = $name.Substring($indexOfLastUnderscore + 1, $name.Length - $indexOfLastUnderscore - 1)
# $newName now contains "123456.jpg"
Here's another way that uses PowerShell's -split operator and array indexing:
$name = "first_file_123456.jpg"
$newName = ($name -split '_')[-1]
$newName
# $newName now contains "123456.jpg"
Batch rename:
Get-Childitem -path $startDir -recurse |
where { ! $_.PSIsContainer } |
foreach {
$newName = Join-Path $_.Directory ($_.Name -replace '.*_', '');
Rename-Item $_.FullName $newName;
};

Renaming files with powershell to remove a string

I have a bunch of files with the same string in them and would like to remove them
Dir | Rename-Item -NewName { $_.Name -replace " (my string here)","" }
However, this does not seem to be removing the string from all the files that have that string in the file name. Do I need ReGex?
There is a space before the ( which makes me think I need ReGex in some way.
So I was right about needing ReGex with how Powershell does stuff:
Dir | Rename-Item -NewName { $_.Name -replace "(\s*) \(STRING HERE\)","" }
-replace does indeed use regex(case-insensitive).
You can achieve the same result without regex with the use of the .replace which is a string method like so:
Get-ChildItem -path 'your path' |
Rename-Item -NewName { $_.BaseName.replace(' (my string here)','') + $_.extension } -WhatIf
notice the use of $_.basename instead of name. this is because name consists of both filename and extension whereas basename does not.