Question:
I’m playing with INI files in PowerShell v.2.0
I want to change a existing name=value pair inside a concrete section. By example: I want to set color=Blue for section [Sky] without change the same name,value pair inside [Home] Section.
I have the regex to get just the full section I want to change (‘sky’):
1 2 |
[[ \t]*Sky[ \t]*\](?:\r?\n(?:[^[\r\n].*)?)* |
I have also another expression that works, but only if Color is the first name,value pair of the section.
1 2 |
\[[ \t]*Sky[ \t]*\][.\s]*Color[ \t]*=[ \t]*(.*) |
This is the sample ini file:
1 2 3 4 5 6 7 |
[Sky] Size=Big Color=white [Home] Color=Black |
PS: This is the code that i’m using now to replace all instances of a name=value in the ini file and i want to update with the new expression to replace only in a given section
1 2 3 4 5 6 7 8 9 10 11 |
$Name=Color $Value=Blue $regmatch= $("^($Name\s*=\s*)(.*)") $regreplace=$('${1}'+$Value) if ((Get-Content $Path) -match $regmatch) { (Get-Content -Path $Path) | ForEach-Object { $_ -replace $regmatch,$regreplace } | Set-Content $Path } |
Edit:
@TheMadTechnician solution it’s perfect 🙂
Here the code in a Gist: ReplaceIniValue_Sample2.ps1
@Matt solution is another approach:
Here is the complete code: ReplaceIniValue_Sample1.ps1
I’m looking for a solution based on regular expressions, but @mark z proposal works perfectly and is a great example of API calls from Windows PowerShell. Here is the complete code with a few minor adjustments: ReplaceIniValue_Sample3.ps1
Answer:
Here’s what I’d do: Read the whole file as a single string, then change your RegEx match so that it’s a multiline match, then do a reverse lookup for [Sky] followed by capturing anything except ‘[‘ up to the option you want to change, capture everything on the other side of the equal sign in a second capture group, and replace as needed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$Path="C:\Temp\prueba.ini" @" [Sky] Size=Big Color=White [Home] Color=Black "@ | Set-content $Path $Section="Sky" $Name="Color" $Value="Blue" (Get-Content $Path) -join "`n" -replace "(?m)(?<=\[$Section\])([^\[]*$Name=)(.+?)$","`$1$Value" | Set-Content $Path |
Edit: Almost forgot the obligatory RegEx101 link to explain my RegEx: https://regex101.com/r/uC0cC3/1
Edit2: Changed -Raw
to -ReadCount 0
for v2 compatibility.
Edit3: Ok, I evidently remembered incorrectly. I thought that -ReadCount 0
worked the same as -Raw
but it does not. Updated code to fix this. Now it joins the array of strings with new line characters basically turning it into a here-string and now the -replace
works as expected.