Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I delay expansion of variables in PowerShell strings?

Whatever you want to call it, I'm trying to figure out a way to take the contents of an existing string and evaluate them as a double-quoted string. For example, if I create the following strings:

$string = 'The $animal says "meow"'
$animal = 'cat'

Then, Write-Host $string would produce The $animal says "meow". How can I have $string re-evaluated, to output (or assign to a new variable) The cat says "meow"?


How annoying...the limitations on comments makes it very difficult (if it's even possible) to include code with backticks. Here's an unmangled version of the last two comments I made in response to zdan below:

----------

Actually, after thinking about it, I realized that it's not reasonable to expect The $animal says "meow" to be interpolated without escaping the double quotes, because if it were a double-quoted string to begin with, the evaluation would break if the double quotes weren't escaped. So I suppose the answer would be that it's a two step process:

$newstring = $string -replace '"', '`"'
iex "`"$string`""

One final comment for posterity: I experimented with ways of getting that all on one line, and almost anything that you'd think works breaks once you feed it to iex, but this one works:

iex ('"' + ($string -replace '"', '`"') + '"')
like image 765
Adi Inbar Avatar asked Mar 01 '13 23:03

Adi Inbar


Video Answer


2 Answers

You could use Invoke-Expression to have your string reparsed - something like this:

$string = 'The $animal says `"meow`"'
$animal = 'cat'
Invoke-Expression "Write-Host `"$string`""

Note how you have to escape the double quotes (using a backtick) inside your string to avoid confusing the parser. This includes any double quotes in the original string.

Also note that the first command should be a command, if you need to use the resulting string, just pipe the output using write-output and assign that to a variable you can use later:

$result = Invoke-Expression "write-output `"$string`""

As noted in your comments, if you can't modify the creation of the string to escape the double quotes, you will have to do this yourself. You can also wrap this in a function to make it look a little clearer:

function Invoke-String($str) { 
    $escapedString =  $str -replace '"', '`"'
    Invoke-Expression "Write-Output `"$escapedString`""
}

So now it would look like this:

# ~> $string = 'The $animal says "meow"'
# ~> $animal = 'cat'
# ~> Invoke-String $string
The cat says "meow"
like image 136
zdan Avatar answered Oct 20 '22 02:10

zdan


You can use the -f operator. This is the same as calling [String]::Format as far as I can determine.

PS C:\> $string = 'The {0} says "meow"'
PS C:\> $animal = 'cat'
PS C:\> Write-Host ($string -f $animal)
The cat says "meow"

This avoids the pitfalls associated with quote stripping (faced by ExpandString and Invoke-Expression) and arbitrary code execution (faced by Invoke-Expression).

I've tested that it is supported in version 2 and up; I am not completely certain it's present in PowerShell 1.

like image 36
jpmc26 Avatar answered Oct 20 '22 04:10

jpmc26