In PowerShell [Core] (v6.1+), a concise solution is possible:
$file = 'somefile.txt'
(Get-Content -Raw $file) -replace '(?m)(?<=^\s+version: ).+(?=;$)', {
# Increment the *last numeric* component of the version number.
# See below for how to target other components.
$_.Value -replace '(?<=\.)\d+(?=$|-)', { 1 + $_.Value }
} | Set-Content $file
Note:
* In PowerShell [Core] 6+, BOM-less UTF-8 is the default encoding; use -Encoding
with Set-Content
if you need a different encoding.
* By using -Raw
, the command reads the entire file into memory first, which enables writing back to that same file in the same pipeline; however, there is a slight risk of data loss if writing back to the input file gets interrupted.
* -replace
invariably replaces all substrings that match the regex.
* Inline regex option (?m)
ensures that ^
and $
match the start and end of individual lines, which is necessary due to Get-Content -Raw
reading the entire file as a single, multi-line string.
Note:
For simplicity, text-based manipulation of the version string is performed, but you could also cast $_.Value
to [version]
or [semver]
(PowerShell [Core] v6+ only) and work with that.
The advantage of the text-based manipulation is the concise ability to retain all other components of the input version string as-is, without adding previously unspecified ones.
The above relies on the -replace
operator's ability to perform regex-based string substitutions fully dynamically, via a script block ({ ... }
) - as explained in this answer.
The regexes use look-around assertions ((?<=...)
and (?=...)
) so as to ensure that only the part of the input to be modified is matched.
- Only the
(?<=^\s+version: )
and (?=;$)
look-arounds are specific to the sample file format; adjust these parts as needed to match the version number in your file format.
The above increment's the input version's last numeric component.
To target the various version-number components, use the following inner regex instead:
Increment the major number (e.g., 2.0.9
-> 3.0.9
):
'2.0.9' -replace '\d+(?=\..+)', { 1 + [int] $_.Value }
The minor number:
'2.0.9' -replace '(?<=^\d+\.)\d+(?=.*)', { 1 + [int] $_.Value }
The patch / build number (3rd component; 2.0.9
-> 2.0.10
):
'2.0.9' -replace '(?<=^\d+\.\d+\.)\d+(?=.*)', { 1 + [int] $_.Value }
The last / revision number, as above, whatever it is, even if followed by a pre-release label (e.g.,; 2.0.9.10
-> 2.0.9.11
or 7.0.0-preview2
-> 7.0.1-preview2
):
'2.0.9.10' -replace '(?<=\.)\d+(?=$|-)', { 1 + [int] $_.Value }
Note: If the targeted component doesn't exist, the original version is returned as-is.
In Windows PowerShell, where -replace
doesn't support script-block-based substitutions, you can use the switch
statement with the -File
and -Regex
options instead:
$file = 'someFile.txt'
$updatedFileContent =
switch -regex -file $file { # Loop over all lines in the file.
'^\s+version: (.+);$' { # line with version number
# Extract the old version number...
$oldVersion = $Matches[1]
# ... and update it, by incrementing the last component in this
# example.
$components = $oldVersion -split '\.'
$components[-1] = 1 + $components[-1]
$newVersion = $components -join '.'
# Replace the old version with the new version in the line
# and output the modified line.
$_.Replace($oldVersion, $newVersion)
}
default { # All other lines.
# Pass them through.
$_
}
}
# Save back to file. Use -Encoding as needed.
$updatedFileContent | Set-Content $file