PowerShell is a powerful tool for every windows power user. I need an easy way to rename all images within a project.
If we run the final code at the end, it will rename all image files in all sub folders. Their names will be the same as its directories with an incremented number as a prefix which reset in every new folder. For example, if the folder named New-Folder
contains 3 images the script will rename them as:
01-New-Folder.jpg
02-New-Folder.jpg
03-New-Folder.jpg
First, we need to open Notepad or other editor and save the empty file with PowerShell .ps1
extension for example create a file called run.ps1
. If you open PowerShell terminal and run a script, you will get the following message:
PS C:\> .\run.ps1
.\run.ps1 : File C:\run.ps1 cannot be loaded because running scripts is disabled on this system.
For more information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:1
+ .\run.ps1
+ ~~~~~~~~~
+ CategoryInfo : SecurityError: (:) [], PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess
It’s a good thing though because PowerShell scripts are a powerful and dangerous thing and it can be malicious.
TIP: Never run a PowerShell script without knowing what is every single thing otherwise you can end up with missing files, a broken system or worst. That is why I will explain you everything line by line.
We will need to declare some initial variables and constants:
$path = "project\\test"
$fileTypes = ".*.jpg|.*.bmp|.*.png|.*.gif|.*.tif"
$files = Get-ChildItem -Recurse | Where-Object FullName -Match ".*$path*"
$counter = 1
$dir = ""
$path
will be the relative path from where we will want to manipulate data. In our case we put the file in a project
folder and we want to do everything only in the sub folder test
and its sub folders.
$fileTypes
will be a RegEx (Regular expression) getting all images that have an extension of .jpg
, .bmp
, .png
, .gif
or .tif
. You can add or change to whatever valid RegEx you want.
$files
is a little more complex:
- Get-ChildItem will get all files in a folder and the parameter
-Recurse
will loop through all sub folders. - Pipeline (|) is an operator which will pass one by one all objects from the left side to the command on the right.
- Where-Object will be our filter. First, I'm getting
FullName
because it is a string containing the full path and the filename. Having this data and with the help of the RegEx we are matching$path
withFullName
.
Now we can say that $files
is a collection or an array of all files in the folders we want. To start rename images, we will loop through them with foreach ($file in $files) { }
.
Within the loop we need the filename as $name
the full path (including the filename and the extension) as $fullname
and the file type as $extension
.
Now we need a conditional which match the looped file and the $fileTypes
. This is the if block if ($name -Match $fileTypes)
and -Match
is the RegEx parameter.
Next, we need to reset our $counter
on every new folder. We do that with another if block which test if $dir
is not equal (-nq
). If it is true the $dir
will get the current name and will reset the $counter
.
We also want our counter to be in double digit format. With $zero
we will cover this case. We are using ternary operator which test if $counter
is less or equal to 9 and if true will be equal to string "0".
The next line is the actual file renaming. The Rename-Item
is the command and in our case it takes $fullname
which is the full path with the filename and the new name - "$zero$counter-$dir$extension"
. The new name is the combination of the counter with 2-digit format and the folder name with extension.
Finaly, we will increment $counter
.
I tried to cover most of the common cases to have a good base from which to expand and improve to all your needs. You can run and change the script but always test it in a demo folder, because there is no undo button.
Final code
$path = "project\\test"
$fileTypes = ".*.jpg|.*.bmp|.*.png|.*.gif|.*.tif"
$files = Get-ChildItem -Recurse | Where-Object FullName -Match ".*$path*"
$counter = 1
$dir = ""
foreach ($file in $files) {
$name = $file.Name
$fullname = $file.FullName
$extension = $file.Extension
if ($name -Match $fileTypes) {
if ($dir -ne $file.Directory.Name) {
$dir = $file.Directory.Name
$counter = 1
}
$zero = If ( $counter -le 9) { "0" } Else { "" }
Rename-Item $fullname "$zero$counter-$dir$extension"
$counter++
}
}