Powershell text/html templates that include loops Powershell text/html templates that include loops powershell powershell

Powershell text/html templates that include loops


I am really interested in a good answer for this but I will expand on my suggestion in the comment. I'm sure you are capable of doing this yourself but this could be of value to someone.

If your file contained

<div>title</div><ul>${list}</ul>

Then we could do this to populate the list

$list = ("First Point", "Second Point" | ForEach-Object{"`t<li>$_</li>"}) -join "`r`n"$template = Get-Content 'c:\temp\docs\template.txt' -raw$ExecutionContext.InvokeCommand.ExpandString($template)

Yes I know this is not exactly what you are asking but it does have a similar result.

Why not turn the whole file into code instead?

Disclaimer: I would like to point out that expanding strings and executed code from files are two different things. What if someone put malicious code in your template file? You could blindly execute it. Realistic problem? No. Possible catastrophe? Maybe.

I update a small part of your sample edit to prove the method. Yes the HTML is malformed and sucks. It exists to show what I mean.

Sample File

'<div class="container-fluid">''    <div class="page-header">'"        <h1>$name</h1>""        <p class=`"lead`">$synopsis</p>"'    </div>''    <tr>'foreach($param in $parameters){"        <td>$($param.Name)</td>""        <td>$($param.Description)</td>"}'    </tr>'

I picked that snippet since you see a simple variable, simple variable in quotes and a loop structure. I have single quotes around most of the lines since they will just be sent as standard string output. So, with that, we use the following code:

$name = "Matt"$synopsis ="Ughhh... stuff"$parameters = 1,2 | Foreach-object{[pscustomobject]@{Name="$_ Factory";Description="$_ Apples"}}$template = Get-Content 'c:\temp\docs\template.txt' -rawInvoke-Expression $template

Which nets the following, again awful, output.

<div class="container-fluid">    <div class="page-header">        <h1>Matt</h1>        <p class="lead">Ughhh... stuff</p>    </div>    <tr>        <td>1 Factory</td>        <td>1 Apples</td>        <td>2 Factory</td>        <td>2 Apples</td>    </tr>


I know this is an old question, and you have a good workaround, but I thought others might be interested in the answer. What you had in the original question was very close.

This works

template.txt

<div>title</div><ul>$(${points} | ForEach {@"    <li>$_<\li>"@})</ul>

PowerShell

$points = 'First Point', 'Second Point', 'Third Point'$template = Get-Content 'template.txt' -Raw$expanded = $ExecutionContext.InvokeCommand.ExpandString($template)$expanded

Output

<div>title</div><ul>    <li>First Point<\li>    <li>Second Point<\li>    <li>Third Point<\li></ul>

You got the one trick, using $( on the second line of the template to open an expression. But your expression didn't use the proper syntax. The second trick is to keep using ExpandString like you did in the working example you provided. Once the proper syntax is provided in the template, it will be correctly evaluated by ExpandString (because were using an interpolated strings expression). The output matches your expected output (except I left in "Third Point" which I added while testing and fixing the formatting).