0

I have following beggining of a Powershell script in which I would like to replace the values of variables for different enviroment.

$SomeVar1 = "C:\path\to\file\a"
$SomeVar1 = "C:\path\to\file\a" # Copy for test - Should not be rewriten
$SomeVar2 = "C:\path\to\file\b" 
# Note $SomeVar1 = "C:\path\to\file\a" - Should not be rewriten

When I run the rewrite script, the result should look like this:

$SomeVar1 = "F:\different\path\to\file\a"
$SomeVar1 = "C:\path\to\file\a" # Copy for test - Should not be rewrite
$SomeVar2 = "F:\different\path\to\file\b" 
# Note $SomeVar1 = "C:\path\to\file\a" - Should not be rewriten

Current script that does(n't) rewrite:

$arr = @(
   [PSCustomObject]@{Regex = '$SomeVar1 = "';  Replace = '$SomeVar1 = "F:\different\path\to\file\a"'}
   [PSCustomObject]@{Regex = '$SomeVar2 = "';  Replace = '$SomeVar1 = "F:\different\path\to\file\b"'}
)

for ($i = 0; $i -lt $arr.Length; $i++) {

   $ArrRegex = [Regex]::Escape($arr[$i].Regex)
   $ArrReplace = $arr[$i].Replace
   
   # Get full line for replacement
   $Line = Get-Content $Workfile | Select-String $ArrRegex | Select-Object -First 1 -ExpandProperty Line

   # Rewrite part
   $Line = [Regex]::Escape($Line)
   $Content = Get-Content $Workfile
   $Content -replace "^$Line",$ArrReplace | Set-Content $Workfile
}

This replaces all the occurences in file on the start of the line (and I need only the 1st one) and doest not replace the one in Note which is okay.

Then I found this Powershell: Replace last occurence of a line in a file which does the exact oposite of what I need, only rewrites the last occurence of the string and it does it in the Note aswell and I would somehow like to change it to do the opposite - 1st occurence, line begining (Wont target the Note)

Code in my case looks like this:

# Rewrite part
$Line = [Regex]::Escape($Line)
$Content = Get-Content $Workfile -Raw
$Line = "(?s)(.*)$Line"
$ArrReplace = "`$1$ArrReplace"
$Content -replace $Line,$ArrReplace | Set-Content $Workfile

Do you have any recommendations on how to archive my goal, or is there a more sothisticated way to replace variables for powershell scripts like this?

Thanks in advance.

  • Why are you scripting this? Why not just open in the ISE/VSCode, etc., and change it? If you have many of these, I get that, but that is not what you are showing. – postanote Dec 07 '22 at 20:48
  • @postanote Hi, this is concept for variable rewrite that will be used in many scripts accross few envirometns and I would like to keep only one version of the script and rewrite variables during release process – Daniel Procházka Dec 08 '22 at 11:30

3 Answers3

1

So I finally figured it out, I had to add Select-String "^$ArrRegex" during $Line creation to exclude any string that were on on line beggining and then use this Regex to do the job: ^(?s)(.*?\n)$Line

In my case it does the following: Only selects 1st occurnece on the beggining of the line and replaces it. It ignores everything else and when re-run, does not rewrite others. The copies of vars will not really exist in final version and will be set once like $Var1 = "Value" and never changed during script, but I wanted to be sure that I won't replace something by mistake.

The final replacing part does look like this:

for ($i = 0; $i -lt $arr.Length; $i++) {
   $ArrRegex = [Regex]::Escape($arr[$i].Regex)
   $ArrReplace = $arr[$i].Replace
   $Line = Get-Content $Workfile | Select-String "^$ArrRegex" | Select-Object -First 1 -ExpandProperty Line
   $Line = [Regex]::Escape($Line)
   $Line = "^(?s)(.*?\n)$Line"
   $ArrReplace = "`$1$ArrReplace"
   $Content -replace $Line, $ArrReplace | Set-Content $Workfile
}
0

You could possibly use flag variables like below to only do the first replacement for each of your regex patterns.

$Altered = Get-Content -Path $Workfile |
    Foreach-Object {
        if(-not $a) { #If replacement hasn't been done, replace
            $_ = $_ -replace 'YOUR_REGEX1','YOUR_REPLACEMENT1'
            if($_ -match 'YOUR_REPLACEMENT1') { $a = 'replacement done' } #Set Flag
        }
        if(-not $b) { #If replacement hasn't been done, replace
            $_ = $_ -replace 'YOUR_REGEX2','YOUR_REPLACEMENT2'
            if($_ -match 'YOUR_REPLACEMENT2') { $b = 'replacement done' } #Set Flag
        }
        $_ # Pipe back to $Altered
    } 
$Altered | Set-Content -Path $WorkFile
Grok42
  • 196
  • 4
0

Just reverse the RegEx, if that is what you are after:

Clear-Host
@'
abc
abc
abc
'@ -replace '^(.*?)\babc\b', '$1HelloWorld'

# Results
<#
HelloWorld
abc
abc
#>
postanote
  • 15,138
  • 2
  • 14
  • 25