Powershell function to replace or add lines in text files

29,818

Solution 1

Assuming the $key you want to replace is always at the beginning of a line, and that it contains no special regex characters

function setConfig( $file, $key, $value ) {
    $content = Get-Content $file
    if ( $content -match "^$key\s*=" ) {
        $content -replace "^$key\s*=.*", "$key = $value" |
        Set-Content $file     
    } else {
        Add-Content $file "$key = $value"
    }
}

setConfig "divider.conf" "Logentrytimeout" "180" 

If there is no replacement $key = $value will be appended to the file.

Solution 2

Updated version of the functions above with some parametrisation and verbose output if required.

   Function Set-FileConfigurationValue()
{
    [CmdletBinding(PositionalBinding=$false)]   
    param(
        [Parameter(Mandatory)][string][ValidateScript({Test-Path $_})] $Path,
        [Parameter(Mandatory)][string][ValidateNotNullOrEmpty()] $Key,
        [Parameter(Mandatory)][string][ValidateNotNullOrEmpty()] $Value,
        [Switch] $ReplaceExistingValue,
        [Switch] $ReplaceOnly
    )

    $content = Get-Content -Path $Path
    $regreplace = $("(?<=$Key).*?=.*")
    $regValue = $("=" + $Value)
    if (([regex]::Match((Get-Content $Path),$regreplace)).success)
    {
        If ($ReplaceExistingValue)
        {
            Write-Verbose "Replacing configuration Key ""$Key"" in configuration file ""$Path"" with Value ""$Value"""
            (Get-Content -Path $Path) | Foreach-Object { [regex]::Replace($_,$regreplace,$regvalue) } | Set-Content $Path
        }
        else
        {
            Write-Warning "Key ""$Key"" found in configuration file ""$Path"". To replace this Value specify parameter ""ReplaceExistingValue"""
        }
    } 
    elseif (-not $ReplaceOnly) 
    {    
        Write-Verbose "Adding configuration Key ""$Key"" to configuration file ""$Path"" using Value ""$Value"""
        Add-Content -Path $Path -Value $("`n" + $Key + "=" + $Value)       
    }
    else
    {
        Write-Warning "Key ""$Key"" not found in configuration file ""$Path"" and parameter ""ReplaceOnly"" has been specified therefore no work done"
    }
}

Solution 3

I'd do this:

function setConfig( $file, $key, $value )
{
  $regex = '^' + [regex]::escape($key) + '\s*=.+'
  $replace = "$key = $value"
  $old = get-content $file
  $new = $old -replace $regex,$replace 

  if (compare-object $old $new)
    {  
      Write-Host (compare-object $old $new |  ft -auto | out-string) -ForegroundColor Yellow
      $new | set-content $file
    }

    else {
           $replace | add-content $file
           Write-Host "$replace added to $file" -ForegroundColor Cyan
         }

}

Edit: added a replacement bell, and a not match whistle.

Solution 4

Change the function to this:

function Set-Config( $file, $key, $value )
{
    $regreplace = $("(?<=$key).*?=.*")
    $regvalue = $(" = " + $value)
    if (([regex]::Match((Get-Content $file),$regreplace)).success) {
        (Get-Content $file) `
            |Foreach-Object { [regex]::Replace($_,$regreplace,$regvalue)
         } | Set-Content $file
    } else {
        Add-Content -Path $file -Value $("`n" + $key + " = " + $value)          
    }
}

Then when you call the function, use this format:

Set-Config -file "divider.conf" -key "Logentrytimeout" -value "180"

Edit: I forgot your requirement of adding the line if it doesn't exist. This will check for the $key, if it exists it will set its value to $value. If it doesn't exist it will add $key = $value to the end of the file. I also renamed the function to be more consistent with power shell naming conventions.

Share:
29,818
mles
Author by

mles

Quality Assurance tester for kdice.com since 2008

Updated on July 05, 2022

Comments

  • mles
    mles almost 2 years

    I'm working on a powershell script that modifies config files. I have files like this:

    #####################################################
    # comment about logentrytimeout
    #####################################################
    Logentrytimeout= 1800
    

    who should look like this:

    #####################################################
    # comment about logentrytimeout
    #####################################################
    Logentrytimeout= 180
    disablepostprocessing = 1
    segmentstarttimeout = 180
    

    If there is a key set(Logentrytimeout), just update it to the given value. Ignore comments, where the key is mentioned(lines that start with #). The Key is case insensitive.

    If the key is not set(disablepostprocessing and segmentstarttimeout), append key and value to the file. My function so far goes like this:

    function setConfig( $file, $key, $value )
    {
      (Get-Content $file) |
      Foreach-Object {$_ -replace "^"+$key+".=.+$", $key + " = " + $value } |
      Set-Content $file
    }
    
    setConfig divider.conf "Logentrytimeout" "180"
    setConfig divider.conf "disablepostprocessing" "1"
    setConfig divider.conf "segmentstarttimeout" "180"
    
    • What is the correct regex?
    • How do I check if there was a replacement?
    • If there was no replacement: How can I append $key+" = "+$value to the file then?