Removing multiple consecutive periods from file names - powershell

I am working on cleaning up a file share for a SharePoint migration, and I am writing a script to either remove or replace unwanted characters from file names. I am struggling to remove multiple consecutive periods (file..example.txt as an example of what I am dealing with).
I was able to use the simple replace script below to deal with all of the other objectionable characters, but the script fails when attempting to replace double period errors.
dir -recurse | rename-item -NewName {$_.name -replace ".." , ""}
I expect that a file with a name like file..example.txt to become fileexample.txt, however nothing changes.

As Matt mentioned in the comments, -replace uses regex. In regex, the . character is a wildcard representing any single character. To actually select a dot, you must use \..
The regex for selecting anything with two or more dots is \.\.+ (RegExr)
Therefore, your command should be:
dir -Recurse | Rename-Item -NewName {$_.name -replace "\.\.+" , ""}
However, dir is an alias for Get-ChildItem. It's a good practice when writing scripts to avoid aliases whenever possible as it can create a situation where your script does not work in certain environments. With that in mind, your command should be:
Get-ChildItem -Recurse | Rename-Item -NewName {$_.name -replace "\.\.+" , ""}

You can use .replace() instead, and not have to worry about the regex. Note that Rename-Item is using a delay bind script block https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parameters?view=powershell-5.1
Get-Childitem -Recurse -Filter *..* |
Rename-Item -NewName { $_.Name.Replace('..','.') } -WhatIf

Related

Powershell Changing Bulk File Extensions All At Once

Long story short: need to change multiple file extensions that are . (in Windows, the file extension is just a .) to .csv. I am able to do this in command prompt with this:
ren *. *.csv
But when I try to rename in Powershell, it only changes the first file (result: .csv.csv.csv.csv.csv.csv.csv) while the rest of the files remain untouched. I used this command:
Dir | Rename-Item -NewName { $_.name -replace ".",".csv" }
Can someone explain what I'm doing wrong and how come the first file is being renamed as such? Don't understand why Powershell makes it more complicated since it is based off CMD.
-replace is using regular expression matching where . will match any character so every character is replaced with .csv. Try this to replace *.txt and *.file with *.csv
gci -File | Rename-Item -NewName { $_.name -replace "\.(txt|file)$", ".csv" }
The question has changed. If your files really end in . which I can't actually reproduce then -replace "\.$", ".csv" where \. matches a literal dot and $ matches the end of the line.
If your files have no extension at all then you could do -replace "$", ".csv"
Or you could filter for files with no extension and just add one
gci -File |? Extension -eq '' |% { Rename-Item $_.FullName -NewName "$($_).csv" }
Get-ChildItem -Path C:\ -File | ForEach {Rename-Item $_.FullName -NewName ($_.name).Replace(".txt",".csv")}
Using dot notation, it reads characters as such; meaning no need in escaping any special chars.

How to use powershell to remove spaces from the beginning of a filename

I've been using the below to replace spaces in all the filenames and folders under the current directory location with underscores.
dir -Force -Recurse | Rename-Item -NewName {$_.name -replace " ","_"}
How do I specify to only replace spaces if they are at the the beginning of the filename, eg the first character?
Get-ChildItem -Force -Recurse | Rename-Item -NewName ($_.Name -replace "^ ","_")
Your post title doesn't quite line up with what you're asking.
There's also a syntax error in your example code (you're missing the period when trying to access the Name property of the PSItem $_).
None the less I hope this is what you're looking for. You were mostly there. The first parameter of -replace interprets regex.

How to recursively append to file name in powershell?

