You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Should we officially "deprecate" Invoke-Expression? #11662
Opening issue to get feedback per our shiproom conversation.
We have publicly stated that Invoke-Expression should be avoided. There are too many inherent security risks built into it. We continue to get questions in the Docs repo about how and why it should be used, and asks for useful examples.
We have the ability, in code, to set an attribute on the cmdlet that marks it as deprecated. Should this change be made? Are there compelling cases for the use of this cmdlet?
As someone who does use Invoke-Expression for good reason, in a small number of scripts, I'm damned if I can see why you want to take away this functionality. It exists in Powershell and exists in some form in every other scripting language. There are plenty of compatibility and performance issues with PS core that need to be addressed before you start breaking my existing scripts.
Reacted by Matthew Gray, Danijel-James Wynyard, Thomas Lee, Kris Borowinski, Bo Lingen, __, beatcracker, Flavien MICHALECZEK, Tommaso, Francisco J Calderon and 26 more
I feel deprecating like this is not all that helpful. There are, as lukeb1961 and others point out, useful reasons for using IEX. Not many, but some are certainly 'valid'.
I feel that to document the issue and warn against it is probably enough.
Reacted by Michael Klement, Keith Hill, Joel Bennett, wisemoth, Dan Komnick, flutterby, gscanlonhq, Xtrem532, Douglas Thrift and Tobias
I do not see the use in removing this, when I use it in so many scripts, and have been taught how to use this effectively in so many scripts for API calls too. Please don't remove it.
Reacted by Thomas Lee, Matthew Gray, Keith Hill, Joel Bennett, Dan Komnick, flutterby, gscanlonhq, Pavel, FireInWinter, Xtrem532 and 2 more
To be clear, we are not talking about removing Invoke-Expression. We are talking about marking it as "deprecated" and more emphatically warning against its use.
If you have compelling use cases, please share them so we can see WHY it is needed.
Reacted by Rain Sallow (/u/ta11ow), Rob Holt and Mr Beedell, Roke Julian Lockhart
I'm damned if I can see why you want to take away this functionality
Nobody is talking about removing Invoke-Expression. It’s an important primitive in PowerShell (as in any scripting language).
Here and in a few other places there has been some confusion about the meaning of the term deprecate. It simply means to express disapproval of, to disrecommend. Obsolescence is one reason to do so, but another is unnecessary danger. Invoke-Expression lies in the second category; it’s not going anywhere but it’s dangerous to use non-interactively, both from a security standpoint and an efficiency one (the whole parser/compiler toolchain has to be run again at execution time).
What we mean, on a technical level, by deprecation in this case is still not clear to me (just in documentation, or with code attributes as well?), but you’ll always be able to use Invoke-Expression (even though you shouldn’t).
As someone who does use Invoke-Expression for good reason, in a small number of scripts
Would you be able to share those scenarios/usages or adaptations of them? I think Sean Wheeler (@sdwheeler) in particular is looking for examples of iex usage.
Reacted by Michael Klement, Rain Sallow (/u/ta11ow), Sean Wheeler, Patrick Meinecke, Steve Lee, gscanlonhq and Mr Beedell, Roke Julian Lockhart
Rob Holt (@rjmholt) Thanks. Well said. The purpose of this issue was to discuss whether we should add the "deprecated" attribute to the code to enhance the warning about use of the cmdlet. This is separate from the question of how should this be documented.
I am also looking for good example for how and why you are using IEX instead of the the &-operator. If someone can provide a useful example then we can add that to the documentation. Otherwise, I will just update the documentation with a more direct recommendation for not using the cmdlet.
Reacted by Joel Bennett and Mr Beedell, Roke Julian Lockhart
Here and in a few other places there has been some confusion about the meaning of the term deprecate. It simply means to express disapproval of, to disrecommend.
Yeah literally every time the term is used. Y'all may want to adopt a template for using the term in a public space, something like:
Actually I don't know if anyone would read that. Maybe a different term with less connotation needs to be used instead.
Rob Holt (@rjmholt) Thanks. Well said. The purpose of this issue was to discuss whether we should add the "deprecated" attribute to the code to enhance the warning about use of the cmdlet. This is separate from the question of how should this be documented.
Do you mean ObsoleteAttribute? If so, the runtime warnings would get really annoying. A PSSA rule is where this would need to live imo.
Reacted by Michael Klement, Rob Holt, Kris Borowinski, Keith Hill, gscanlonhq and Tobias
whether we should add the "deprecated" attribute to the code to enhance the warning about use of the cmdlet. This is separate from the question of how should this be documented.
Thanks for that clarification, Sean Wheeler (@sdwheeler); the distinction wasn't obvious to me, and it seems that these aspects have already been conflated here, which is just as well, because I think discussing them in tandem makes sense.
As for the attribute: I agree with Patrick Meinecke (@SeeminglyScience) that a PSSA rule is the right place to warn programmatically, if desired; certainly not at runtime, as that amounts to a quasi-breaking change.
As a matter of habit, avoid use of Invoke-Expression, because there are usually more secure and robust alternatives.
If you do find that Invoke-Expression is your only choice, carefully consider the security implications: if a string from an (untrusted) outside source (e.g., user input) is passed directly to Invoke-Expression, arbitrary commands may be executed.
I think that is sufficient for this particular help topic, but separately, perhaps in a new about_Invoke-Expression conceptual help topic, we could focus on when not to use Invoke-Expression.
Specifically, we could take widespread current and historical (mis)uses of Invoke-Expression and show superior, safer alternatives.
Even in the perhaps most seductive use case - direct execution of script text downloaded from the web (e.g, iwr https://aka.ms/install-powershell.ps1 | iex) - Invoke-Expression is ultimately ill-advised, and enhancing Invoke-Command to operate on Invoke-WebRequest output should be favored - see #5909 (comment)
certainly not at runtime, as that amounts to a quasi-breaking change
While I agree that adding an ObsoleteAttribute would be annoying and probably not what we want here, I strongly disagree that it would be a breaking change.
If adding ObsoleteAttribute to anything is a breaking change, then that attribute is pointless. The whole idea of attributes is that they behave as additive metadata.
Specifically, we could take widespread current and historical (mis)uses of Invoke-Expression and show superior, safer alternatives.
Absolutely agreed.
I’d like to build a library of Invoke-Expression use-cases and document alternatives.
Unfortunately in the three issues we’ve been discussing this, we haven’t managed to record any of those uses. Hopefully we can collect some here so we can write or enhance documentation around them.
aescolastico: The & operator does not evaluate PowerShell source code stored in a string the way that Invoke-Expression does.
It only accepts a command name or path as its operand (or, alternatively a script block), so for running external programs the arguments must still be passed separately.
In fact, the only reason & is ever needed when calling external programs is a syntactic one: So that PowerShell knows you're executing a command, & must be used if the executable file path is specified in quotes and/or contains variable references / subexpressions (& "C:\Program Files\Acme\foo.exe" bar or & $HOME\bin\foo.exe bar); otherwise, just invoke the executable directly (C:\Users\jdoe\bin\foo.exe bar).
If you need to construct arguments programmatically, it is much cleaner to create them as elements of an array first, which you can then pass as a whole ($arguments = 'bar', 'baz'; foo.exe $arguments) - beware the issues around passing empty-string arguments and arguments with embedded " chars., however - see #1995.
Start-Process, which allows you to pass the list of arguments for an external executable as a single string, is the wrong tool for synchronously invoking external programs that are console applications - as you've observed, you lose integration with PowerShell's streams, even if you run the process synchronously (-Wait) in the same console window (-NoNewWindow, implied on Unix-like platforms).
The & operator does not evaluate PowerShell source code stored in a string the way that Invoke-Expression does.
It only accepts a command name or path as its operand (or, alternatively a script block), so for running external programs the arguments must still be passed separately.
Or any of the command *Info objects, or a module object and then a scriptblock, or ... well, you get the drift, there's actually a lot of things, but in all cases, the thing & applies to an an object treated literally, not parsed...
Executing a script saved to a temporary file does it entirely in memory.
Huh? Are we being super pedantic here for a reason?
Yes, it executes in memory, because that's what execution means.
But the point he's making is that downloading it to file creates a file on disk which needs cleaning up ...
* if we had support for `Invoke-WebRequest` output in `Invoke-Command` (e.g.,
`iwr https://aka.ms/install-powershell.ps1 | icm`), as proposed in [#5909 (comment)](https://github.com/PowerShell/PowerShell/issues/5909#issuecomment-461192202), and things would get even simpler if #8835 gets implemented.
* or, as an out-of-process alternative, if `pwsh -` worked properly with code piped to it (e.g.,
`irm https://aka.ms/install-powershell.ps1 | pwsh`) - see #3223.
Yes, obviously if we did either of those things, we would certainly remove the need for Invoke-Expression -- but what would be the point? If we did that, we would have simply transferred all the "inherent security risks" the OP reffered to into new places which would be much harder to flag in a code review or static analyzer.
P.S. Sean Wheeler (@sdwheeler) none of the examples I gave you made it into that "wiki" page. Note that I use "wiki" in quotes here, because those things are less editable than the source code in this repo...
Rather than extend Invoke-Expression, it makes more sense to enhance Invoke-Command, as proposed.
Invoke-Command (icm) runs code in a child scope by default, while allowing running directly in the caller's scope as an opt-in via -NoNewScope.
With an Invoke-WebRequest (iwr) output object as input, it would have to treat exit as simply exiting the child scope, i.e. it would have to treat the code as if it were a script file.
It already supports passing arguments via -ArgumentList / -Args.
However, since this is an array parameter, the syntax for multiple arguments is somewhat awkward, so making -ArgumentList a ValueFromRemainingParameters parameter should help.
Also, to recap Steve Lee (@SteveL-MSFT)'s workaround for use of Invoke-Expression (in combination with Invoke-RestMethod / irm), which works around the argument-passing issue and the scope issue, but not the exit issue:
Executing a script saved to a temporary file does it entirely in memory.
Huh? Are we being super pedantic here for a reason?
Yes, it executes in memory, because that's what execution means.
But the point he's making is that downloading it to file creates a file on disk which needs cleaning up ...
The storage for (small) temporary files is in RAM.
those things are less editable than the source code in this repo
The wiki is easier to edit when you are a member of the project.
@PowerShell/powershell-committee reviewed this 5/11/2022
We definitely do not want to deprecate Invoke-Expression - when you need it, you really need it. We also have no plans to remove it from the product, so marking it as deprecated which implies that it won't always be there is misleading. However, we do agree that we could possibly provide more guidance and information as to why it's such a dangerous tool.
Sean Wheeler (@sdwheeler) Here's my use case: I have a collection of ps files used for scripting sql db metadata, etc. that I usually run individually. I have one script that loops through all these files and calls them in order dynamically using Invoke-Expression. It would be cumbersome to convert the code within these files to functions, and I'd like to call them dynamically anyway. Is there another way to do this without iex?
I opened this issue to have a discussion about the idea. This really should have been a Discussion thread, but Discussions were not enabled at the time.
The question has been adequately answered. I don't think we should deprecate Invoke-Expression. However, we should probably have better guideance for the risks involved with using it. The article Preventing script injection attacks is a start.
Activity
mklement0 commentedon Jan 23, 2020
In the linked issue Sean Wheeler (@sdwheeler) states:
From Rob Holt (@rjmholt)'s response ibidem:
Also of interest: his comment with specific invocation scenarios, MicrosoftDocs/PowerShell-Docs#4897 (comment), where he concludes:
lukeb1961 commentedon Jan 23, 2020
As someone who does use Invoke-Expression for good reason, in a small number of scripts, I'm damned if I can see why you want to take away this functionality. It exists in Powershell and exists in some form in every other scripting language. There are plenty of compatibility and performance issues with PS core that need to be addressed before you start breaking my existing scripts.
doctordns commentedon Jan 23, 2020
I feel deprecating like this is not all that helpful. There are, as lukeb1961 and others point out, useful reasons for using IEX. Not many, but some are certainly 'valid'.
I feel that to document the issue and warn against it is probably enough.
danijeljw commentedon Jan 23, 2020
I do not see the use in removing this, when I use it in so many scripts, and have been taught how to use this effectively in so many scripts for API calls too. Please don't remove it.
sdwheeler commentedon Jan 23, 2020
To be clear, we are not talking about removing
Invoke-Expression. We are talking about marking it as "deprecated" and more emphatically warning against its use.If you have compelling use cases, please share them so we can see WHY it is needed.
rjmholt commentedon Jan 23, 2020
Nobody is talking about removing
Invoke-Expression. It’s an important primitive in PowerShell (as in any scripting language).Here and in a few other places there has been some confusion about the meaning of the term
deprecate. It simply means to express disapproval of, to disrecommend. Obsolescence is one reason to do so, but another is unnecessary danger.Invoke-Expressionlies in the second category; it’s not going anywhere but it’s dangerous to use non-interactively, both from a security standpoint and an efficiency one (the whole parser/compiler toolchain has to be run again at execution time).What we mean, on a technical level, by deprecation in this case is still not clear to me (just in documentation, or with code attributes as well?), but you’ll always be able to use
Invoke-Expression(even though you shouldn’t).Would you be able to share those scenarios/usages or adaptations of them? I think Sean Wheeler (@sdwheeler) in particular is looking for examples of
iexusage.sdwheeler commentedon Jan 23, 2020
Rob Holt (@rjmholt) Thanks. Well said. The purpose of this issue was to discuss whether we should add the "deprecated" attribute to the code to enhance the warning about use of the cmdlet. This is separate from the question of how should this be documented.
I am also looking for good example for how and why you are using IEX instead of the the &-operator. If someone can provide a useful example then we can add that to the documentation. Otherwise, I will just update the documentation with a more direct recommendation for not using the cmdlet.
SeeminglyScience commentedon Jan 23, 2020
Yeah literally every time the term is used. Y'all may want to adopt a template for using the term in a public space, something like:
Actually I don't know if anyone would read that. Maybe a different term with less connotation needs to be used instead.
Do you mean
ObsoleteAttribute? If so, the runtime warnings would get really annoying. A PSSA rule is where this would need to live imo.mklement0 commentedon Jan 23, 2020
Thanks for that clarification, Sean Wheeler (@sdwheeler); the distinction wasn't obvious to me, and it seems that these aspects have already been conflated here, which is just as well, because I think discussing them in tandem makes sense.
As for the attribute: I agree with Patrick Meinecke (@SeeminglyScience) that a PSSA rule is the right place to warn programmatically, if desired; certainly not at runtime, as that amounts to a quasi-breaking change.
As for documentation and use cases:
In the
Invoke-Expressionhelp topic, I think a general warning is sufficient, as Rob Holt (@rjmholt) proposes, along the following lines (adapted from the original MicrosoftDocs/PowerShell-Docs#2679 issue):I think that is sufficient for this particular help topic, but separately, perhaps in a new
about_Invoke-Expressionconceptual help topic, we could focus on when not to useInvoke-Expression.Specifically, we could take widespread current and historical (mis)uses of
Invoke-Expressionand show superior, safer alternatives.If we do end up agreeing on legitimate public uses worth advertising (other than during PowerShell tests, as described by Rob Holt (@rjmholt) in MicrosoftDocs/PowerShell-Docs#4897 (comment)), we can add them there as well.
Even in the perhaps most seductive use case - direct execution of script text downloaded from the web (e.g,
iwr https://aka.ms/install-powershell.ps1 | iex) -Invoke-Expressionis ultimately ill-advised, and enhancingInvoke-Commandto operate onInvoke-WebRequestoutput should be favored - see #5909 (comment)rjmholt commentedon Jan 23, 2020
In fact PSSA has had a rule to disrecommend
Invoke-Expressionfor a few years nowrjmholt commentedon Jan 23, 2020
While I agree that adding an
ObsoleteAttributewould be annoying and probably not what we want here, I strongly disagree that it would be a breaking change.If adding
ObsoleteAttributeto anything is a breaking change, then that attribute is pointless. The whole idea of attributes is that they behave as additive metadata.Anyway, that’s a tangent.
rjmholt commentedon Jan 23, 2020
Absolutely agreed.
I’d like to build a library of
Invoke-Expressionuse-cases and document alternatives.Unfortunately in the three issues we’ve been discussing this, we haven’t managed to record any of those uses. Hopefully we can collect some here so we can write or enhance documentation around them.
36 remaining items
aescolastico commentedon Dec 16, 2020
Michael Klement (@mklement0)
This is a very clear and succinct explanation. Thank you.
Do you know if there are ways of invoking scripts hosted online without using iex?
ie
DownloadString or BITs $scriptURL | Invoke-Expression
I guess you could download the script to a temp ps1 file, call that, then delete it. But I'm curious if there's a way to do it entirely in memory.
yecril71pl commentedon Dec 16, 2020
Executing a script saved to a temporary file does it entirely in memory.
Jaykul commentedon Dec 17, 2020
Michael Klement (@mklement0) wrote:
Or any of the command *Info objects, or a module object and then a scriptblock, or ... well, you get the drift, there's actually a lot of things, but in all cases, the thing
&applies to an an object treated literally, not parsed...Christopher Yeleighton (@yecril71pl) writes:
Huh? Are we being super pedantic here for a reason?
Yes, it executes in memory, because that's what execution means.
But the point he's making is that downloading it to file creates a file on disk which needs cleaning up ...
Michael Klement (@mklement0) also wrote, much earlier:
Yes, obviously if we did either of those things, we would certainly remove the need for
Invoke-Expression-- but what would be the point? If we did that, we would have simply transferred all the "inherent security risks" the OP reffered to into new places which would be much harder to flag in a code review or static analyzer.P.S. Sean Wheeler (@sdwheeler) none of the examples I gave you made it into that "wiki" page. Note that I use "wiki" in quotes here, because those things are less editable than the source code in this repo...
mklement0 commentedon Dec 17, 2020
The primary reason for not using
Invoke-Expression(iex) is that is is inadequate for running the content of script files directly from the web:exitstatement, the session exits as a whole.Rather than extend
Invoke-Expression, it makes more sense to enhanceInvoke-Command, as proposed.Invoke-Command(icm) runs code in a child scope by default, while allowing running directly in the caller's scope as an opt-in via-NoNewScope.With an
Invoke-WebRequest(iwr) output object as input, it would have to treatexitas simply exiting the child scope, i.e. it would have to treat the code as if it were a script file.It already supports passing arguments via
-ArgumentList/-Args.-ArgumentListaValueFromRemainingParametersparameter should help.Also, to recap Steve Lee (@SteveL-MSFT)'s workaround for use of
Invoke-Expression(in combination withInvoke-RestMethod/irm), which works around the argument-passing issue and the scope issue, but not theexitissue:iex "& { $(irm https://aka.ms/install-powershell.ps1) } -Preview"Needless to say, even if that fully worked as intended, it would neither be obvious nor convenient.
mklement0 commentedon Dec 18, 2020
yecril71pl commentedon Dec 20, 2020
The storage for (small) temporary files is in RAM.
The wiki is easier to edit when you are a member of the project.
JamesWTruher commentedon May 12, 2022
@PowerShell/powershell-committee reviewed this 5/11/2022
We definitely do not want to deprecate
Invoke-Expression- when you need it, you really need it. We also have no plans to remove it from the product, so marking it as deprecated which implies that it won't always be there is misleading. However, we do agree that we could possibly provide more guidance and information as to why it's such a dangerous tool.rpressman commentedon Jun 15, 2023
Sean Wheeler (@sdwheeler) Here's my use case: I have a collection of ps files used for scripting sql db metadata, etc. that I usually run individually. I have one script that loops through all these files and calls them in order dynamically using
Invoke-Expression.It would be cumbersome to convert the code within these files to functions, and I'd like to call them dynamically anyway. Is there another way to do this withoutiex?sdwheeler commentedon Jun 15, 2023
rpressman It sounds like you just want to call the scripts. You can use
&orInvoke-Commandin your loop instead.sdwheeler commentedon Jun 15, 2023
I opened this issue to have a discussion about the idea. This really should have been a Discussion thread, but Discussions were not enabled at the time.
The question has been adequately answered. I don't think we should deprecate
Invoke-Expression. However, we should probably have better guideance for the risks involved with using it. The article Preventing script injection attacks is a start.