Openai/696d32ab-db40-8002-88a6-787fbce475bb
Appearance
This conversation was exported from ChatGPT[1]
gpt-5-2-thinking[edit | edit source]
User: Can you write a Powershell script that solves the issue described in the picture?[edit | edit source]
Can you write a Powershell script that solves the issue described in the picture?
Assistant: Here’s a PowerShell script that watches one or many folders and auto-renames any newly added file to:[edit | edit source]
Here’s a PowerShell script that watches one (or many) folders and auto-renames any newly added file to:
<folder name> <next number><original extension>
Example: dropping h322fsrdfk.jpg into beach\ becomes beach 4.jpg if beach 1., beach 2., beach 3.* already exist.
<#
Auto-rename files when they appear in watched folders.
Behavior:
* Watches one or more folders (non-recursive by default).
* When a new file is created or renamed into the folder, it renames it to:
"<FolderName> <NextNumber><OriginalExtension>"
e.g. "beach 4.jpg"
Notes:
* Handles files that are still being written by waiting until the file is unlocked.
* Skips files that already match the pattern "<folder> <number>.<ext>".
* Skips temporary/system-ish files (customize in $IgnoreRegex if needed).
#>
=== ------------------- CONFIG ------------------- ===
=== Add folders you want to watch here: ===
$WatchFolders = @(
"C:\Images\beach"
# "D:\OtherFolder"
)
=== Watch subfolders too? ===
$IncludeSubdirectories = $false
=== Ignore certain filenames (temp downloads etc). Adjust as needed. ===
$IgnoreRegex = '(\.tmp$|\.part$|\.crdownload$|^~\$)'
=== How long to wait for a file to become available (seconds) ===
$MaxWaitSeconds = 15
=== Poll interval while waiting (milliseconds) ===
$WaitIntervalMs = 200
=== --------------------------------------------- ===
function Test-FileUnlocked {
param([Parameter(Mandatory)][string]$Path)
try {
$stream = [System.IO.File]::Open($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
$stream.Close()
return $true
} catch {
return $false
}
}
function Wait-ForFileReady {
param(
[Parameter(Mandatory)][string]$Path,
[int]$MaxWaitSeconds = 15,
[int]$IntervalMs = 200
)
$sw = [System.Diagnostics.Stopwatch]::StartNew()
while ($sw.Elapsed.TotalSeconds -lt $MaxWaitSeconds) {
if (Test-Path -LiteralPath $Path -PathType Leaf) {
if (Test-FileUnlocked -Path $Path) { return $true }
}
Start-Sleep -Milliseconds $IntervalMs
}
return $false
}
function Get-NextNumberForFolder {
param(
[Parameter(Mandatory)][string]$FolderPath,
[Parameter(Mandatory)][string]$FolderName
)
# Match: "<FolderName> <number>.<any extension>"
$pattern = '^' + [regex]::Escape($FolderName) + '\s+(?<n>\d+)\.[^.]+$'
$max = 0
Get-ChildItem -LiteralPath $FolderPath -File -ErrorAction SilentlyContinue | ForEach-Object {
$m = [regex]::Match($_.Name, $pattern)
if ($m.Success) {
$n = [int]$m.Groups['n'].Value
if ($n -gt $max) { $max = $n }
}
}
return ($max + 1)
}
function Rename-NewFile {
param(
[Parameter(Mandatory)][string]$FullPath
)
if (-not (Test-Path -LiteralPath $FullPath -PathType Leaf)) { return }
$item = Get-Item -LiteralPath $FullPath -ErrorAction SilentlyContinue
if (-not $item) { return }
$fileName = $item.Name
# Ignore temp-ish files
if ($fileName -match $IgnoreRegex) { return }
$folderPath = $item.Directory.FullName
$folderName = Split-Path -Leaf $folderPath
# If it already matches "<folder> <number>.<ext>", skip
$alreadyPattern = '^' + [regex]::Escape($folderName) + '\s+\d+\.[^.]+$'
if ($fileName -match $alreadyPattern) { return }
# Wait for the file to be fully written / unlocked
if (-not (Wait-ForFileReady -Path $FullPath -MaxWaitSeconds $MaxWaitSeconds -IntervalMs $WaitIntervalMs)) {
Write-Host "Skipped (file stayed locked too long): $FullPath"
return
}
$ext = $item.Extension # includes the dot
$next = Get-NextNumberForFolder -FolderPath $folderPath -FolderName $folderName
# Ensure unique name even if something races in
while ($true) {
$newName = "$folderName $next$ext"
$newPath = Join-Path $folderPath $newName
if (-not (Test-Path -LiteralPath $newPath)) { break }
$next++
}
try {
Rename-Item -LiteralPath $FullPath -NewName $newName -ErrorAction Stop
Write-Host "Renamed: '$fileName' -> '$newName'"
} catch {
Write-Host "Rename failed for $FullPath : $($_.Exception.Message)"
}
}
=== Create watchers ===
$watchers = @()
foreach ($folder in $WatchFolders) {
if (-not (Test-Path -LiteralPath $folder -PathType Container)) {
Write-Host "Folder not found, skipping: $folder"
continue
}
$fsw = New-Object System.IO.FileSystemWatcher
$fsw.Path = $folder
$fsw.Filter = "''.''"
$fsw.IncludeSubdirectories = $IncludeSubdirectories
$fsw.NotifyFilter = [System.IO.NotifyFilters]'FileName, LastWrite'
# Handle Created + Renamed (covers many “copy into folder” behaviors)
Register-ObjectEvent -InputObject $fsw -EventName Created -SourceIdentifier "FSW.Created.$folder" -Action {
Rename-NewFile -FullPath $Event.SourceEventArgs.FullPath
} | Out-Null
Register-ObjectEvent -InputObject $fsw -EventName Renamed -SourceIdentifier "FSW.Renamed.$folder" -Action {
Rename-NewFile -FullPath $Event.SourceEventArgs.FullPath
} | Out-Null
$fsw.EnableRaisingEvents = $true
$watchers += $fsw
Write-Host "Watching: $folder"
}
Write-Host "Running. Press Ctrl+C to stop."
while ($true) { Start-Sleep -Seconds 1 }
How to use (quick):
- Save as AutoRenameOnDrop.ps1
- Edit $WatchFolders to the folders you want.
- Run in PowerShell: ``
powershell powershell -ExecutionPolicy Bypass -File .\AutoRenameOnDrop.ps1``
If you want it to watch a parent folder and apply this rule to every subfolder (each subfolder uses its own name/numbering), tell me your folder structure and I’ll adapt the script.
References[edit | edit source]
- ↑ "Powershell auto-rename script". ChatGPT. Retrieved 2026-01-19.