18

I want to replace a text in multiple files and folders. The folder name changes, but the filename is always config.xml.

$fileName = Get-ChildItem "C:\config\app*\config.xml" -Recurse
(Get-Content $fileName) -replace 'this', 'that' | Set-Content $fileName

When I run the above script it works, but it writes the whole text in config.xml about 20 times. What's wrong?

1

4 Answers 4

18

$filename is a collection of System.IO.FileInfo objects. You have to loop to get the content for each file : this should do what you want :

$filename | %{
    (gc $_) -replace "THIS","THAT" |Set-Content $_.fullname
}
Sign up to request clarification or add additional context in comments.

2 Comments

Note: this seems to set the content of all files, i.e. image files will be opened as text and re-saved. I added an additional check before modifying files
The text "THIS" can contain a regular expression as well. So, if you want to replace a literal string "THIS+" with "THAT+" then you need to escape the + in the source string. E.g. "THIS\+","THAT+"
13

In general, you should use the pipeline and combine the ForEach-Object and/or Where-Object CmdLets.

In your case, this would like like something more akin to:

Get-ChildItem "C:\config\app*\config.xml" -Recurse | ForEach-Object -Process {
    (Get-Content $_) -Replace 'this', 'that' | Set-Content $_
}

Which can be shortened somewhat to:

dir "C:\config\app*\config.xml" -recurse |% { (gc $_) -replace 'this', 'that' | (sc $_) }

1 Comment

Nice. Thanks for the showing both the long and shorthand.
6

$filename is an array of filenames, and it's trying to do them all at once. Try doing them one at a time:

$fileNames = Get-ChildItem "C:\config\app*\config.xml" -Recurse |
 select -expand fullname

foreach ($filename in $filenames) 
{
  (  Get-Content $fileName) -replace 'this', 'that' | Set-Content $fileName
}

1 Comment

How would I count the number of files changed and/or number of changes made?
0

I got list of files to replace text this way.

$filenames = Get-ChildItem|Select-String -Pattern ""|select Filename

This gets 12 files.

To replace this text in all files

foreach ($filename in $filesnames){ (Get-Content $filename.Filename) -replace "", ""|Set-Content $filename.Filename }

Don't forget last part for Filename. $filename.Filename

1 Comment

$filenames = Get-ChildItem|Select-String -Pattern "<script src='jquery.js'></script>"|select Filename

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.