Friday, June 27, 2008

Powershell replace text in files and recurse subdirectories

I needed to go through every file in a folder and all of its sub directories and open each file and replace a given string. This is what I finally came up with. I'm sure that this can be improved on though...

function ReplaceText($fileInfo)
{
    if( $_.GetType().Name -ne 'FileInfo')
    {
        # i.e. reject DirectoryInfo and other types
         return
    }
    $old = 'my old text'
    $new = 'my new text'
    (Get-Content $fileInfo.FullName) | % {$_ -replace $old, $new} | Set-Content -path $fileInfo.FullName
    "Processed: " + $fileInfo.FullName
}

$loc = 'c:\my file\location'
cd $loc
$files = Get-ChildItem . -recurse

$files | % { ReplaceText( $_ ) }

7 comments:

  1. Thank you!! Sovled my problem.

    ReplyDelete
  2. It's worth pointing out that the search term in -replace isn't a string, it's an regular expression.
    So to match "[TOKEN]" you need to use the espace (/) character, resulting in "/[TOKEN/]".

    ReplyDelete
  3. Thanks Ryan - I had not realized that.

    ReplyDelete
  4. Howdy Guy!
    This is how I would have written it. It is a bit more streamlined and efficient. It is still not SED but do you like this version any better? (We are improving our text processing release after release but honestly it is not our top priority [Object manipulation is]).
    $old = 'my old text'
    $new = 'my new text'
    Get-ChildItem c:\my file\location -Recurse |
    Where {$_ -IS [IO.FileInfo]} |
    % {
    Set-Content $_.FullName (Get-Content $_.FullName) -replace $old,$new)
    Write-Host "Processed: " + $_.FullName
    }
    Enjoy!
    Jeffrey Snover [MSFT]
    Distinguished Engineer
    Visit the Windows PowerShell Team blog at: blogs.msdn.com/.../PowerShell
    Visit the Windows PowerShell ScriptCenter at: www.microsoft.com/.../msh.mspx

    ReplyDelete
  5. I'm new to Powershell, first day. I couldn't get Jeff's script to work. So I modified just a little and it is now working. Just in case, anyone else has an issue I hope this helps.
    $old = 'my old text'
    $new = 'my new text'
    Get-ChildItem c:\myfile\ -Recurse | Where {$_ -IS [IO.FileInfo]} |
    % {
    (Get-Content $_.FullName) -replace $old,$new | Set-Content $_.FullName
    Write-Host "Processed: " + $_.FullName
    }

    ReplyDelete
  6. I was unable to get the shorter script to work, so I used the script from the original post and it works great! The only change I made was to add the
    -force switch before -recurse so it would find hidden files.

    ReplyDelete
  7. Have you ever thought about replacing a $old and $new which contains characters like <, ", '....
    it runs into error in such cases

    ReplyDelete