I have multiple .txt files in folders/their sub-folders.
I want to append _old to their file names.
I tried:
Get-ChildItem -Recurse | Rename-Item -NewName {$_.name -replace '.txt','_old.txt' }
This results in:
Some files get updated correctly
Some files get updated incorrectly - they get _old twice - example: .._old_old.txt
There are few errors: Rename-Item : Source and destination path must be different.
To prevent already renamed files from accidentally reentering the file enumeration and therefore getting renamed multiple times, enclose your Get-ChildItem call in (), the grouping operator, which ensures that all output is collected first[1], before sending the results through the pipeline:
(Get-ChildItem -Recurse) |
Rename-Item -NewName { $_.name -replace '\.txt$', '_old.txt' }
Note that I've used \.txt$ as the regex[2], so as to ensure that only a literal . (\.) followed by string txt at the end ($) of the file name is matched, so as to prevent false positives (e.g., a file named Atxt.csv or even a directory named AtxtB would accidentally match your original regex).
Note: The need to collect all Get-ChildItem output first arises from how the PowerShell pipeline fundamentally works: objects are (by default) sent to the pipeline one by one, and processed by a receiving command as they're being received. This means that, without (...) around Get-ChildItem, Rename-Item starts renaming files before Get-ChildItem has finished enumerating files, which causes problems. See this answer for more information about how the PowerShell pipeline works.
Tip of the hat to Matthew for suggesting inclusion of this information.
However, I suggest optimizing your command as follows:
(Get-ChildItem -Recurse -File -Filter *.txt) |
Rename-Item -NewName { $_.BaseName + '_old' + $_.Extension }
-File limits the the output to files (doesn't also return directories).
-Filter is the fastest way to limit results to a given wildcard pattern.
$_.BaseName + '_old' + $_.Extension uses simple string concatenation via the sub-components of a file name.
An alternative is to stick with -replace:
$_.Name -replace '\.[^.]+$', '_old$&'
Note that if you wanted to run this repeatedly and needed to exclude files renamed in a previous run, add -Exclude *_old.txt to the Get-ChildItem call.
[1] Due to a change in how Get-ChildItem is implemented in PowerShell [Core] 6+ (it now internally sorts the results, which invariably requires collecting them all first), the (...) enclosure is no longer strictly necessary, but this could be considered an implementation detail, so for conceptual clarity it's better to continue to use (...).
[2] PowerShell's -replace operator operates on regexes (regular expressions); it doesn't perform literal substring searches the way that the [string] type's .Replace() method does.
The below command will return ALL files from the current folder and sub-folders within the current directory the command is executed from.
Get-ChildItem -Recurse
Because of this you are also re-turning all the files you have already updated to have the _old suffix.
What you need to do is use the -Include -Exclude paramters of the Get-Childitem Cmdlet in order to ignore files that already have the _old suffix, and meet your include criteria, for example.
Get-ChildItem -Recure -Include "*.txt" -Exclude "*_old"
Then pipe the results into your re-name item command
Get-ChildItem cmdlet explanation can be found here.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-7

powershell to bulk remove certain character(s) from many filenames within multiple subfolders

I've researched this issue and have perused the knowledge base here. I did find a few topics that dabbled in removing certain characters in a file/folder name via PowerShell. Unfortunately, trying to do the below cmdlet resulted in the following error.
cmd: Get-Item * | ForEach-Object {Rename-Item $_ ($_.Name -replace "%", "")}
error: rename-item: Source and destination path must be different
There are many thousands of files. I'm trying to remove % and # symbols from any and all filenames within many subfolders.
Example: Before
FileName%1%#1.doc
after
FileName11.doc
Don't use cmd but powershell. Here is the correct syntax from your example:)
Get-Item * | ForEach-Object {Rename-Item $_ -NewName ($_.name -replace '#','' -replace '%','')}

rename multiple files using substring of the filename

I have 100's of file in windows with names like
W-cat_T_1001_s.jpg
W-dog_T_12112_o.jpg
W-rabbit_T_121_w.jpg
i want to rename all the files to its substring for example
cat.jpg
dog.jpg
rabbit.jpg
My approach was to first replace "_T_*" with "" in powerShell something like
DIR| Rename-Item -NewName {$_.Name -replace "_T_*", ""}
this gives error
Rename-Item : Cannot rename because item at 'z' does not exist
i don't know whether it was a right approach and whether it is good to use PowerShell, batch file, java or simple "rename" command will do.
dir | Rename-Item -NewName {$_.Name -replace 'W-(.*)_T_.*','$1.jpg'}