0

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
1
  • Welcome to StackOverflow! The statement "it does not work." is a little vague - can you please describe what actually happens (if anything) :) Commented Mar 21, 2019 at 11:43

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you, it works great. I am wondering how to parameterize this since I have a list of different values that need to be searched and replaced on B.txt file. For example, A.txt fontains the following values. LICENSE_KEY_LOC=test_lic DB_UNAME=test_DB DB_PASSWD=sdfssdfsf SQLSERVER_SCHEMA_NAME=dfhosdfhsdof
@signalhouse I added another code block that will allow you to add more fields to replace. Just update the $key array items. We could make this a function where you pass in parameters including the file names as well.
I am a newbie to PS. Can you please explain how your code works so that it will be a good learning for me. Thank you.
@signalhouse I added some explanation. Let me know if that is sufficient.
I really appreciate your time and answering my questions. This is really helpful.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.