Renaming multiple files with different names - powershell

I am a programmer by no means and am brand new to using powershell, but have been tasked with setting up some batch export processes for daily files we FTP. I need to come up with a script that will take changing file names and change them within the same directory to new names;
Example: files will come in as below (YYYYMMDD will be the changing variable)
YYYYMMDD_Share_Support.txt
YYYYMMDD_Person_Support.txt
We need them to be stripped from the above to:
Share.txt
Person.txt
so on and so forth.
I have found ways to make this work, but only on an as needed basis for one file at a time with specific names, not names that will change daily.
So far I am using:
Get-ChildItem -Filter *.txt
Dir | %{Rename-Item $_ -NewName ("NEWFILENAME.txt" -f $nr++)}

You could use the regex -replace operator inside a pipeline-bound scriptblock:
$files = Get-ChildItem -filter *.txt
$files |Rename-Item -NewName { $_.Name -replace '^\d{8}_(.*)_Support\.txt$', '$1.txt' }
As suggested by TheIncorrigible1, if you know the relative position of the word you need, you can also use -split:
$files |Rename-Item -NewName {'{0}.txt' -f ($_.Name -split '_')[-2]} # grab 2nd last word

How about:
dir *.txt |
rename-item -newname { $null,$base,$null = $_.basename -split '_'; "$base.txt" } -whatif

Probably a longer version of the answer. An alternative mentioned by #TheIncorrigible1
$logDir = "D:\Satish\TestFolders"
cd $logDir
$files = ls
foreach ($file in $files){
$fileSplit=($file.ToString()).split("_")
ren $file "$($fileSplit[1]).txt"
}
And for Share.txt to YYYYMMDD_Share_Support.txt
$logDir = "D:\Satish\TestFolders"
cd $logDir
$files = ls
$date = Get-Date -Format "yyyyMMdd"
foreach ($file in $files){
$fileSplit=($file.ToString()).split(".")
ren $file "$($date)_$($fileSplit[0])_Support.txt"
}

Related

replacing files names with split output

I am trying to use PowerShell to read filenames from a dir;
then within a for loop:
split names using a delimiter; store desired output in a new variable. Now I want to replace the original filenames in the directory with this new variable. So far I have gathered the following with the expected outputs shown:
$files = Get-ChildItem -Path C:\Test
write-output $files
Directory: C:\Test
1_N04532L_LEFT.JPG
2_N04532R_RIGHT.JPG
code continues
foreach ($file in $files)
{
$nameArray = $file -split "_"
$newName = $nameArray[1]
write-output $newName
}
N04532L
N04532R
Any Ideas on how to accomplish this. I am not a programmer and there is lots of data on this, but it's not working for me.
As both commenters already explained, there is the Rename-Item cmdlet for renaming files.
Since this cmdlet can take a scriptblock in its NewName parameter, you can use that to create a new filename.
# adding switch -File makes sure you do not also try to rename subfolders
$files = Get-ChildItem -Path 'C:\Test' -File
foreach ($file in $files) {
$file | Rename-Item -NewName { '{0}{1}' -f ($file.BaseName -split '_')[1], $file.Extension }
}
You can shorten this by piping the results from Get-ChildItem trhough one-by-one to the Rename-Item cmdlet.
Because we're piping the FileInfo objects here, we can make use of the $_ automatic variable
# enclose the Get-ChildItem cmd in brackets so this will enumerate the files to completion
# before passing them on to te Rename-Item cmdlet.
# if you don't, files you already have renamed could be picked up and processed again..
(Get-ChildItem -Path 'C:\Test' -File) |
Rename-Item -NewName { '{0}{1}' -f ($_.BaseName -split '_')[1], $_.Extension }
Note: when renaming files, you can always run into naming collisions, upon which you will receive an exception

Can't Move-Item Modified file

I was trying to follow the solution given by #StephenP in this post:
Renaming and Moving Files Powershell
I am trying to Move a renamed file to the Output Folder, but it didn't move.
What could go wrong?
Here's my code:
$Files = GCI "$ParentFolder" | ?{$_.Extension -Match "png?"}
$Date = Get-Date -Format "yyyymmddhhmmss"
$Dest = ".\Output"
$Files | ForEach-Object {
# Get the File BaseName and Select the Screen Title only
$FileName = $_.BaseName
$NameCount = $FileName.length
$ScreenTitle = $FileName.substring(0,$NameCount -21)
# Set the New File Name as Variable
$NewFileName = "$($Date)_[$($ScreenTitle)]"
# Start Renaming
$GetName = $_.FullName -replace "$FileName","$NewFileName"
Rename-Item $_ $GetName
# Move the renamed file
Move-Item $GetName -Destination $Dest
}
Thank you for helping :)
First of all, you don't need to rename the file first and then move, because you can do this using Move-Item at the same time.
Use -Filter '*.png' instead of a Where-Object afterwards. The Filter is much more efficient.
Your code does not check if the length of the file BaseName is actually more than 21 characters long, so this $FileName.Substring(0, $NameCount -21) can throw exceptions. However, since you didn't provide any filename examples, I left that in.
Try
$Files = Get-ChildItem -Path $ParentFolder -Filter '*.png' -File
$Date = Get-Date -Format "yyyymmddhhmmss"
$Dest = ".\Output"
$Files | ForEach-Object {
# Get the File BaseName and Select the Screen Title only
$FileName = $_.BaseName
$NameCount = $FileName.Length
# very tricky this.. could throw error if $FileName is less than 21 characters..
$ScreenTitle = $FileName.Substring(0, $NameCount -21)
# Set the New File Name as Variable
$NewFileName = '{0}_[{1}]{2}' -f $Date, $ScreenTitle, $_.Extension
# Move the file with a new name to the destination
$_ | Move-Item -Destination (Join-Path -Path $Dest -ChildPath $NewFileName)
}
As aside, using square brackets in filenames could cause you problems and to do more PowerShell on these files, you need to always remember to use -LiteralPath instead of -Path on cmdlets that support it like Get-ChildItem

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

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
}