I\'m looking for a feature comparable to Python interactive shell\'s \"_\" variable. In PowerShell I want something like this:
> Get-Something # this returns
As stated, there's no built-in support for this, but here's a simple, but suboptimal PSv3+ custom solution:
Note:
For a proper, but nontrivial solution, see BartekB's helpful answer.
There is a feature request on Github to build this functionality into a future PowerShell Core version (the current version as of this writing is PowerShell [Core] 7.0).
Add the following to your $PROFILE
file:
# Store previous command's output in $__
$PSDefaultParameterValues['Out-Default:OutVariable'] = '__'
What to name the variable - such as $__
(2 underscores) in this example - is up to you, but beware of name collisions, notably with $_
, the automatic variable that represents the input object at hand in a number of contexts.
This will capture the terminal-bound output of the most recently executed PowerShell command [that produced terminal output] in variable $__
in your interactive sessions,
by way of PowerShell's ability to globally preset parameter defaults - see Get-Help about_Parameters_Default_Values.
-OutVariable
is a common parameter designed to collect a cmdlet's / advanced function's output objects in a variable, and the above definition applies this parameter implicitly to all Out-Default
calls, which in turn is called behind the scenes whenever PowerShell outputs something to the terminal - however, note the exceptions mentioned below.
Caveats:
If needed, use $saved = $($__)
to save the captured output for later use, given that $__
is reassigned to on every command (of course, if you know ahead of time that you want to keep a command's output, use an assignment to begin with: $saved =
).
$saved = $__
does not work, because that makes $saved
point to the same [ArrayList]
instance as $__
, which gets repopulated on the next command; $(...)
(or @(...)
if you also want a single-object result to be an array) ensures that the array list's elements are collected in a new array.Output is not captured in the following cases:
Output from external programs, such as git
, because by design PowerShell passes the output streams from external programs directly to the terminal (unless they're redirected or captured), and therefore doesn't call Out-Default
. The simplest workaround is to pipe to Write-Output
(something like *>&1
to explicitly route through PowerShell streams doesn't work); e.g.:
whoami.exe | Write-Output # $__ is now populated
Output from commands that explicitly call a formatting cmdlet - Format-Custom
, Format-Hex
, Format-List
, Format-Table
, or Format-Wide
.
$PSDefaultParameterValues['Format-*:OutVariable'] = '__'
, but, unfortunately, this would collect formatting objects (instructions) rather than the original data in $__
, which is undesired.
An unsatisfying workaround is to capture Format-*
output in a different variable, which not only requires you to think about which variable you need to target, but you'll still only see formatting objects rather than data, and, since Format-*
cmdlets are involved behind the scenes even if you don't use them explicitly, the output of commands without Format-*
calls is then captured twice - once as data, in $__
, and again as formatting objects, in the other variable.Due to a design quirk, $__
will always contain an array list (of type [System.Collections.ArrayList]
), even if the previous command output only a single object. When in doubt, use $($__)
(or $__[0]
) to get a single output object as such.
Beware of commands producing very large output sets, because $__
will collect them in memory.
$__
will only capture objects output to the terminal - just like _
does in Python; a command that produces no output or $null
/ an array of $null
s leaves any previous $__
value intact.