Jump to content

Openai/696d32ab-db40-8002-88a6-787fbce475bb

From freem


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):

  1. Save as AutoRenameOnDrop.ps1
  2. Edit $WatchFolders to the folders you want.
  3. 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]

  1. "Powershell auto-rename script". ChatGPT. Retrieved 2026-01-19.