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

霸气de小男生 提交于 2019-12-01 11:41:29

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

# 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:

  • I've chosen UTF-8 encoding for the output XML files, and to name them "$line.xml", i.e. to name them for each input line and to store them in the current location; adjust as needed.

  • The template expansion (interpolation) is performed via automatic variable $ExecutionContext, whose .InvokeCommand property provides access to the .ExpandString() method, which allows performing string expansion (interpolation) on demand, as if the input string were a double-quoted string - see this answer for a detailed example.


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:

  • Advantages:

    • It is made explicit on invocation what values will be filled in.

      • Additionally, it's easier to include formatting instructions in placeholders (e.g., {0:N2} to format numbers with 2 decimal places).

      • Passing the values explicitly allows easy reuse of a template in different scopes.

    • An error will occur by default if you accidentally pass too few or too many values.

  • Disadvantages:

    • -f placeholders are invariably positional and abstract; e.g., {2} simply tells you that you're dealing with the 3rd placeholder, but tells you nothing about its purpose; in larger templates with multiple placeholders, this can become an issue.

    • Even if you pass the right number of values, they may be in the wrong order, which can lead to subtle bugs.

Using $ExecutionContext.InvokeCommand.ExpandString():

  • Advantages:

    • If your variables have descriptive names, your template will be more readable, because the placeholders - the variable names - will indicate their purpose.

    • No need to pass values explicitly on invocation - the expansion simply relies on the variables available in the current scope.

  • Disadvantages:

    • If you use a template in multiple functions (scopes), you need to make sure that the variables referenced in the template are set in each.

    • At least by default, $ExecutionContext.InvokeCommand.ExpandString() will quietly ignore nonexistent variables referenced in the template - which may or may not be desired.

    • Generally, you manually need to keep your template in sync with the code that sets the variables referenced in the template, to ensure that the right values will be filled in (e.g., if the name of a referenced variable changes, the template string must be updated too).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!