PowerShell, Load Configuration From XML File

When you need create a script file with a complex parameter set, sometimes a better option can be load a file with configuration instead of using a large set of arguments on script invoke.

I found this solution when I faced a very small problem, I need create a script that can replace a XML Element in a target document using another XML Document. basically it’s a template file, and its associated segments.

By Example I had a template document with  this content.

<?xml version="1.0"?>
<sections>
    <section_a>
    </section_a>
    <section_b>
    </section_b>
</sections>

and two files with the actual content of each section.

<?xml version="1.0"?>
<section_a>
    <content_a/>
</section_a>
<?xml version="1.0"?>
<section_b>
    <content_b/>
</section_b>

And, finally a configuration file, that define the map, SectionName -> FileName, this map allow to define a variable number of sections to be replaced, using files, this configuration file was intentionally defined with the same format of the App.config or Web.Config  AppSettings section.

<?xml version="1.0"?>
<configuration>  
  <appSettings>
    <add key="section_a" value="sectiona.xml" />    
    <add key="section_b" value="sectionb.xml" />            
  </appSettings>
</configuration>

So the first step was load section map file, the configuration, that file defines which segment file is used to replace a section).

function LoadSectionConfigMap( $configurationFilePath )
{
    $result = @{}
    $config = [xml](get-content $configurationFilePath)
    
    $configDir = Split-Path $configurationFilePath -parent
    
    foreach ($addNode in $config.configuration.appsettings.add) {
     if ($addNode.Value.Contains(‘,’)) {
      # Array case
      $value = $addNode.Value.Split(‘,’)
      for ($i = 0; $i -lt $value.length; $i++) { 
        $value[$i] = $value[$i].Trim() 
      }
     }
     else {
      # Scalar case
      $value = $addNode.Value
     }
     $key = $addNode.Key     
     $result[$key] = Join-Path $configDir $value     
    }
    return $result
}

So, if we had a folder called “C:temp” with the above files on it.

we can call the function with this parameter “C:tempsectionMap.xml” and we get a the name of the section related to the filename with the actual content of that section.

The function to load the configuration from the XML File is pretty specific to this case, but can be generalized to be used on any kind of configuration value.

function LoadSectionConfigMap( $configurationFilePath )
{
    $result = @{}
    $config = [xml](get-content $configurationFilePath)
             
    foreach ($addNode in $config.configuration.appsettings.add) {
     if ($addNode.Value.Contains(‘,’)) {
      $value = $addNode.Value.Split(‘,’)
      for ($i = 0; $i -lt $value.length; $i++) { 
        $value[$i] = $value[$i].Trim() 
      }
     }
     else {
      $value = $addNode.Value
     }
     $key = $addNode.Key     
     $result[$key] = $value    
    }
    return $result
}

so we can use it to load any value.

this will be the first post of a serie, the next one will be focused how to replace the sections with the content in the segment files.