Functions/Set-IniEntry.ps1
# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. function Set-IniEntry { <# .SYNOPSIS Sets an entry in an INI file. .DESCRIPTION A configuration file consists of sections, led by a `[section]` header and followed by `name = value` entries. This function creates or updates an entry in an INI file. Something like this: [ui] username = Regina Spektor <regina@reginaspektor.com> [extensions] share = extdiff = Names are not allowed to contains the equal sign, `=`. Values can contain any character. The INI file is parsed using `Split-Ini`. [See its documentation for more examples.](Split-Ini.html) Be default, operates on the INI file case-insensitively. If your INI is case-sensitive, use the `-CaseSensitive` switch. .LINK Split-Ini LINK Remove-IniEntry .EXAMPLE Set-IniEntry -Path C:\Users\rspektor\mercurial.ini -Section extensions -Name share -Value '' If the `C:\Users\rspektor\mercurial.ini` file is empty, adds the following to it: [extensions] share = .EXAMPLE Set-IniEntry -Path C:\Users\rspektor\music.ini -Name genres -Value 'alternative,rock' If the `music.ini` file is empty, adds the following to it: genres = alternative,rock .EXAMPLE Set-IniEntry -Path C:\Users\rspektor\music.ini -Name genres -Value 'alternative,rock,world' If the `music.ini` file contains the following: genres = r&b After running this command, `music.ini` will look like this: genres = alternative,rock,world .EXAMPLE Set-IniEntry -Path C:\users\me\npmrc -Name prefix -Value 'C:\Users\me\npm_modules' -CaseSensitive Demonstrates how to set an INI entry in a case-sensitive file. #> [CmdletBinding(SupportsShouldProcess=$true)] param( [Parameter(Mandatory=$true)] [string] # The path to the INI file to set. $Path, [Parameter(Mandatory=$true)] [string] # The name of the INI entry being set. $Name, [string] # The value of the INI entry being set. $Value, [string] # The section of the INI where the entry should be set. $Section, [Switch] # Treat the INI file in a case-sensitive manner. $CaseSensitive ) Set-StrictMode -Version 'Latest' Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState if( $Name -like '*=*' ) { Write-Error "INI entry name '$Name' invalid: can not contain equal sign '='." return } $settings = @{ } $lines = New-Object 'Collections.ArrayList' if( Test-Path $Path -PathType Leaf ) { $settings = Split-Ini -Path $Path -AsHashtable -CaseSensitive:$CaseSensitive Get-Content -Path $Path | ForEach-Object { [void] $lines.Add( $_ ) } } $settings.Values | Add-Member -MemberType NoteProperty -Name 'Updated' -Value $false -PassThru | Add-Member -MemberType NoteProperty -Name 'IsNew' -Value $false $key = "$Name" if( $Section ) { $key = "$Section.$Name" } if( $settings.ContainsKey( $key ) ) { $setting = $settings[$key] if( $setting.Value -cne $Value ) { Write-Verbose -Message "Updating INI entry '$key' in '$Path'." $lines[$setting.LineNumber - 1] = "$Name = $Value" } } else { $lastItemInSection = $settings.Values | ` Where-Object { $_.Section -eq $Section } | ` Sort-Object -Property LineNumber | ` Select-Object -Last 1 $newLine = "$Name = $Value" Write-Verbose -Message "Creating INI entry '$key' in '$Path'." if( $lastItemInSection ) { $idx = $lastItemInSection.LineNumber $lines.Insert( $idx, $newLine ) if( $lines.Count -gt ($idx + 1) -and $lines[$idx + 1]) { $lines.Insert( $idx + 1, '' ) } } else { if( $Section ) { if( $lines.Count -gt 1 -and $lines[$lines.Count - 1] ) { [void] $lines.Add( '' ) } if(-not $lines.Contains("[$Section]")) { [void] $lines.Add( "[$Section]" ) [void] $lines.Add( $newLine ) } else { for ($i=0; $i -lt $lines.Count; $i++) { if ($lines[$i] -eq "[$Section]") { $lines.Insert($i+1, $newLine) break } } } } else { $lines.Insert( 0, $newLine ) if( $lines.Count -gt 1 -and $lines[1] ) { $lines.Insert( 1, '' ) } } } } $lines | Set-Content -Path $Path } |