PowerShell bulk replacing a specific character and rename file extension - powershell

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
}

Related

If testfile1.log exists, create testfile2.log, and so on.. - PowerShell

My PowerShell script creates a log file, but when I run the script for the second time, it tells me that the testfile1.log file already exists.
How do I make the script if it finds testfile1.log, it creates testfile2.log, and if this also exists, it creates testfile3.log, and so on..
New-Item -Path $path -Name "testfile1.log" -ItemType "file"
You could do it this way, first get all the files in the desired path and sort them by the ending digits on their name. If no files are found create the testfile1.log, if there were files found, get the last sorted file (the one with the highest ending digit) extract the ending digits and add +1 to the count and use it to create the new file.
$files = Get-ChildItem $path -Filter testfile*.log | Sort-Object {
$_.BaseName -replace '\D' -as [int]
}
if(-not $files)
{
New-Item -Path $path -Name "testfile1.log" -ItemType File
}
else
{
[int]$number = $files[-1].BaseName -replace '\D'
$number++
New-Item -Path $path -Name "testfile$number.log" -ItemType File
}
An alternative method, based on this answer could be
$path = 'D:\Test'
$log = 'testfile'
$index = ((Get-ChildItem -Path $path -Filter "$log*.log" -File |
Where-Object { $_.BaseName -match "$log\d+$" } |
Select-Object #{Name = 'index'; Expression = {[int]($_.BaseName -replace '\D')}}).index |
Measure-Object -Maximum).Maximum + 1
# create the new file
New-Item -Path (Join-Path -Path $path -ChildPath "$log${index}.log") -ItemType File
A concise solution that also builds on this answer (see there for an explanation of the core technique):
$path = '.' # Output dir.
$nameTemplate = 'testfile{0}.log' # {0} is the sequence-number placeholder
New-Item -ItemType File -Path $path -Name (
$nameTemplate -f (1 + (
# Find all existing log files
Get-ChildItem (Join-Path $path $nameTemplate.Replace('{0}', '*')) |
Measure-Object -Maximum {
# Extract the embedded sequence number.
$_.Name -replace [regex]::Escape($nameTemplate).Replace('\{0}', '(\d+)'), '$1'
}
).Maximum)
) -WhatIf
Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.
Note:
The above uses a complex -replace operation to reliably extract the sequence number from existing file names; if you know that that only one number is present in each given file name, $_.BaseName -replace '\D' (removing all non-digit characters) will do in the Measure-Object call above.
If you wanted to use zero-padded, fixed-width sequence numbers, you can adjust (all occurrences of) the {0} placeholder accordingly; e.g, to create sequence numbers 01, 02, ... 99, use {0:00} - see the Composite formatting help topic, which describes the string formatting language also used by PowerShell's -foperator

Renaming multiple files with different names

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"
}

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.