Rename files with Powershell, file name already exist - powershell

I try to rename in batch files in multiple folders by removing - .extension
Example files:
test file 1 - 1234.docx
test file 1 - 4321.docx
test file 1 - 6789.docx
For this I run the following script:
Get-ChildItem -recurse -exclude .dxl | foreach {
Rename-Item -Path $_.FullName -NewName (($_.BaseName -replace '(.)-.*?$','$1') + $_.Extension) }
This will give me the following error:
"Rename-Item : Cannot create a file when that file already exists."
How can I get rid of this by adding (1), (2), (3) if the file already exist after renaming?

Here is something I came up with for this problem:
$FileTracker = #{}
$files = (Get-ChildItem -recurse -exclude "*.dxl" -file | sort fullname).fullname
$files | foreach {
$Base = (($_ | select-string -pattern "(.*)-.*?$").matches.groups[1].value).Trim()
if ($FileTracker[$Base]) {
Rename-Item -path $_ -newName ((split-Path $Base -Leaf),"($($FileTracker[$Base]))",($_ -replace ".*(\..*?)$",'$1') -join "")
$FileTracker[$Base]++
}
else {
$FileTracker.add($Base,1)
Rename-Item -path $_ -newName ((split-path $Base -Leaf),($_ -replace ".*(\..*?)$",'$1') -join "")
}
}
Keep in mind that this solution looks to make files unique in their respective directories. If it sees test file 1 - 23.txt in two different directories, it will rename them both to test file 1.txt. If you already have files that have been renamed like testfile 1(1).txt and testfile 1(2).txt, there will be issues with this working. So I need to know if that is a condition.

Related

Is it possible to rename each file in a folder with a different name using powershell or a batch file?

I've tried looking this up but have got nowhere so far and I'm on a time limit.
Let's say I have three files that have similar clones in multiple folders:
(folder1)
image1.png
image2.png
image3.png
(folder2)
image1.png
image2.png
image3.png
I want to rename these using cmd prompt, powershell, or using a .bat to:
(folder1)
B-Sign.png
B-Gauge.png
B-Cup.png
(folder2)
G-Sign.png
G-Gauge.png
G-Cup.png
I intend to run the commands for each folder as only the front of the name is different. I want something simple.
rename-item *.png B-Sign.png
rename-item *.png B-Gauge.png
When it needs a different prefix I would just find and replace the prefix with the new one using ctrl+H in notepad.
Problem is I can't figure out, in any of these, how to automatically cycle to the next file in the folder instead of changing all of the files' names at once. Any one can help?
Yes that's very easy in PowerShell:
Get-ChildItem "C:\temp\Folder1" |
Rename-Item -NewName { "B-" + $_.Name }
The new name is a result of an Expression that Rename-Item knows to evaluate. Because the information is sent down the pipeline the Rename-Item command is run once per file, resulting in names like your example.
Also you can use the filter parameter as you described with either of the below:
Get-ChildItem "C:\temp\Folder1\*.png" |
Rename-Item -NewName { "B-" + $_.Name }
I prefer to filter using the -Filter parameter:
Get-ChildItem "C:\temp\Folder1" -Filter *.png |
Rename-Item -NewName { "B-" + $_.Name }
You can store the folder in a variable too:
$Folder = "C:\temp\Folder1"
Get-ChildItem $Folder -Filter *.png |
Rename-Item -NewName { "B-" + $_.Name }
Update:
Per comments here's an example to correlate a list of prefixes with the renames you want to do:
$Prefix = 'B-'
$NewNames =
#(
'Sign'
'Guage'
'Cup'
)
# If New names are stored ina file simply do:
# $NewNames = Get-Content <FilePath>
$Folder = "C:\temp\Test_10-30-20"
$Files = Get-ChildItem $Folder -Filter *.png
For( $i = 0; $i -lt $Files.Count; ++$i )
{
$CurrentFile = $Files[$i]
$NewName = $Prefix + $NewNames[$i] + $CurrentFile.Extension
Rename-Item $CurrentFile.FullName -NewName $NewName
}

