signalhouse
signalhouse

Reputation: 83

Search and replace a string in PowerShell

I need to search and replace values in a file using the values from another file. For example, A.txt has a string with a value LICENSE_KEY_LOC=test_lic and B.txt contains the string LICENSE_KEY_LOC= or some value in it. Now I need to replace the complete string in B.txt with the value from A.txt. I tried the following but for some reason it does not work.

$filename = "C:\temp\A.txt"

Get-Content $filename | ForEach-Object {
    $val  = $_
    $var  = $_.Split("=")[0]
    $var1 = Write-Host $var'='
    $_ -replace "$var1", "$val"
} | Set-Content C:\temp\B.txt

Upvotes: 0

Views: 1654

Answers (1)

AdminOfThings
AdminOfThings

Reputation: 25001

You may use the following, which assumes LICENSE_KEY_LOC=string is on a line by itself in the file and only exists once:

$filename = Get-Content "c:\temp\A.txt"
$replace = ($filename | Select-String -pattern "(?<=^LICENSE_KEY_LOC=).*$").matches.value
(Get-Content B.txt) -replace "(?<=^LICENSE_KEY_LOC=).*$","$replace" | Set-Content "c:\temp\B.txt"

For updating multiple single keys/fields in a file, you can use an array and loop through each element by updating the $Keys array:

$filename = Get-Content "c:\temp\A.txt"
$Keys = @("LICENSE_KEY_LOC","DB_UName","DB_PASSWD")
ForEach ($Key in $Keys) {

    $replace = ($filename | Select-String -pattern "(?<=^$Key=).*$").matches.value
    (Get-Content "c:\temp\B.txt") -replace "(?<=^$Key=).*$","$replace" | Set-Content "c:\temp\B.txt"

}

You can put this into a function as well to make it more modular:

Function Update-Fields {
  Param(
    [Parameter(Mandatory=$true)]
    [Alias("S")]
    [ValidateScript({Test-Path $_})]
    [string]$SourcePath,
    [Parameter(Mandatory=$true)]
    [Alias("D")]
    [ValidateScript({Test-Path $_})]
    [string]$DestinationPath,
    [Parameter(Mandatory=$true)]
    [string[]]$Fields
  )

$filename = Get-Content $SourcePath
ForEach ($Key in $Fields) {

    $replace = ($filename | Select-String -pattern "(?<=^$Key=).*$").matches.value
    (Get-Content $DestinationPath) -replace "(?<=^$Key=).*$","$replace" | Set-Content $DestinationPath

}
}

Update-Fields -S c:\temp\a.txt -D c:\temp\b.txt -Fields "LICENSE_KEY_LOC","DB_UName","DB_PASSWD"

Explanation - Variables and Regex:

  • $replace contains the result of a string selection that matches a regex pattern. This is a case-insensitive match, but you can make it case-sensitive using -CaseSensitive parameter in the Select-String command.
  • (?<=^LICENSE_KEY_LOC=): Performs a positive lookbehind regex (non-capturing) of the string LICENSE_KEY_LOC= at the beginning of a line.
    • (?<=) is a positive lookbehind mechanism of regex
    • ^ marks the beginning of the string on each line
    • LICENSE_KEY_LOC= is a string literal of the text
  • .*$: Matches all characters except newline and carriage return until the end of the string on each line
    • .* matches zero or more characters except newline and carriage return because we did not specify single line mode.
    • $ marks the end of the string on each line
  • -replace "(?<=^LICENSE_KEY_LOC=).*$","$replace" is the replace operator that does a regex match (first set of double quotes) and replaces the contents of that match with other strings or part of the regex capture (second set of double quotes).
    • "$replace" becomes the value of the $replace variable since we used double quotes. If we had used single quotes around the variable, then the replacement string would be literally $replace.
  • Get-Content "c:\temp\A.txt" gets the contents of the file A.txt. It reads each line as a [string] and stores each line in an [array] object.

Explanation - Function:

  • Parameters

    • $SourcePath represents the path to the source file that you want to read. I added alias S so that -S switch could be used when running the command. It validates that the path exists ({Test-Path $_}) before executing any changes to the files.

    • $DestinationPath represents the path to the source file that you want to read. I added alias D so that -D switch could be used when running the command. It validates that the path exists ({Test-Path $_}) before executing any changes to the files.

    • $Fields is a string array. You can input a single string or multiple strings in an array format (@("string1","string2") or "string1","string2"). You can create a variable that contains the string array and then just use the variable as the parameter value like -Fields $MyArray.

Upvotes: 2

Related Questions