I have a powershell script (triggered by automation software). It effectively renames files by the directory, followed by an underscore, leading zero and sequential numbering.
$i = 0
$folder = Any-path
Get-ChildItem -Path $folder |ForEach-Object
{$extension = $_.Extension
$newName = $_.Directory.Name + '_{0:d3}{1}' -f $i, $extension
$i++
Rename-Item -Path $_.FullName -NewName $newName}
The problem is it renames every file in the directory, every time the script is triggered, which is inefficient.
I only want to rename files that don't fit the naming scheme (FolderName_01.ext), and rename the anomalies by the order they were added, continuing from the apex.
So
- FolderName_01
- FolderName_02
- FolderName_03
- Anomaly1-Latest
- Anomaly2-Earliest
Would become
FolderName_01 through FolderName_05 , with Anomaly2 renamed to FolderName_04, because it was created sooner.
I know that I can use
Get-ItemProperty '$filename' | select CreationTime
to see the dates for each file, but my brain starts to fry, as I try figuring out how to use that info to rename the files, by date created, picking up from the last properly named file.
I definitely appreciate any help!
I did a lot of work on this. I got help and did a lot of reading. This solution is probably rough in some areas, but it does the job and can run in the background to perform actions automatically - with one caveat: the Powershell console must be left open.
I haven't figured out how to make this a permanent WMI event binding.
Solution:
#REQUIRES -Version 4.0
#This is a string of folders you'd like to monitor
$Monitored = 'C:\Users\Me\Desktop\Pic Test\Tom Hiddleston', 'C:\Users\Me\Desktop\Pic Test\Kate Bosworth'
#This part is selecting the folder paths to be processed indvidually
$MatchPath = @($Monitored | Where-Object { Test-Path -Path $_ } | ForEach-Object {
$Path = $_;
$Watcher = New-Object System.IO.FileSystemWatcher -Property @{
Path = $Path;
Filter = '*.*';
IncludeSubdirectories = $True;
NotifyFilter = [System.IO.NotifyFilters]'FileName, LastWrite'}
#This may be unnecessary, but it's there to add the folder name to the -#SourceIdentifier, which makes the automation easier to shut down.
$ID = Split-Path $Path -Leaf
#Here it's important that the variable have the same name as the delete section, because it passes to the New-Object creation at the bottom.
#In this case, four events will be created. Two folders x two actions.
$FileAction = Register-ObjectEvent -InputObject $Watcher Created -SourceIdentifier FileCreated_$ID -Action {
$Local = Split-Path ($Event.SourceEventArgs.FullPath)
$i = 0
#Selects which file extentions to include in renaming
Filter Where-Extension {
Param( [String[]] $Extension = ('.bmp', '.jpg', '.png', '.gif', '.jpeg', '.avi')) $_ |
Where-Object { $Extension -contains $_.Extension }}
#Orders all the files by their CreationTime
Function Global:File-Order ($Local) {Get-ChildItem -Path $Local |
Where-Extension .jpg,.bmp,.png,.jpeg,.gif,.avi |
Select-Object Name,FullName,CreationTime|Sort-Object -Property CreationTime}
#Returns a file's extension
Function Global:File-Ext ($File) {Get-ItemProperty $File| Select-Object -Expand Extension}
#Returns the name the file should be - the NewName
$NewBase = ((Split-Path $Local -Leaf) + '_{0:d2}{1}' -f $i, $Ext).Split("\.")
File-Order ($Local) | ForEach-Object -Begin {$i = 0} `
-Process {
$Ext = File-Ext ($_.FullName)
$NewName = $NewBase[0] + $i
if (!(Test-Path (-Join ($Local,'\',$NewName,'.*'))))
{Rename-Item -Path $_.FullName -NewName (-Join ($NewName,$Ext))}
$i++ }
};
$FileAction = Register-ObjectEvent -InputObject $Watcher Deleted -SourceIdentifier FileDeleted_$ID -Action {
$Local = Split-Path ($Event.SourceEventArgs.FullPath)
$i = 0
#Selects which file extentions to include in renaming
Filter Where-Extension {
Param( [String[]] $Extension = ('.bmp', '.jpg', '.png', '.gif', '.jpeg', '.avi')) $_ |
Where-Object { $Extension -contains $_.Extension }}
#Orders all the files by their CreationTime
Function Global:File-Order ($Local) {Get-ChildItem -Path $Local |
Where-Extension .jpg,.bmp,.png,.jpeg,.gif,.avi |
Select-Object Name,FullName,CreationTime|Sort-Object -Property CreationTime}
#Returns a file's extension
Function Global:File-Ext ($File) {Get-ItemProperty $File| Select-Object -Expand Extension}
#Returns the name the file should be - the NewName
$NewBase = ((Split-Path $Local -Leaf) + '_{0:d2}{1}' -f $i, $Ext).Split("\.")
File-Order ($Local) | ForEach-Object -Begin {$i = 0} `
-Process {
$Ext = File-Ext ($_.FullName)
$NewName = $NewBase[0] + $i
if (!(Test-Path (-Join ($Local,'\',$NewName,'.*'))))
{Rename-Item -Path $_.FullName -NewName (-Join ($NewName,$Ext))}
$i++ }
};
New-Object PSObject -Property @{ Watcher = $Watcher; OnCreated = $FileAction };
});
#These will the stop the scripts
#Unregister-Event FileCreated_Pic Test -Verbose
#Unregister-Event FileDeleted_Pic Test -Verbose
#Unregister-Event FileCreated_Another Test -Verbose
#Unregister-Event FileDeleted_Another Test -Verbose
#This will stop all the scripts at once, including any others you may have running; so use Get-EventSubscriber first, to see what's running, then.
#Get-EventSubscriber | Unregister-Event -Verbose
And I'd like to thank @justinf and give credit to the most influential sources I used.