neha
neha

Reputation: 463

How do I replace a line in a file using PowerShell?

I am trying to read replace a line in a configuration file using PowerShell. Sometimes this script works, but most of the time it does not replace the line.

(Get-Content D:\home\App_Config\Sitecore.config) `
    | %{ $_ -replace '  <setting name="Media.MediaLinkServerUrl" value=" "/>',' <setting name="Media.MediaLinkServerUrl" value="https://newurl.com"/>'} `
    | Set-Content D:\home\App_Config\Sitecore.config

Upvotes: 36

Views: 93197

Answers (4)

mklement0
mklement0

Reputation: 437803

Try the following:

$file = 'D:\home\App_Config\Sitecore.config'
$regex = '(?<=<setting name="Media\.MediaLinkServerUrl" value=")[^"]*'
(Get-Content $file) -replace $regex, 'https://newurl.com' | Set-Content $file

* Re Set-Content: In Windows PowerShell it uses your system's legacy single-byte character encoding by default (based on the active ANSI code page), so you may want to use -Encoding to control the output file's encoding explicitly; PowerShell [Core] 6+ defaults to BOM-less UTF-8.

  • Also note the required (...) around the Get-Content call to ensure that the pipeline can write back to the same file that Get-Content has read from.
  • If there's a chance that the opening tag in question (<setting ...>) spans multiple lines, use
    Get-Content -Raw $file (PSv3+) to read the entire file content as a single string (thanks, deadlydog);
    without -Raw, Get-Content returns an array of strings, representing the input lines.

Due to using a regular expression to match your existing setting, any text currently inside value="..." is matched, so this command will work even when run repeatedly.

By contrast, what you tried uses an effective literal (... value=" ") to find what to replace, and after the 1st - successful - run, that literal no longer matches, and subsequent runs have no effect.

The command above uses a streamlined approach to replacement:

  • (?<=<setting name="Media.MediaLinkServerUrl" value=") is a look-behind assertion ((?<=...)) that matches, but doesn't capture what it matches: it finds the part up to and including the opening " of the value you're trying to replaces, without making that prefix a part of what will get replaced.

  • [^"]* then matches the entire value, up to, but not including the closing ". ([^"] is a character set that matches any character other than (^) a ", and * finds any (possibly empty) sequence of such characters.

  • Therefore, because the regex captured only the value itself, all you need to specify as the replacement string is the new value.

Upvotes: 63

js2010
js2010

Reputation: 27423

Here's an example that preserves the PSPath property, so you don't have to specify the path to set-content:

(Get-Content -raw input) | ForEach-Object {
    $_ -replace 111,222 |
    Add-Member NoteProperty PSPath $_.PSPath -PassThru
} | Set-Content -nonewline

Upvotes: 0

Md Asiful Haque
Md Asiful Haque

Reputation: 21

This Function worked for me

I am trying to replace anything come after Infile enter image description here

Function:

function Write-FileContent {
        [cmdletBinding()]
        param(
            [parameter(Mandatory = $true)]
            [string]$FileToReplacePath,
            [parameter(Mandatory = $true)]
            [string]$TextToReplaceWith,
            [parameter(Mandatory = $true)]
            [string]$LineNumber,
            [parameter(Mandatory = $true)]
            [string]$TextToBeingWith        
        )
        $Read = Get-Content -Path $FileToReplacePath
        $Read | ForEach-Object { if ($_.ReadCount -eq $LineNumber) { $_ -replace "'$TextToBeginWith'=.+'", "$TextToReplaceWith" }   else { $_ } } | Set-Content $FileToReplacePath
    }

Testing Parameter

$CsvFilePath="C:\msydatfgdfa.csv"
Write-FileContent -FileToReplacePath D:\test.txt -TextToReplaceWith "'$CsvFilePath'" -LineNumber 2 -TextToBeingWith "Infile"

Upvotes: 1

henrycarteruk
henrycarteruk

Reputation: 13227

Use the Replace method like this:

$file = 'D:\home\App_Config\Sitecore.config'
$find = '  <setting name="Media.MediaLinkServerUrl" value=" "/>'
$replace = ' <setting name="Media.MediaLinkServerUrl" value="https://newurl.com"/>'

(Get-Content $file).replace($find, $replace) | Set-Content $file

Upvotes: 27

Related Questions