PowerShell - Loop through files and rename

newbie here. I am trying to write a PowerShell script to:
loop through all files in directory
List item
Get all .pdf files ONLY
Rename them-the file names are long - over 30 chars
-They contain 2 numbers which I need to extract
-Example:
Cumulative Update 11 for Microsoft Dynamics NAV 2018 (Build 25480).pdf ->
RESULT : = 18CU11.pdf
I tried examples from bunch of sites and I can't seem to even loop successfully.
Either get an error - that path doesn't exist or that can't rename files as somehow loop gets a filepath and that I can't rename
Get-ChildItem "C:\Users\******\Desktop\PowerShell Practice" -Filter *.pdf | #create list of files
ForEach-Object{
$oldname = $_.FullName;
$newname = $_.FullName.Remove(0,17);
#$newname = $_.FullName.Insert(0,"CU")
Rename-Item $oldname $newname;
$oldname;
$newname; #for testing
}
That's just latest attempt, but any other ways of doing it will be fine - as long as it does the job.
Try this logic:
[string]$rootPathForFiles = Join-Path -Path $env:USERPROFILE -ChildPath 'Desktop\PowerShell Practice'
[string[]]$listOfFilesToRename = Get-ChildItem -Path $rootPathForFiles -Filter '*.PDF' | Select-Object -ExpandProperty FullName
$listOfFilesToRename | ForEach-Object {
#get the filename wihtout the directory
[string]$newName = Split-Path -Path $_ -Leaf
#use regex replace to apply the new format
$newName = $newName -replace '^Cumulative Update (\d+) .*NAV 20(\d+).*$', '$2CU$1.pdf' # Assumes a certain format; if the update doesn't match this expectation the original filename is maintained
#Perform the rename
Write-Verbose "Renaming '$_' to '$newName'" -Verbose #added the verbose switch here so you'll see the output without worrying about the verbose preference
Rename-Item -Path $_ -NewName $newName
}
Check the Help for Rename-Item. The Parameter -NewName requires the name of the file only, not the full path.
Try out this:
Get-ChildItem "C:\Users\******\Desktop\PowerShell Practice-Filter" -Filter *.pdf | #create list of files
ForEach-Object{
$oldname = $_.FullName
$newname = $_.Name.Remove(0,17)
Rename-Item -Path $oldname -NewName $newname
$oldname
$newname #for testing
}
Please try this
Get-ChildItem -Path "C:\Users\******\Desktop\PowerShell Practice-Filter" -Filter *.pdf | Rename-Item -NewName $newname

Cycle through sub-folders to rename files in Powershell

I have a file directory that contains many folders within it. Inside each of these sub-folders, I have a variety of files. I would like to go through each file, rename some of the items, and add extensions to some of them. I am using Powershell to do this.
I have file names with "." that all need to be replaced with "_" for example, "wrfprs_d02.03" should be "wrfprs_d02_03". I was able to successfully do that in one folder with the following code:
dir | rename-item -NewName {$_.name -replace "wrfprs_d02.","wrfprs_d02_"}
After, I make those replacements, I want to add .grb extensions on to some of the files, which all happen to start with "w", and I was able to do that within one folder with:
Get-ChildItem | Where-Object {$_.Name -match "^[w]"} | ren -new {$_.name + ".grb"}
When I step back from one folder and try to do it iteratively within many folders, my code doesn't work. I am in a directory called "Z:\Windows.Documents\My Documents\Test_data\extracted" which contains all my sub-folders that I want to iterate over. I am using the following code:
$fileDirectory = "Z:\Windows.Documents\My Documents\Test_data\extracted"
foreach($file in Get-ChildItem $fileDirectory)
{
dir | rename-item -NewName {$_.name -replace "wrfprs_d02.","wrfprs_d02_"}
Get-ChildItem | Where-Object {$_.Name -match "^[w]"} | ren -new {$_.name + ".grb"}
}
Any ideas on what my problem is?
because you $_ is replaced into loop when you use pipe. I propose you a new code:
$fileDirectory = "Z:\Windows.Documents\My Documents\Test_data\extracted"
Get-ChildItem $fileDirectory -recurse -file -filter "*.*" |
%{
#replace . by _
$NewName=$_.Name.Replace(".", "_")
#add extension grb if name start by w
if ($NewName -like "w*") {$NewName="$NewName.grb"}
#Add path file
$NewName=Join-Path -Path $_.directory -ChildPath $NewName
#$NewName
#rename
Rename-Item $_.FullName $NewName
}
Not sure what error you were getting, but using rename-item can be finicky. Or at least so in my experience.
I used the follow without issue. My files names were different so I replaced all periods with underscores. If the file starts with "W" then it changed the extension for that file.
$FilePath = Get-ChildItem "Z:\Windows.Documents\My Documents\Test_data\extracted" -Recurse -File
foreach ($file in $FilePath)
{
$newName = $file.Basename.replace(".","_")
$New = $newName + $file.Extension
if($file.Name -match "^[w]")
{
Rename-Item $file.FullName -NewName "$($New).grb"
}
else
{
Rename-Item $file.FullName -NewName $New
}
}
Hope that helps.

