Last active
August 10, 2023 09:50
-
-
Save Bill-Stewart/6b8e54e17526a0e6f7fafe432ca8a397 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Update-FileText.ps1 | |
# Written by Bill Stewart (bstewart@iname.com) | |
#requires -version 2 | |
<# | |
.SYNOPSIS | |
Updates text in files using a regular expression. | |
.DESCRIPTION | |
Updates text in files using a regular expression. | |
.PARAMETER Pattern | |
Specifies the regular expression pattern. | |
.PARAMETER Replacement | |
Specifies the regular expression replacement pattern. | |
.PARAMETER Path | |
Specifies the path to one or more files. Wildcards are not supported. Each file is read entirely into memory to support multi-line searching and replacing, so performance may be slow for large files. | |
.PARAMETER CaseSensitive | |
Specifies case-sensitive matching. The default is to ignore case. | |
.PARAMETER SimpleMatch | |
Specifies a simple match rather than a regular expression match (i.e., the Pattern parameter specifies a simple string rather than a regular expression). | |
.PARAMETER Multiline | |
Changes the meaning of ^ and $ so they match at the beginning and end, respectively, of any line, and not just the beginning and end of the entire file. The default is that ^ and $, respectively, match the beginning and end of the entire file. | |
.PARAMETER UnixText | |
Causes $ to match only linefeed (\n) characters. By default, $ matches carriage return+linefeed (\r\n). (Windows-based text files usually use \r\n as line terminators, while Unix-based text files usually use only \n.) | |
.PARAMETER Overwrite | |
Overwrites a file by creating a temporary file containing all replacements and then replacing the original file with the temporary file. The default is to output but not overwrite. | |
.PARAMETER Force | |
Allows overwriting of read-only files. Note that this parameter cannot override security restrictions. | |
.PARAMETER Encoding | |
Specifies the encoding for the file when -Overwrite is used. Possible values for this parameter are ASCII, BigEndianUnicode, Unicode, UTF32, UTF7, and UTF8. The default value is ASCII. | |
.INPUTS | |
System.IO.FileInfo. | |
.OUTPUTS | |
System.String (single-line file) or System.String[] (file with more than one line) without the -Overwrite parameter, or nothing with the -Overwrite parameter. | |
.LINK | |
about_Regular_Expressions | |
.EXAMPLE | |
C:\> Update-FileText.ps1 '(Ferb) and (Phineas)' '$2 and $1' Story.txt | |
This command replaces the text 'Ferb and Phineas' with the text 'Phineas and Ferb' in the file Story.txt and outputs the content. Note that the pattern and replacement strings are enclosed in single quotes to prevent variable expansion. | |
.EXAMPLE | |
C:\> Update-FileText.ps1 'Perry' 'Agent P' Story2.txt -Overwrite | |
This command replaces the text 'Perry' with the text 'Agent P' in the file Story2.txt. | |
#> | |
[CmdletBinding(SupportsShouldProcess = $true,ConfirmImpact = "High")] | |
param( | |
[Parameter(Mandatory = $true,Position = 0,ValueFromPipeline = $true)] | |
[String[]] $Path, | |
[Parameter(Mandatory = $true,Position = 1)] | |
[String] $Pattern, | |
[Parameter(Mandatory = $true,Position = 2)] | |
[AllowEmptyString()] | |
[String] $Replacement, | |
[Switch] $CaseSensitive, | |
[Switch] $SimpleMatch, | |
[Switch] $Multiline, | |
[Switch] $UnixText, | |
[Switch] $Overwrite, | |
[Switch] $Force, | |
[ValidateSet("ASCII","BigEndianUnicode","Unicode","UTF32","UTF7","UTF8")] | |
[String] $Encoding = "ASCII" | |
) | |
begin { | |
function Get-TempName { | |
param( | |
$path | |
) | |
do { | |
$tempName = Join-Path $path ([IO.Path]::GetRandomFilename()) | |
} | |
while ( Test-Path $tempName ) | |
$tempName | |
} | |
if ( $SimpleMatch ) { | |
$Pattern = [Regex]::Escape($Pattern) | |
} | |
else { | |
if ( -not $UnixText ) { | |
$Pattern = $Pattern -replace '(?<!\\)\$','\r$' | |
} | |
} | |
function New-Regex { | |
$regexOpts = [Text.RegularExpressions.RegexOptions]::None | |
if ( -not $CaseSensitive ) { | |
$regexOpts = $regexOpts -bor [Text.RegularExpressions.RegexOptions]::IgnoreCase | |
} | |
if ( $Multiline ) { | |
$regexOpts = $regexOpts -bor [Text.RegularExpressions.RegexOptions]::Multiline | |
} | |
New-Object Text.RegularExpressions.Regex $Pattern,$regexOpts | |
} | |
$Regex = New-Regex | |
function Update-FileText { | |
param( | |
$path | |
) | |
$pathInfo = Resolve-Path -LiteralPath $path | |
if ( $pathInfo ) { | |
if ( (Get-Item $pathInfo).GetType().FullName -eq "System.IO.FileInfo" ) { | |
$fullName = $pathInfo.Path | |
Write-Verbose "Reading '$fullName'" | |
$text = [IO.File]::ReadAllText($fullName) | |
Write-Verbose "Finished reading '$fullName'" | |
if ( -not $Overwrite ) { | |
$regex.Replace($text,$Replacement) | |
} | |
else { | |
$tempName = Get-TempName (Split-Path $fullName -Parent) | |
Set-Content $tempName $null -Confirm:$false | |
if ( $? ) { | |
Write-Verbose "Created file '$tempName'" | |
try { | |
Write-Verbose "Started writing '$tempName'" | |
[IO.File]::WriteAllText("$tempName",$Regex.Replace($text,$Replacement),[Text.Encoding]::$Encoding) | |
Write-Verbose "Finished writing '$tempName'" | |
Write-Verbose "Started copying '$tempName' to '$fullName'" | |
Copy-Item $tempName $fullName -Force:$Force -ErrorAction Continue | |
if ( $? ) { | |
Write-Verbose "Finished copying '$tempName' to '$fullName'" | |
} | |
Remove-Item $tempName | |
if ( $? ) { | |
Write-Verbose "Removed file '$tempName'" | |
} | |
} | |
catch [Management.Automation.MethodInvocationException] { | |
Write-Error $Error[0] | |
} | |
} | |
} | |
} | |
else { | |
Write-Error "The item '$path' must be a file in the file system." -Category InvalidType | |
} | |
} | |
} | |
} | |
process { | |
foreach ( $PathItem in $Path ) { | |
if ( $Overwrite ) { | |
if ( $PSCmdlet.ShouldProcess("'$PathItem'","Overwrite file") ) { | |
Update-FileText $PathItem | |
} | |
} | |
else { | |
Update-FileText $PathItem | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment