3

I have the following script:

$allFiles = Get-ChildItem "./" -Recurse | Where { ($_.Extension -eq ".ts")}
foreach($file in $allFiles)
{
    # Find and replace the dash cased the contents of the files
    (Get-Content $file.PSPath) | 
        Foreach-Object {$_ -replace "my-project-name", '$appNameDashCased$'} |
        Set-Content $file.PSPath    

    # Find and replace the dash cased the contents of the files
    (Get-Content $file.PSPath) | 
        Foreach-Object {$_ -replace "MyProjectName", '$appNameCamelCased$'} |
        Set-Content $file.PSPath    

    # Find and replace the dash cased the contents of the files
    (Get-Content $file.PSPath) | 
        Foreach-Object {$_ -replace "myProjectName", '$appNamePascalCased$'} |
        Set-Content $file.PSPath    
}

It takes a file and does some replacing, then saves the file. Then it takes the same file and does some more replacing then saves the file again. Then it does it one more time.

This works, but seems inefficient.

Is there a way to do all the replacing and then save the file once?

(If possible, I would prefer to keep the readable style of PowerShell.)

1
  • TheMadTechnician's answer got my vote. Other things when I see your code: First line is clumsy: ./ is Linux for 'here', so leave that off, Get-ChildItem assumes the current path (and the current PS drive) if you don't specify one. Piping the output to Where-Object works, but in this command it is inefficient since the command has built in filtering. Also, with where-object clause you've used, you have curly brackets around parenthesis. The parenthesis are unneeded. $allFiles = Get-ChildItem -recurse -Include "*.ts". For Get-Content, you can just use the $file object. Get-Content $file Commented Aug 23, 2016 at 22:46

2 Answers 2

3

Sure, just chain your replaces inside the ForEach-Object block:

$allFiles = Get-ChildItem "./" -Recurse | Where { ($_.Extension -eq ".ts")}
foreach($file in $allFiles)
{
    (Get-Content $file.PSPath) | 
        Foreach-Object {
            # Find and replace the dash cased the contents of the files
            $_ -replace "my-project-name", '$appNameDashCased$' `
               -replace "MyProjectName", '$appNameCamelCased$' `
               -replace "myProjectName", '$appNamePascalCased$'
        } |
        Set-Content $file.PSPath    
}
Sign up to request clarification or add additional context in comments.

5 Comments

@Xalorous I'm not following.. could you expand on what you mean? I don't think there are any additional pipes needed.
I deleted my comment when it sunk in that it was one long command. However, your code doesn't have anything keeping the line going at the end of the '-replace' lines, I'm not sure having the following line start with -replace will do it. I think you need a backtick at the end of the first two.
When I run this I get The term '-replace' is not recognized as the name of a cmdlet, function, script file, or operable program. But if I take out all but the first -replace lines then it runs without errors. (It does not seem to like the way it is put together...)
Later versions of Powershell have made it where commands can be split over multiple lines, as long as what is left does not make a complete command. The easiest way to picture it is with parenthesis. If you have an open parenthetical expression, it will automatically span lines until you close it. The backtick character is a way to force a new line and tells the console to treat the following line as a continuation.
@Vaccano I was trying to make it more readable with the line breaks and backticks, but you can just put them all on one line like in TheMadTechnician's answer.
3

This can be done, and is actually far simpler than what you're doing. You can chain the -Replace command as such:

$allFiles = Get-ChildItem "./" -Recurse | Where { ($_.Extension -eq ".ts")}
foreach($file in $allFiles)
{
    # Find and replace the dash cased the contents of the files
    (Get-Content $file.PSPath) -replace "my-project-name", '$appNameDashCased$' -replace "StringB", '$SecondReplacement$' -replace "StringC", '$ThirdReplacement$' | Set-Content $file.PSPath
}

3 Comments

Nice! I think Set-Content can fail in this way because of the pipeline, hence his wrapping of Get-Content in parentheses to force the whole file to be read first, but that can easily be applied to this as well.
I tried this in PowerShell 4.0 as well and it id not work there either.... Complained about not knowing what replace was.
Added () around the Get-Content cmdlet to make it apply the -Replace to the results, instead of trying to interpret it as an argument to Get-Content. That should work for you.

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.