Powershell and Regex: how to replace the INI name, a pair of values ​​inside a named section?

I play with INI files in PowerShell v.2.0

I want to modify an existing name = value pair inside a specific section. For example: I want to set color = blue for the [Sky] section without changing with the same name, a pair of values ​​inside the [Home] section.

I have a regex to get only the full section that I want to change ("sky"):

[[ \t]*Sky[ \t]*\](?:\r?\n(?:[^[\r\n].*)?)*

I also have another expression that works, but only if Color is the first name, the value of the section pair.

\[[ \t]*Sky[ \t]*\][.\s]*Color[ \t]*=[ \t]*(.*) 

This is an example ini file:

[Sky]
Size=Big
Color=white

[Home]
Color=Black

PS: This is the code I'm using now to replace all name = value instances in the ini file, and I want to update a new expression to replace it only in this section

$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 is perfect! Here's the code in Gist: ReplaceIniValue_Sample2.ps1

Decision

@Matt is another approach:
Here is the complete code: ReplaceIniValue_Sample1.ps1

I'm looking for a regex-based solution, but the @mark z clause works fine and is a great example of API calls from Windows PowerShell. Here is the complete code with a few minor tweaks : ReplaceIniValue_Sample3.ps1

+4
3

: , RegEx , , [Sky], -, '[' , , .

$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

: RegEx101 RegEx: https://regex101.com/r/uC0cC3/1

Edit2: -Raw -ReadCount 0 v2.

Edit3: , , , . , -ReadCount 0 , -Raw, . , . , , -replace .

+2

, regex Windows API WritePrivateProfileString. ini . PInvoke PowerShell , # Add-Type:

$source = @"

    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;

    public static class IniFile
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool WritePrivateProfileString(string lpAppName,
           string lpKeyName, string lpString, string lpFileName);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        static extern uint GetPrivateProfileString(
           string lpAppName,
           string lpKeyName,
           string lpDefault,
           StringBuilder lpReturnedString,
           uint nSize,
           string lpFileName);

        public static void WriteValue(string filePath, string section, string key, string value)
        {
            string fullPath = Path.GetFullPath(filePath);
            bool result = WritePrivateProfileString(section, key, value, fullPath);
        }

        public static string GetValue(string filePath, string section, string key, string defaultValue)
        {
            string fullPath = Path.GetFullPath(filePath);
            var sb = new StringBuilder(500);
            GetPrivateProfileString(section, key, defaultValue, sb, (uint)sb.Capacity, fullPath);
            return sb.ToString();
        }
    }
"@

Add-Type -TypeDefinition $source

function Set-IniValue {

   param (
       [string]$path,
       [string]$section,
       [string]$key,
       [string]$value
   )

   $fullPath = [System.IO.Path]::GetFullPath($(Join-Path $pwd $path))
   [IniFile]::WriteValue($fullPath, $section, $key, $value)
}

, , ini :

Set-IniValue -Path "test.ini" -Section Sky -Key Color -Value Blue

. . .

GetPrivateProfileString INI . # , PowerShell .

+3

, .

@"

#This line have a white line after and before

[Sky]
Size=Big

Color=White

[Home]
Color=Black
#Last line
"@ | Set-content c:\temp\test.ini

. .

$edits = (Get-Content c:\temp\test.ini) -join "`r`n" -split '\s(?=\[.+?\])' | ForEach-Object{
    If($_ -match '\[sky\]'){
        $_ -replace '(color=)\w+', '$1Blue'
    } Else {
        $_
    }
}

$edits | Set-Content c:\temp\test.ini

ini , Get-Content, -join . -split, [parts]. , [sky]. , replace "" .

, , . [word], , , , .

I did not understand this until Juan Antonio Tubio realized that subsequent passages of the code created additional spaces. That was how I split the file to parse it. I fixed this by appending the array to one line before I output the file. In addition, to simplify the subsequent tests, I also made a function.

function Set-INIKey{
    param(
        [string]$path,
        [string]$section,
        [string]$key,
        [string]$value
    )

    $edits = (Get-Content $path) -join "`r`n" -split '\s(?=\[.+?\])' | ForEach-Object{
        If($_ -match "\[$section\]"){
            $_ -replace "($key=)\w+", "`$1$value"
        } Else {
            $_
        }
    }

    -join $edits | Set-Content $path
}

Therefore, when I used this in several tests, extra spaces were no longer present.

Set-INIKey "c:\temp\test.ini" "Sky" "Color" "Blue"
+1
source

All Articles