Add counter as suffix to all files in subfolders - powershell

I have this problem with renaming 50,000 files, separated to numerous folders. the problem is that the original sequential naming is all massed up because some file were deleted, so the count jumps from let's say *0005 to *0007.
I want to rename all the files in all subfolders, so that the suffix will be a 4 digit number, based on the current order of the files. Most importantly I want the counter the restart in each folder.
I have one working script that renames the files according putting a general name and then the folder name and last the current file name.
Get-ChildItem C:\test -Filter *.tif -Recurse | Rename-Item -NewName { 'IL-TRUM'+'_'+$_.Directory.Name+'_'+$_.name}
All I need to do is to add another counter at the end!

If you want the counter to restart in each folder you need to separate folder recursion from enumerating/renaming the TIFF files in each folder. Try something like this:
Get-ChildItem -LiteralPath 'C:\test' -Recurse | Where-Object {
$_.PSIsContainer
} | ForEach-Object {
$cnt = 0
Get-ChildItem -LiteralPath $_.FullName -Filter '*.tif' | ForEach-Object {
Rename-Item -LiteralPath $_.FullName -NewName ("IL-TRUM_{0}_{1}_{2:d4}{3}" -f $_.Directory.Name, $_.Name, $cnt, $_.Extension)
$cnt++
}
}

Related

Exclude Subfolders and Their Parent Folder from a Function

I have a script that is designed to do three things:
Convert all .webp files to .jpg from the main "Test" and all its differently-titled subfolders.
For each directory, make a sub directory called "Ch1" within.
Move all the files into the "Ch1" folder
The script currently looks like this, and works fine for single-titled folders with only .webp or .jpg files in each:
cd D:\TestingGrounds\Test
get-childItem -recurse | Where {$_.extension -eq ".webp"} | rename-item -newname {$_.name -replace ".webp",".jpg"}
$dirs = Get-ChildItem -force D:\TestingGrounds\Test
foreach ($dir in $dirs) {mkdir D:\TestingGrounds\Test\$dir\ch_1; move D:\TestingGrounds\Test\$dir\* D:\TestingGrounds\Test\$dir\ch_1}
I now have multi-chapter folders that already have subfolders with .webp and .jpg files inside pre-made chapter folders, such as "Ch1", "Ch1.5", "Ch2", etc.
I cannot figure out a way to add an exception or exclusion to these multi-chapter folders where they are not touched by the mkdir and move portions, only all .webp files to still be renamed to .jpg
I'm not very familiar with Powershell, much less exception commands. I've tried -notcontains, Where-Object, and making another designator, like $multi = 'Ch*' to be ignored. So far, nothing has worked. It will continue to make a "Ch1" in the multi-chapter subfolders except for the original "Ch1", and move their respective files into them... basically what the original script did. Attached are photos of what I'm trying to do.
1 Before 2 Desired Outcome
Here are some of my attempts:
$dirs = Get-ChildItem -force 'D:\TestingGrounds\Test';
$Multi = 'Ch*';
get-childItem -recurse | Where {$_.extension -eq ".webp"} | rename-item -newname {$_.name -replace ".webp",".jpg"};
if ($folder -notcontains 'Ch*') {mkdir D:\TestingGrounds\Test\$folder\Ch1; move D:\TestingGrounds\Test\$folder\* D:\TestingGrounds\Test\$folder\Ch1}
{mkdir D:\TestingGrounds\Test\$folder\Ch1; move D:\TestingGrounds\Test\$folder\* D:\TestingGrounds\Test\$folder\Ch1} | Where {D:\Testing Grounds\Test\$dir\ -notcontains 'Ch*'}
gci "D:\TestingGrounds\Test" | Where-Object {$_.FullName -notlike "Ch*"} | mkdir D:\TestingGrounds\Test\$dir\Ch1; move D:\TestingGrounds\Test\$dir\Ch1\* D:\TestingGrounds\Test\$dir\Ch1; move D:\TestingGrounds\Test\$dir\Ch1 D:\TestingGrounds\Test\$dir
$dirs = Get-ChildItem -force D:\TestingGrounds\Test; $Multi = 'Ch*'; get-childItem -recurse | Where {$_.extension -eq ".webp"} | rename-item -newname {$_.name -replace ".webp",".jpg"}; if ($dir -notcontains $Multi) {mkdir D:\Testing Grounds\Test\$dir\Ch1; move D:\Testing Grounds\Test\$dir\* D:\Testing Grounds\Test\$dir\Ch1}
Edited to reflect clarification in the question:
This will get all of the .webp files in a given directory, move them to a Chapter folder (and create it if needed), or just rename them to .jpg if the file is in the right place.
#Get all WEBP files in the source folder
$sourcefolder = "C:\Test"
$files = Get-ChildItem $sourcefolder -Recurse -Filter *.webp
$chapter = "Ch1"
#Loop through each of the files
Foreach($f in $files)
{
$newname = $f.Name -replace ".webp",".jpg"
$directory = $f.DirectoryName
#Case insensitive RegEx to see if the file is already in a chapter folder, rename the file.
if($f.DirectoryName -imatch ".*\\ch\d+")
{
Rename-Item $f.FullName -NewName $newname
}
#Chapter folder NOT exists, and, File is NOT in chapter folder. Otherwise we'll create sub chapter folders
If((!(Test-Path "$directory\$chapter")) -and($f.DirectoryName -inotmatch ".*\\ch\d+"))
{
New-Item -Path "$directory\$chapter" -ItemType Directory
}
#Chapter folder EXISTS and File is NOT in chapter folder. We can now move it where it needs to be
If((Test-Path "$directory\$chapter") -and ($f.DirectoryName -inotmatch ".*\\ch\d+"))
{
Move-Item $f.FullName -Destination "$directory\$chapter\$newname"
}
}