How do I remove Blank Space from File Names

I am trying to remove blank spaces from many file names using PowerShell 3.0. Here is the code that I am working with:
$Files = Get-ChildItem -Path "C:\PowershellTests\With_Space"
Copy-Item $Files.FullName -Destination C:\PowershellTests\Without_Space
Set-Location -Path C:\PowershellTests\Without_Space
Get-ChildItem *.txt | Rename-Item -NewName { $_.Name -replace ' ','' }
For example: the With_Space directory has these files:
Cable Report 3413109.pdf
Control List 3.txt
Test Result Phase 2.doc
The Without_Space directory will need the above file name to be:
CableReport3413109.pdf
ControlList3.txt
TestResultPhase 2.doc
Currently, the script shows no error but it only copies the source files to the destination folder, but doesn't remove the spaces in file names.
Your code should work just fine, but since Get-ChildItem *.txt lists only .txt files the last statement should remove the spaces from just the text files, giving you a result like this:
Cable Report 3413109.pdf
ControlList3.txt
Test Result Phase 2.doc
This should remove spaces from the names of all files in the folder:
Get-ChildItem -File | Rename-Item -NewName { $_.Name -replace ' ','' }
Prior to PowerShell v3 use this to restrict processing to just files:
Get-ChildItem | Where-Object { -not $_.PSIsContainer } |
Rename-Item -NewName { $_.Name -replace ' ','' }
something like this could work
$source = 'C:\temp\new'
$dest = 'C:\temp\new1'
Get-ChildItem $source | % {copy $_.FullName $(join-path $dest ($_.name -replace ' '))}
I think your script should almost work, except $_ isn't going to be defined as anything. By using the for-each cmdlet (%), you assign it and then can use it.
Get-ChildItem *.txt | %{Rename-Item -NewName ( $_.Name -replace ' ','' )}
EDIT:
That interpretation was totally wrong. Some people seem to have found it useful, but as soon as you have something being piped, it appears that $_ references the object currently in the pipe. My bad.

Rename files to lowercase in Powershell

