Hello,
I think that all of us reading this article already know what an Ini file is. Though there may be many uses to those kinds of files, they are kind of hard to deal with when we want to access a value. I started to write this script to see if we can parse an ini file and solve, even if by little, the problem.
The problem with .ini files compared with xml file is that there are no tags to access elements.
Here’s an example of INI file content:
; last modified 1 April 2001 by John Doe
[owner]
name=John Doe
organization=Acme Widgets Inc.
[database]
; use IP address in case network name resolution is not working
server=192.0.2.62
port=143
file="payroll.dat"
Which lines are considered as commented lines?
Lines which begin with “;” are considered as commented lines
$COMMENT_CHARACTERS = ";"
Which lines are considered as a Section header?
A section structure is always something like: [mySection01]
So, It may contains Capital letter, number and specials characters. These are the specials characters supported by this script: _ %<>/#+- , blank space is also supported. In my script, this is done by specifying a regex chains:
$HEADER_REGEX = "\[+[A-Z0-9._ %<>/#+-]+\]"
So what do we have in the Script?
- First Step:
Useful lines are selected and set in a PScustomObject
$CONTENT_USEFUL = $ContentFile | Where { ($_ -notmatch "^\s*$COMMENT_CHARACTERS") -or ($_ -notmatch "^$COMMENT_CHARACTERS") }
$ALL_SECTION_HASHTABLE = $CONTENT_USEFUL | Where { $_ -match $HEADER_REGEX } | % { [PSCustomObject]@{ Section= $_ ; Index = [Array]::IndexOf($CONTENT_USEFUL,$_) }}
- Second Step
Each lines that doesn’t match the header section’s regex are stored in $SECTION_STRING and then processed
We take the index of the next section and subtract it with the current section to get the content between those two sections. However, there are cases when there is nothing between two sections (I already took that into account in the script so don’t worry).
$SECTION_STRING = $CONTENT_USEFUL | Select-Object -Index (($SECTION_INI[$i-1].Index+1)..($SECTION_INI[$i].Index-1)) | Out-String
$CONVERTED_OBJ = convertfrom-stringdata -stringdata $SECTION_STRING
The magic function here is convertfrom-stringdata -stringdata
It really made my day.
Here is a little example of the capabilities of this function:
$myString= "
server=192.0.2.62
port=143
file='payroll.dat'
"
ConvertFrom-StringData -StringData $myString
Here is the output
As we can see, this function converts a string that contains one or more key and value pairs into a hashtable.
- Last step
We put all of those elements into a big Array. :)
The result looks like this:
Section: Content:
---------- -------------
[owner] {name,organization}
[database] {server,port,file}
Here is the complete script:
Yeahh nice post my colleague :-)
ReplyDeleteHey,
ReplyDeleteI need a slightly different result so here's my code. I used a few differnet pages including yours to help me with this. Thanks.
Function Parse-IniFile ($file)
{
<#
Gratitude to these people / pages
Gottfried Bregenzer1 -- https://community.idera.com/database-tools/powershell/ask_the_experts/f/learn_powershell_from_don_jones-24/22806/convert-a-ini-file-to-xlm-array-filter-specific-values-in-the-xml-array-and-write-the-output-to-xml-and-back-to-ini-file
dev4sys -- https://www.dev4sys.com/2016/05/how-to-parse-ini-file-in-powershell.html
#>
$IniSection = ""
$IniFileTable = @()
switch -regex -file $file
{
"^\[(.+)\]$"
{
$IniSection = $matches[1].Trim()
#write-host "Section: $section"
}
'^\s*([^#].+?)\s*=\s*(.*)'
{
$name,$value = $matches[1..2]
$IniParsedRecord = New-Object PSObject
$IniParsedRecord | Add-Member -type NoteProperty -name Section -value $IniSection
$IniParsedRecord | Add-Member -type NoteProperty -name ItemName -value $name
$IniParsedRecord | Add-Member -type NoteProperty -name ItemValue -value $value
$IniFileTable += $IniParsedRecord
}
}
Return $IniFileTable
}