In Powershell I am trying to rename ~2,500 files. However, some needed to be deleted as they were duplicates. Now 2,400 remain, but these files are not numbered sequentially (ie DATE_Photo001_NAME, DATE_Photo003_NAME)
I have been using the following to do the dates and the photo #'s in one pass, however, these photos span multiple dates and I'm just trying to streamline it.
ls |
Rename-Item -NewName {$_.name -replace "Photo???",("Photo{0:d3}" -f {1},$nr++)}
This keeps throwing me an error because the "???" is naturally invalid in a file name. I thought that the placeholder would work the same as the command prompt which I used before diving into Powershell. Any help is welcome and if there is an easier way to do this let me know!
Make the regex you pass to -replace
match a run of digits (\d+
) only if preceded by _Photo
and succeeded by _
, and replace those digits with the new sequence number:
$nr = @{ Value = 1 }
Get-ChildItem -File |
Rename-Item -NewName {
$_.Name -replace '(?<=_Photo)\d+(?=_)', ($nr.Value++).ToString('D3')
} -WhatIf
Note: The -WhatIf
common parameter in the command above previews the operation. Remove -WhatIf
and re-execute once you're sure the operation will do what you want.
Note:
An aux. hashtable (@{ Value = 1 }
) is used to contain the sequence number, which is necessary for technical reasons: delay-bind script blocks run in a child scope of the caller - see this answer for background information.
The -File
switch passed to Get-ChildItem
(one of whose built-in aliases on Windows is ls
) limits processing to only files, not also directories.
The regex passed to -replace
uses positive lookaround assertions ((?<=...)
and (?=...)
), which ensure that patterns of interest precede and succeed the run of digits but without becoming part of what is captured.
The desired formatting string, D3
is passed to a .ToString()
method call directly on the sequence number; the -f
operator-based alternative would be:
('{0:D3}' -f $nr.Value++)