First, the obligatory warning:
Invoke-Expression
(iex
) should generally be avoided and used only as a last resort, due to its inherent security risks. Superior alternatives are usually available. If there truly is no alternative, only ever use it on input you either provided yourself or fully trust - see this answer.
To add to Mathias' helpful answer and zett42's simpler alternative mentioned in a comment on the question (Invoke-Expression "$expression "
):
These solutions silence only the case where $null
or an empty string is passed to Invoke-Expression
- which may well be your intent.
To also cover the case where all error output should be silenced - whether due to invalid input or due to valid input causing errors during execution - the following variation is needed:
# Silences *all* errors.
try { Invoke-Expression $expression 2>$null } catch { }
# Alternative:
# Silences *all* errors and additionally *ignores* all *non-terminating* errors,
# i.e. not only silences them, but also prevents their recording in $Error.
# By executing inside & { ... }, the effect of setting $ErrorActionPreference is
# transitory due to executing in a *child scope*.
# Note that this also means that $expression is evaluated in the child scope.
& { $ErrorActionPreference = 'Ignore'; Invoke-Expression $expression }
Note:
First command:
The common -ErrorAction
parameter fundamentally only acts on non-terminating errors, whereas terminating ones (both statement- and script-terminating ones) must be handled with a try
/ catch
/ finally
statement.
Passing $null
or the empty string to Invoke-Expression
causes an error during parameter binding (that is the, cmdlet itself is never invoked, because invalid arguments were passed), which in effect is a statement-terminating error - hence the need for try
/ catch
.
The try
/ catch
with the empty catch
block additionally prevents script-terminating errors that result from the Invoke-Expression
call from terminating your script too (e.g, if $expression
contained something like 'throw "Fatal Error"'
Note that -ErrorAction SilentlyContinue
was replaced with 2>$null
in order to silence non-terminating errors (e.g., the error resulting from Get-ChildItem NoSuchDir
), because - inexplicably - -ErrorAction
is not effective with Invoke-Expression
(even though the -ErrorVariable
common parameter does work, for instance). See GitHub issue #19734.
Second command:
Setting the $ErrorActionPreference
preference variable to Ignore
causes all errors to be silenced, and additionally - for non-terminating errors only - prevents their recording in the automatic $Error
variable.
- If
-ErrorAction
worked in this case, -ErrorAction
would have the same effect, but would act solely on non-terminating errors, as noted. (This asymmetry between what should be equivalent mechanisms - preference variable vs. per-call common parameter, is one of the pitfalls of PowerShell's error handling - see GitHub issue #14819).
Unfortunately, (caught) terminating errors are invariably recorded in $Error
as of PowerShell 7.3.4. From what I can tell, changing this in a future version has been green-lit a while ago, but is yet to be implemented: see GitHub issue #3768
Using &
, the call operator with a script block { ... }
executes the enclosed statements in a child scope.
This causes $ErrorActionPreference = 'Ignore'
to create a local copy of the preference variable, which automatically goes out of scope when the script block is exited, thereby implicitly restoring the previous value of $ErrorActionPreference
.
However, this also means that the code executed by Invoke-Expression
executes in that child scope.
If that is undesired, forgo the & { ... }
enclosure and save and restore the previous $ErrorActionPreference
value.