Removing parts of filenames in Powershell from a file list

I have a bunch of directories with files in them and my goal is to loop through a directory structure and write each of the files one by one to a new location.
The files on disk look like this:
- DATAFILE1_DATE_20210101_RUNDATE_20210101.csv
- DATAFILE1_DATE_20210102_RUNDATE_20210102.csv
- DATEFILE2_DATE_20210103_RUNDATE_20210103.json
- DATEFILE2_DATE_20210104_RUNDATE_20210104.json
I'm trying to pass the contents of the directory to a variable $fileSystemItems and then to remove everything after _DATE so that I could build a new directory structure in the target as:
- /target/DATAFILE1/DATAFILE1_DATE_20210101_RUNDATE_20210101.csv
- /target/DATAFILE1/DATAFILE1_DATE_20210102_RUNDATE_20210102.csv
- /target/DATAFILE2/DATEFILE2_DATE_20210103_RUNDATE_20210103.json
- /target/DATAFILE2/DATEFILE2_DATE_20210104_RUNDATE_20210104.json
The PS code I have so far takes the files from a specified directory and outputs them:
$sourcePath = "\\files\data"
$fileSystemItems = Get-ChildItem $sourcePath -Recurse | Where { ! $_.PSIsContainer }
foreach ($file in $fileSystemItems) {
Write-Host "Writing name of the file is $($file.BaseName)"
}
I have tried using the Rename-Item and regex but renaming the files the source is not an option as other programs are accessing the same data, for example:
Get-ChildItem $sourcePath -Recurse | Rename-Item -NewName { $_.Name -replace "^_DATE+","" }
How do I modify the filename in the $file variable in the foreach loop to output both a edited version of the file name (e.g. DATEFILE1) and also the full file name DATAFILE1_DATE_20210101_RUNDATE_20210101.csv ?
Rename-Item is a great tool to begin with! First, let's optimize your code snippet a little bit:
Instead of piping Get-ChildItems output to Where { ! $_.PSIsContainer }, we'll use the -File switch.
Let's also change your regex from ^_DATE+ to _DATE.* and use a pipeline with ForEach-Object:
Get-ChildItem $sourcePath -Recurse -File | ForEach-Object {
Rename-Item -Path $_.Fullname -NewName (($_.Name -replace "_DATE.*","") + $_.Extension)
}
Looking at your destination structure it looks like you might also want to move files to a target directory.

Rename files in subfolders

