Expanding variables in file contents Expanding variables in file contents powershell powershell

Expanding variables in file contents


Another option is to use ExpandString() e.g.:

$expanded = $ExecutionContext.InvokeCommand.ExpandString($template)

Invoke-Expression will also work. However be careful. Both of these options are capable of executing arbitrary code e.g.:

# Contents of file template.txt"EvilString";$(remove-item -whatif c:\ -r -force -confirm:$false -ea 0)$template = gc template.txtiex $template # could result in a bad day

If you want to have a "safe" string eval without the potential to accidentally run code then you can combine PowerShell jobs and restricted runspaces to do just that e.g.:

PS> $InitSB = {$ExecutionContext.SessionState.Applications.Clear(); $ExecutionContext.SessionState.Scripts.Clear(); Get-Command | %{$_.Visibility = 'Private'}}PS> $SafeStringEvalSB = {param($str) $str}PS> $job = Start-Job -Init $InitSB -ScriptBlock $SafeStringEvalSB -ArgumentList '$foo (Notepad.exe) bar'PS> Wait-Job $job > $nullPS> Receive-Job $job$foo (Notepad.exe) bar

Now if you attempt to use an expression in the string that uses a cmdlet, this will not execute the command:

PS> $job = Start-Job -Init $InitSB -ScriptBlock $SafeStringEvalSB -ArgumentList '$foo $(Start-Process Notepad.exe) bar'PS> Wait-Job $job > $nullPS> Receive-Job $job$foo $(Start-Process Notepad.exe) bar

If you would like to see a failure if a command is attempted, then use $ExecutionContext.InvokeCommand.ExpandString to expand the $str parameter.


I've found this solution:

$something = "World"$template = Get-Content template.txt$expanded = Invoke-Expression "`"$template`""$expanded


Since I really don't like the idea of One More Thing To Remember - in this case, remembering that PS will evaluate variables and run any commands included in the template - I found another way to do this.

Instead of variables in template file, make up your own tokens - if you're not processing HTML, you can use e.g. <variable>, like so:

Hello <something>

Basically use any token that will be unique.

Then in your PS script, use:

$something = "World"$template = Get-Content template.txt -Raw# replace <something> in template file with current value# of variable in script -> get Hello World    $template=$template.Replace("<something>",$something)

It's more cumbersome than straight-up InvokeCommand, but it's clearer than setting up limited execution environment just to avoid a security risk when processing simple template. YMMV depending on requirements :-)