arrayspowershellstring-interpolationvariable-expansion

How to Create Text Files from an Array of Values in Powershell


I have a text file "list.txt" with a list of hundreds of URL's that I want to parse, along with some common-to-all config data, into individual xml files (config files) using each value in "list.txt", like so:

list.txt contains:

line_1
line_2
line_3

The boilerplate config data looks like (using line_1 as an example):

<?xml version="1.0"?>
<Website xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Url>line_1.mydomain.com</Url>
  <Title>line_1</Title>
  <Enabled>true</Enabled>
  <PluginInName>Tumblr</PluginInName>
</Website>

So if "list.txt" contains 100 items, I want 100 config files written with the URL and Title elements individualized.

I have fumbled with several posts on reading the array and on creating text files, but I haven't been able to make any of it work.

What I tried, although it's munged at this point. I'm not sure where I started or how I got to here:

$FileName = "C:\temp\list.txt"
$FileOriginal = Get-Content $FileName

# create an empty array
Foreach ($Line in $FileOriginal)
{    
    $FileModified += $Line

    if ($Line -match $pattern) 
    {
        # Add Lines after the selected pattern 
        $FileModified += 'add text'
        $FileModified += 'add second line text'
    } 
}
Set-Content $fileName $FileModified

This is way beyond my neophyte Powershell skills. Can anyone help out?


Solution

  • You're looking for a string-templating approach, where a string template that references variables is instantiated on demand with the then-current variable values:

    # Define the XML file content as a *template* string literal
    # with - unexpanded - references to variable ${line}
    # (The {...}, though not strictly necessary here, 
    # clearly delineates the variable name.)
    $template = @'
    <code>
    <?xml version="1.0"?>
    <Website xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Url>${line}.mydomain.com</Url>
      <Title>${line}</Title>
      <Enabled>true</Enabled>
      <PluginInName>Tumblr</PluginInName>
    </Website>
    '@
    
    
    # Loop over all input lines.
    Get-Content C:\temp\list.txt | ForEach-Object {
       $line = $_ # store the line at hand in $line.
       # Expand the template based on the current $line value.
       $configFileContent = $ExecutionContext.InvokeCommand.ExpandString($template)
       # Save the expanded template to an XML file.
       $configFileContent | Set-Content -Encoding Utf8 "$line.xml"
    }
    

    Notes:

    Caveat:


    Ansgar Wiechers points out that a simpler alternative in this simple case - given that only a single piece of information is passed during template expansion - is to use PowerShell's string-formatting operator, -f to fill in the template:

    # Define the XML file content as a *template* string literal
    # with '{0}' as the placeholder for the line variable, to
    # be instantiated via -f later.
    $template = @'
    <code>
    <?xml version="1.0"?>
    <Website xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Url>{0}.mydomain.com</Url>
      <Title>{0}</Title>
      <Enabled>true</Enabled>
      <PluginInName>Tumblr</PluginInName>
    </Website>
    '@
    
    
    # Loop over all input lines.
    Get-Content C:\temp\list.txt | ForEach-Object {
       # Expand the template based on the current $line value.
       $configFileContent = $template -f $_
       # Save the expanded template to an XML file.
       $configFileContent | Set-Content -Encoding Utf8 "$line.xml"
    }
    

    Optional reading: choosing between -f and $ExecutionContext.InvokeCommand.ExpandString() for template expansion:

    Tip of the hat to Ansgar for his help.

    Using -f:

    Using $ExecutionContext.InvokeCommand.ExpandString():