Occasionally, you might find yourself needing to modify a file which has an ini-type format, i.e. setting=value. For example, you might be doing an unattended install of SQL using a script which needs to modify certain values in the configuration file. Or perhaps you’re installing Micros-Retail’s XStore product which makes extensive use of files that use this format.
There are two methods I commonly use to do this type of thing, and which method I choose depends on how many values I’m modifying. If it’s just one value, I’ll use the one-liner method but if I’m modifying many values I use a custom function I wrote to do this. For the purposes of this post, let’s assume we’re customizing a SQL install and want to vary the instance name with each install.
The One-Liner Method
| 001 002 003 004 | $iniFile = 'C:\Temp\SQLInstall.ini' (Get-Content $iniFile) | foreach { $_ -replace "INSTANCENAME=.+","INSTANCENAME=MYINSTANCE"} | Set-Content $iniFile |
Pretty straightforward – any line matching “INSTANCENAME=” will be replaced with “INSTANCENAME=MYINSTANCE”. While this approach works well for replacing one value, I like to move this work to a function when I’m replacing multiple values. So let’s expand our scenario to include some other values that we want to modify and see how it looks with a function doing the work.
Using a Function
The basic approach with this function is to create a hashtable of the values we want to replace in the file and then pass the hashtable to a function which then does a search and replace and updates the file. Let’s take a look at how it all works.
Since the function is expecting to receive a hashtable, let’s start by creating the input it’s expecting and then take a look at the function.
| 001 002 003 004 005 006 007 008 009 010 011 012 013 | $iniFile = 'C:\Temp\SQLInstall.ini' $sqlInstallParams = @{ "SQLSVCACCOUNT=" = "SQLServiceAccount" "INSTANCENAME=" = "MYINSTANCE"; "SQLBACKUPDIR=" = "C:\Backups"; "SQLUSERDBDIR=" = "C:\SQL\DB"; "SQLUSERDBLOGDIR=" = "C:\SQL\DB\Logs"; "SQLTEMPDBDIR=" = "C:\SQL\TempDB"; } #Now call custom function to update the config file using the hashtable values Set-IniValue –targetFile $iniFile –hashTable$sqlInstallParams |
Nothing much to this step – we just create a basic hashtable with the values we want to replace. What I like about this approach is that it allows you to see what’s being modified in an easy-to-read format. Now let’s take a look at the function we just called in Step 1.
| 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 | function Set-IniValue ([string]$targetFile, [hashtable]$hashTable) { # Get contents of current target file $content = Get-Content $targetFile # Loop through hash table of new values and compare each line of # file with each key from hash table # If no match is found, add line to text file $hashTable.GetEnumerator() | ForEach-Object { if (!(Select-String -Pattern $_.Key -Path $targetFile -Quiet)) { $newText = $_.Key + $_.Value Add-Content $targetFile $newText } else { foreach ($line in $content) { #If line is found, replace it with key and new value if ($line -match $_.key) { $newText = $_.Key + $_.Value [IO.File]::ReadAllText($targetFile).Replace($line,$newText) ` | Set-Content $targetFile -Force } } } } } |
The function starts off by checking if any of the entries we want to modify don’t exist in the ini file. If any are found which don’t exist, they are added. It then checks for any matches with the current key of the hashtable and modifies that line with the corresponding value from the hashtable, saving the ini file after each change. And that’s pretty much it – I’ve used this function thousands of times over the years and it has never let me down!
Cleanup
Set-Content adds a blank line to the end of the file each time it is run so if you’re modifying a few values you can end up with a number of blank lines at the end of the file. If you want to clean this up, you can add this line after the function call to remove these blank lines.
| 001 | (Get-Content $iniFile) | where {$_.Trim() -ne "" } | Set-Content $iniFile |
No comments:
Post a Comment