Need to know how to use PowerShell to replace text in a file? 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.

  1. Reading the file
  2. Finding and replacing the string
  3. 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.

Join the Jar Tippers on Patreon

It takes a lot of time to write detailed blog posts like this one. In a single-income family, this blog is one way I depend on to keep the lights on. I'd be eternally grateful if you could become a Patreon patron today!

Become a Patron!