The PowerShell team frequently gets questions that start out “how do I get the quoting right for…” and the answer turns out to usually be – there is a simpler way – don’t use Invoke-Expression.
The problem arises when trying to run some command external to PowerShell. Some common reasons people try Invoke-Expression:
- running some command with a space in the path
- some command takes an argument with characters that have special meaning in PowerShell, e.g. curly braces (‘{‘ and ‘}’)
- some command argument needs to use a PowerShell variable, perhaps as part of a quoted argument
If you’re just running some command external to PowerShell (exe, cmd, etc.) and you’re using Invoke-Expression, you are just making things more difficult than you need to.
So what’s wrong with Invoke-Expression then?
- It complicates getting quoting right
- It makes maintaining your script harder
- It’s slower than the alternatives
- And maybe worst of all – it opens up a script to code injection attacks
If Invoke-Expression isn’t the right way – then what is?
If you’re running some command and the command path has spaces in it, then you need the command invocation operator ‘&’ (see help about_operators, look for “call operator”).
If your command runs, but your arguments are wrong, then there is a good chance you are getting the quotes wrong. Invoke-Expression doesn’t help at all in this case, it just makes the problem more complicated.
The bottom line: Invoke-Expression is a powerful and useful command for some scenarios such as creating new scripts at runtime, but in general, if you find yourself using Invoke-Expression, you should ask yourself, or maybe a respected colleague if there is a better way.
Jason Shirk
Windows PowerShell Team
One thing I like about Invoke-Expression is that I can store the command I want it to run in a string variable, and then right before invoking it I can display the command, so in the output I can see exactly what expression is being ran. I find this very useful for troubleshooting things like calling other console executables with parameters.
For example, this is a common pattern I use:
```
[string] $command = "$someExeFilePath...
The following would be an injection attack:
function Invoke-MyCommand
{
param([string]$Name)
Write-Output "Hello $Name"
}
$Value = "`"; Remove-Item -Force -Recurse /"
Invoke-Expression "Invoke-MyCommand -Name `"$Value`"" # Deletes root filesystem
& "Invoke-MyCommand" -Name $Value # Prints 'Hello "; Remove-Item -Force -Recurse /'
In the Invoke-Expression case, some values of $Value subvert the string to bypass Invoke-MyCommand.
When & is used, that's not possible.
For recording things like the command being run,...