Need to know how to use PowerShell to read a text file and replace text? This is what we call the PowerShell Read-Text File.
Not a reader? Watch this related video tutorial!Look no further! This blog post is for you. By the end of the post, I’ll show you a function I built to make your life much easier.
Replacing text in a file with PowerShell is three-step process.
- Reading the file
- Finding and replacing the string
- Writing changes to the file.
Reading the File
You’ll first need to read the file. Let’s first create one with the Set-Content
cmdlet so we have one to work with.
Set-Content -Path 'C:\file.txt' -Value 'foo bar baz'
To read this file, you can use the Get-Content
command. You can read the file by providing a text file path to the Path
parameter as shown below.
$content = Get-Content -Path 'C:\file.txt'
Finding and Replacing the String
Now that we have the file’s content in memory in a string, we need to search and replace the string. One way to do that is to use the -replace
operator. This PowerShell operator finds a string and replaces it with another.
Using the example file contents, we can provide the search string foo with the replacement string bar which should make the file contents foo foo baz now.
PS> $newContent = $content -replace 'foo', 'bar'
bar bar baz
Writing to the File
Now that we have the new file contents saved in $newContent
, we can now need to write this new content back to the file. One way to do that is to use the Set-Content
command.
The Set-Content
command replaces all contents of a file with assigning a new value.
$newContent | Set-Content -Path 'C:\file.txt'
Whenever you now read the C:\file.txt file with Get-Content
, you’ll see that it now contains the new content.
Dealing with Open File Handles
The steps you previously went through work….most of the time. However, you’ll find in the real world, it doesn’t always turn out that way.
You’ll find that you’ll occasionally have to deal with files that are either open PowerShell itself. This prevents you from writing the new contents back to the file.
To remedy this open file handle situation, I created a simple workflow that allows you to create a temporary text file on disk first with the new contents, remove the original file and then rename the temporary file.
Here’s an example of how it works:
$filePath = 'C:\file.txt'
$tempFilePath = "$env:TEMP\$($filePath | Split-Path -Leaf)"
$find = 'foo'
$replace = 'bar'
(Get-Content -Path $filePath) -replace $find, $replace | Add-Content -Path $tempFilePath
Remove-Item -Path $filePath
Move-Item -Path $tempFilePath -Destination $filePath
Below is an example of a function I built called Find-InTextFile
which uses this approach combined with the ability to find (not replace) text in a file.
This function also uses the more powerful regular expression syntax to find strings as well. You’ll find that regular expressions will allow you to more flexible searching using special characters like single quotes, special characters and more.
You can also see below that I’m using a foreach loop to process multiple files at once. This comes in handy if you have a bunch of files to process.
function Find-InTextFile {
<#
.SYNOPSIS
Performs a find (or replace) on a string in a text file or files.
.EXAMPLE
PS> Find-InTextFile -FilePath 'C:\MyFile.txt' -Find 'water' -Replace 'wine'
Replaces all instances of the string 'water' into the string 'wine' in
'C:\MyFile.txt'.
.EXAMPLE
PS> Find-InTextFile -FilePath 'C:\MyFile.txt' -Find 'water'
Finds all instances of the string 'water' in the file 'C:\MyFile.txt'.
.PARAMETER FilePath
The file path of the text file you'd like to perform a find/replace on.
.PARAMETER Find
The string you'd like to replace.
.PARAMETER Replace
The string you'd like to replace your 'Find' string with.
.PARAMETER NewFilePath
If a new file with the replaced the string needs to be created instead of replacing
the contents of the existing file use this param to create a new file.
.PARAMETER Force
If the NewFilePath param is used using this param will overwrite any file that
exists in NewFilePath.
#>
[CmdletBinding(DefaultParameterSetName = 'NewFile')]
[OutputType()]
param (
[Parameter(Mandatory = $true)]
[ValidateScript({Test-Path -Path $_ -PathType 'Leaf'})]
[string[]]$FilePath,
[Parameter(Mandatory = $true)]
[string]$Find,
[Parameter()]
[string]$Replace,
[Parameter(ParameterSetName = 'NewFile')]
[ValidateScript({ Test-Path -Path ($_ | Split-Path -Parent) -PathType 'Container' })]
[string]$NewFilePath,
[Parameter(ParameterSetName = 'NewFile')]
[switch]$Force
)
begin {
$Find = [regex]::Escape($Find)
}
process {
try {
foreach ($File in $FilePath) {
if ($Replace) {
if ($NewFilePath) {
if ((Test-Path -Path $NewFilePath -PathType 'Leaf') -and $Force.IsPresent) {
Remove-Item -Path $NewFilePath -Force
(Get-Content $File) -replace $Find, $Replace | Add-Content -Path $NewFilePath -Force
} elseif ((Test-Path -Path $NewFilePath -PathType 'Leaf') -and !$Force.IsPresent) {
Write-Warning "The file at '$NewFilePath' already exists and the -Force param was not used"
} else {
(Get-Content $File) -replace $Find, $Replace | Add-Content -Path $NewFilePath -Force
}
} else {
(Get-Content $File) -replace $Find, $Replace | Add-Content -Path "$File.tmp" -Force
Remove-Item -Path $File
Move-Item -Path "$File.tmp" -Destination $File
}
} else {
Select-String -Path $File -Pattern $Find
}
}
} catch {
Write-Error $_.Exception.Message
}
}
}
Resources
For more information on the Set-Content
command check out Set-Content: The PowerShell Way to Write to a File or an alternative way to write contents to a file, the Out-File
command.