Many moons later, let me complement the existing, helpful answers - which continue to work in principle (see below) - with a simpler PowerShell (Core) 7 solution:
Thanks to a contribution by Mathias R. Jessen, PowerShell (Core) 7, the cross-platform successor to the legacy, Windows-only Windows PowerShell (whose latest an last version is 5.1):
now does support passing passing a callback as the substitution operand of the -replace
operator, ...
... namely in the form of a script block ({ ... }
), inside of which the match at hand can be referred to via the automatic $_
variable; $_.Value
therefore refers to the matched text.
Therefore:
# PowerShell 7 only
$i = 0
'zzz match match xxx' -replace 'match', { 'string-{0}-{1}' -f $_.Value, ++$i }
Output:
zzz string-match-1 string-match-2 xxx
Note the use of -f
, the format operator, to synthesize the substitution string that is output by the script block.
Since the substitution script block runs directly in the caller's scope, you can apply ++
, the increment operator, directly to the caller's $i
variable.
The backward-compatible Windows PowerShell-compatible solution that is the equivalent of the above is the following, using [regex]::Replace()
:
# Works in both Windows PowerShell and PowerShell 7.
$i = 0
[regex]::Replace(
'zzz match match xxx',
'match',
{ param($m) 'string-{0}-{1}' -f $m.Value, ++(Get-Variable -Scope 1 -Name i).Value }
)
The script block ({ ... }
) that is passed acts as the MatchEvaluator delegate, to which the match at hand is passed as an argument, which param($m)
inside the script block formally declares.
Unlike with -replace
in PowerShell 7, the script block runs in a child scope of the caller, requiring extra effort to update a variable in the caller's scope: