Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell and Regex: How to replace a INI name,value pair inside a named section?

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'):

[[ \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.

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

This is the sample ini file:

[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

$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

like image 319
Juan Antonio Tubío Avatar asked Feb 11 '23 10:02

Juan Antonio Tubío


1 Answers

Perhaps another solution is not use regex's at all and call the Windows API function WritePrivateProfileString. This is designed to edit ini files. However doing a PInvoke from PowerShell is a little tricky, you've got to compile some C# with 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)
}

However once you've go this, editing ini key value pairs is easy:

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

A couple notes on the usage. Setting a null value will delete the key. Setting a null key will delete the entire section.

Note there's a corresponding GetPrivateProfileString for reading values from an ini file. I've written the C# portion for that, I'll leave it as an exercise to reader to implement a PowerShell function for it.

like image 157
Mike Zboray Avatar answered May 12 '23 08:05

Mike Zboray