I've never used powershell or any cmd line to try and rename files, nor so I really know much about script writing in general. I've already had some success in renaming the files in question but am stuck on the last piece of the puzzle.
Original file names:
NEE100_N-20210812_082245.jpg
NEE101_E-20210812_083782.jpg
NEE102_W-20210812_084983.jpg
I successfully change those to AT-###-N-......jpg using:
Rename-Item -NewName {$_.name -replace "NEE\d\d\d_", "AT-112-"}
And this is what they looked like after: AT-112-N-20210812_082245.jpg
AT-112-E-20210812_083782.jpg
AT-112-W-20210812_084983.jpg
Now however, I have a few files that look like this:
AT-112-NewImage-20210812_083782.jpg
AT-112-NewImage-20210812_093722.jpg
and I want to change them to:
AT-112-D1-20210812_083782.jpg
AT-112-D2-20210812_093722.jpg
...and so on.
I've tried a few things here to try and do that. Such as replacing "NewImage" with "D" and then using something like this (not exact, just an example):
$i = 1
Get-ChildItem *.jpg | %{Rename-Item $_ -NewName ('19981016_{0:D4}.jpg' -f $i )}
But this did not work. I have seen scripts that use sequential numbering either added as a suffix or a prefix. But I can't figure out how to do this if what I want to have sequence numbering in the middle of the name.
Hopefully this make sense, if I need more elaboration, let me know. Thanks!
CodePudding user response:
You need to use an expression (inside
(...)
) as your-replace
substitution operand in order to incorporate a dynamic value, such as the sequence number in your case.In order to use a variable that maintains state across multiple invocations of a delay-bind script block (
{ ... }
, the one being passed to the-NewName
parameter in your first attempt), you need to create the variable in the caller's scope and explicitly reference it there:- This is necessary, because delay-bind script blocks run in a child scope, unfortunately,[1] so that any variables created inside the block go out of scope after every invocation.
- Use
Get-Variable
to obtain a reference to a variable object in the caller's (parent) scope[2], and use its.Value
property, as shown below.
$i = 1
Get-ChildItem *.jpg | Rename-Item -NewName {
$_.Name -replace '-NewImage-', ('-D{0}-' -f (Get-Variable i).Value )
} -WhatIf
Note: The -WhatIf
common parameter in the command above previews the operation. Remove -WhatIf
once you're sure the operation will do what you want.
Note: The above solution is simple, but somewhat inefficient, due to the repeated Get-Variable
calls - see this answer for more efficient alternatives.
[1] This contrasts with the behavior of script blocks passed to Where-Object
and ForEach-Object
. See GitHub issue #7157 for a discussion of this problematic discrepancy.
[2] Without a -Scope
argument, if Get-Variable
doesn't find a variable in the current scope, it looks for a variable in the ancestral scopes, starting with the parent scope - which in this case the caller's. You can make the call's intent more explicitly with -Scope 1
, which starts the lookup from the parent scope.