I am trying to rename files in subfolders in a certain pattern, but I am stuck.
The situation is as follows: I have multiple folders which are sometimes named as the target filename depending on the length, but the name does not really matter.
In each folder are always 2 files: the Target-File with a random name and the correct extension, and the Source-File which is always the correct BaseName with a txt-extension.
For example:
Folder1\7393028473.docx
Folder1\January.txt
Folder2\9373930843.pdf
Folder2\February.txt
My goal is to rename every not-txt-file with the Basename of the txt-file. Executed, it should be like:
Folder1\January.docx
Folder1\January.txt
Folder2\February.pdf
Folder2\February.txt
With gci I was able to create both lists but didn't find a good way for the renaming.
$SourceName = gci -File -Recurse | Where {$_.Extension -ne ".txt"}
$TargetName = gci -File -Recurse | Where {$_.Extension -eq ".txt"}
I did also try to use gci for renaming, but was not able to tell it to use the newname based on the txt-file:
gci -File -Recurse | Where {$_.Extension -ne ".txt"} | Rename-Item -NewName {$_.extension -eq ".txt"}
This only renamed the .docx-file to "FALSE" because the filename already exists.
What I did not try (but would be ok) is to not only rename the file, but also move it to the parent directory.
This is one way to do it but it would fail as soon as there are 2 or more files with a different extension than .txt but having the same extension. It would also fail as soon as one folder has more than one .txt file.
# Get all folders under 'TargetDirectory'
Get-ChildItem TargetDirectory -Directory -Recurse | ForEach-Object {
# For each sub-folder, get their files
$childs = $_.EnumerateFiles()
# Filter and split the child files by their extension
$txt, $notTxt = $childs.Where({ $_.Extension -eq '.txt' }, 'Split')
# Use the BaseName of the '.txt' File but the Extension of
# the file being renamed
$notTxt | Rename-Item -NewName { $txt.BaseName + $_.Extension }
}
Thanks for your reply and sorry for my late reply.
I tried your code but its not working correctly:
The NewName is created correctly, but the problem is the rename-function or rather the notTxt list because it only contains the item itself but not hte full path.
When I copy the file which should be renamed into the parent-directory your code does work in the file in the parent-directory.
There was another answer which apperntly was deleted but did work.
I also tried a foreach-loop in one of my tries but didn't get the NewName to work.
I don't know why, but I didn't consider creating the NewName with a variable, which was done in the deleted answer:
$folders = gci -Directory -Recurse
foreach ($folder in $folders) {
$targetFile = gci $folder | Where {$_.Extension -ne ".txt"}
$sourceFile = gci $folder | Where {$_.Extension -eq ".txt"}
$newName = $sourceFile.BaseName + $targetFile.Extension
Rename-Item $targetFile.FullName $newName
}
Of course you can try and get your code to work, but I can make do with this code.
Thank you very much for your help.

Windows 10, Rename all *.jpg files in all subdirectories, with number starting from 1

I want a solution for the same problem, but in Windows 10.
Recursively rename .jpg files in all subdirectories
I tried with following powershell command,
Get-ChildItem -Recurse -Include *.jpg | % { Rename-Item $_ -NewName ('{0:D1}.jpg' -f $i++)}
but it renames the files in sequential order without resetting the index to 1 in every sub folder.
I think you need two separate Get-ChildItem cmdlets for this. The first will gather all subdirectories and when looping though that, the second will gather the files in each directory:
Get-ChildItem -Path 'X:\RootFolder\where\the\files\are' -Recurse -Directory | ForEach-Object {
$count = 1 # reset the counter for this subdir to 1
Get-ChildItem -Path $_.FullName -Filter '*.jpg' -File | ForEach-Object {
$_ | Rename-Item -NewName ('{0:D1}.jpg' -f $count++) -WhatIf
}
}
Remove the -WhatIf if you are satisfied with the results shown in the console.
P.S. the title says *.png, but your code deals with *.jpg. Doesn't matter, as long as you set your filter to the correct extension and adjust the new name in the code accordingly
As of my knowledge you have to do use it as a nested foreach:
Foreach ($directory in (Get-ChildItem -Directory)){
$i = 1
Get-ChildItem $directory.Fullname -Recurse -Include *.jpg | % { Rename-Item $_ -NewName ('{0:D1}.jpg' -f $i++)}
}
I tested it and it worked :)
If it worked for you, please mark it as the accepted answer.

Rename file using Powershell and create subfolders

I have 10K documents in a directory with this type of naming convention:
1050_14447_Letter Extension.pdf, 1333_14444_Letter.docx, etc...
I tried using this script to remove all characters before the 2nd underscore (including the 2nd underscore):
Get-ChildItem -Filter *.pdf | Rename-Item -NewName {$_.Name -replace '^[0-9_]+'}
This worked, but revealed there would be duplicate file names.
Wondering if there is some way a script can create a subfolder based on the filename (minus the extension)? So there would be 10K subfolders in my main folder. Each subfolder would just have the one file.
This should work. It creates a new folder for each item, then moves it, renaming it in the process.
gci | ? {!$_.PSIsContainer} | % {New-Item ".\$($_.BaseName)" -Type Directory; Move-Item $_ ".\$($_.BaseName)\$($_.Name -replace '^[0-9_]+')"}
Note that if there are two files with the same name, but different extensions, you'll see an error when trying to create the directory, but both files will wind up in the same folder.
Alternately, if you want something more readable to save in a script, this is functionally identical:
$files = Get-ChildItem | Where-Object {!$_.PSIsContainer}
foreach ($file in $files)
{
$pathName = ".\" + $file.BaseName
New-Item $pathName -Type Directory
$newFileName = $pathName + "\" + ($file.Name -replace '^[0-9_]+')
Move-Item $file $newFileName
}