I am trying to rename a bunch of files recursively using Powershell 2.0. The directory structure looks like this:
Leaflets
+ HTML
- File1
- File2
...
+ HTMLICONS
+ IMAGES
- Image1
- Image2
- File1
- File2
...
+ RTF
- File1
- File2
...
+ SGML
- File1
- File2
...
I am using the following command:
get-childitem Leaflets -recurse | rename -newname { $_.name.ToLower() }
and it seems to rename the files, but complains about the subdirectories:
Rename-Item : Source and destination path must be different.
I reload the data monthly using robocopy, but the directories do not change, so I can rename them by hand. Is there any way to get get-children to skip the subdirectories (like find Leaflets -type f ...)?
Thanks.
UPDATE: It appears that the problem is with files that are already all lower case. I tried changing the command to:
get-childitem Leaflets -recurse | if ($_.name -ne $_name.ToLower()) rename -newname { $_.name.ToLower() }
but now Powershell complains that if is not a cmdlet, function, etc.
Can I pipe the output of get-childitem to an if statement?
UPDATE 2: This works:
$files=get-childitem Leaflets -recurse
foreach ($file in $files)
{
if ($file.name -ne $file.name.ToLower())
{
rename -newname { $_.name.ToLower() }
}
}
Even though you have already posted your own answer, here is a variation:
dir Leaflets -r | % { if ($_.Name -cne $_.Name.ToLower()) { ren $_.FullName $_.Name.ToLower() } }
Some points:
dir is an alias for Get-ChildItem (and -r is short for -Recurse).
% is an alias for ForEach-Object.
-cne is a case-sensitive comparison. -ne ignores case differences.
$_ is how you reference the current item in the ForEach-Object loop.
ren is an alias for Rename-Item.
FullName is probably preferred as it ensures you will be touching the right file.
If you wanted to excludes directories from being renamed, you could include something like:
if ((! $_.IsPsContainer) -and $_.Name -cne $_.Name.ToLower()) { ... }
Hopefully this is helpful in continuing to learn and explore PowerShell.
Keep in mind that you can pipe directly to Rename-Item and use Scriptblocks with the -NewName parameter (because it also accepts pipeline input) to simplify this task:
Get-ChildItem -r | Where {!$_.PSIsContainer} |
Rename-Item -NewName {$_.FullName.ToLower()}
and with aliases:
gci -r | ?{!$_.PSIsContainer} | rni -New {$_.FullName.ToLower()}
There are many issues with the previous given answers due to the nature of how Rename-Item, Piping, Looping and the Windows Filesystem works. Unfortunatly the the most simple (not using aliases for readability here) solution I found to rename all files and folders inside of a given folder to lower-case is this one:
Get-ChildItem -Path "/Path/To/You/Folder" -Recurse | Where{ $_.Name -cne $_.Name.ToLower() } | ForEach-Object { $tn="$($_.Name)-temp"; $tfn="$($_.FullName)-temp"; $nn=$_.Name.ToLower(); Rename-Item -Path $_.FullName -NewName $tn; Rename-Item -Path $tfn -NewName $nn -Force; Write-Host "New Name: $($nn)";}
slight tweak on this, if you only want to update the names of files of a particular type try this:
get-childitem *.jpg | foreach { if ($_.Name -cne $_.Name.ToLower()) { ren $_.FullName $_.Name.ToLower() } }
this will only lowercase the jpg files within your folder and ignore the rest
You need to temporarily rename them to something else then name them back all lower case.
$items = get-childitem -Directory -Recurse
foreach ($item in $items)
{
if ($item.name -eq $item.name.ToLower())
{
$temp = $item.FullName.ToLower() + "_"
$name = $item.FullName.ToLower()
ren $name $temp
ren $temp $name
}
It's more idomatic in PowerShell to use where instead of if in a pipeline:
gci -Recurse Leaflets |
? { $_.Name -ne $_.Name.ToLower()) } |
% { ren -NewName $_.Name.ToLower() }
A small but important correction to the answer from Jay Bazuzi. The -cne (case sensitive not equal) operator must be used if the where-part should return anything.
Additionally I found that the Path parameter needed to be present. This version worked in my setup:
gci -Recurse |
? { $_.Name -cne $_.Name.ToLower() } |
% { ren $_.Name -NewName $_.Name.Tolower() }
for everyone who is following this thread; the following line can also be used to lower both files and directories.
Get-ChildItem -r | Rename-Item -NewName { $_.Name.ToLower().Insert(0,'_') } -PassThru | Rename-Item -NewName { $_.Name.Substring(1) }
Main post: https://stackoverflow.com/a/70559621/4165074