4

I'm looking for a generalised solution for parsing configuration files to and from powershell objects.

In this specific instance I have an Oracle TNSNames file, however I have other configuration files which are not as well recognised and don't have parser modules already available.

VIZRTDB =
  (DESCRIPTION_LIST =
    (FAILOVER=TRUE)
    (LOAD_BALANCE=FALSE)
    (DESCRIPTION =
      (ADDRESS_LIST =
        (ADDRESS = (PROTOCOL = TCP)(HOST = 10.35.36.111)(PORT = 1521))
      )
      (CONNECT_DATA =
        (SERVER = DEDICATED)
        (SERVICE_NAME = VCPGTV)
      )
    )

    (DESCRIPTION =
      (ADDRESS_LIST =
        (ADDRESS = (PROTOCOL = TCP)(HOST = 10.109.36.112)(PORT = 1521))
      )
      (CONNECT_DATA =
        (SERVER = DEDICATED)
        (SERVICE_NAME = VCPHUB)
      )
    )
  )


VCPGTV =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = 10.35.36.111)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = VCPGTV)
    )
  )

Which I'd like to convert into an object represented by the following PSON;

@{ "VIZRTDB"= @(
        @{"DESCRIPTION_LIST"= @(
                @{"FAILOVER"= @("TRUE")},
                @{"LOAD_BALANCE"= @("FALSE")},
                @{"DESCRIPTION"= @(
                        @{"ADDRESS_LIST"= @(
                                @{"ADDRESS"= @(
                                        @{"PROTOCOL"= @("TCP")},
                                        @{"HOST"= @("10.35.36.111")},
                                        @{"PORT"= @("1521")}
                                )}
                        )},
                        @{"CONNECT_DATA"= @(
                                @{"SERVER"= @("DEDICATED")},
                                @{"SERVICE_NAME"= @("VCPGTV")}
                        )}
                )},
                @{"DESCRIPTION"= @(
                        @{"ADDRESS_LIST"= @(
                                @{"ADDRESS"= @(
                                        @{"PROTOCOL"= @("TCP")},
                                        @{"HOST"= @("10.109.36.112")},
                                        @{"PORT"= @("1521")}
                                )}
                        )},
                        @{"CONNECT_DATA"= @(
                                @{"SERVER"= @("DEDICATED")},
                                @{"SERVICE_NAME"= @("VCPHUB")}
                        )}
                )}
        )}
);
"VCPGTV"= @(
        @{"DESCRIPTION"= @(
                @{"ADDRESS"= @(
                        @{"PROTOCOL"= @("TCP")},
                        @{"HOST"= @("10.35.36.111")},
                        @{"PORT"= @("1521")}
                )},
                @{"CONNECT_DATA"= @(
                        @{"SERVER"= @("DEDICATED")},
                        @{"SERVICE_NAME"= @("VCPGTV")}
                )}
        )}
)}

Then specific values of the configuration can now be changed and written back.

I've managed to perform 95% of the conversion using [Management.Automation.psParser]::tokenize with a heap of if statements to create the PSON. It then requires minor tweaks in a text editor to get it all the way. It's then fairly easy to modify the code to produce other notations like JSON or XML.

Now that I have the configuration file tokenized, I'm looking to parse it, maybe using BNF to describe how it's built and create a representation in a PSObject.

Of course I haven't begun to investigate how to convert a PSObject back into a serialized configuration file.

These are my possible ideas;

  1. find and use equivalents of flex and bison and BNF.
  2. Find appropriate classes and methods in .net or system.management.automation.*
  3. Look at the source for cmdlets like convertfrom-json and create a custom cmdlet by modifying the parser code.
  4. convert to XML and use xml libraries for modification and XSLT to convert back into tnsnames format.

Other ideas, suggestions, libraries, methods and commands appreciated.

silicontrip
  • 906
  • 7
  • 23
  • I think option 3 may be your best bet here. Modifying an existing module to suit your needs should result in the lowest-effort, highest-success solution. Alternatively, converting to XML will open up a lot of possibilities to use existing modules, but won't converting also require some form of parser, thus invalidating the whole point? I say go for option 3. – martorad Oct 08 '21 at 07:20
  • Also take a look at [this question](https://stackoverflow.com/questions/417798/ini-file-parsing-in-powershell). It covers a very similar topic and the top answer suggests much the same - making a compact parser with regular expressions. – martorad Oct 08 '21 at 07:22

0 Answers0