PowerShell: Is there an automatic variable for the last execution result?

Solution 1:

No there is not automatic variable like that.

You have to do:

$output = Get-Something
$output
$anObj = $output

to get the behaviour

Solution 2:

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.

  • GitHub feature request #7853 asks for building this functionality into a future PowerShell Core version (the current version as of this writing is PowerShell (Core) 7.2).


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 = $__.Clone() 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 = <command>).

    • Note that just $saved = $__ does not work, because that makes $saved point to the same [ArrayList] instance as $__, which gets repopulated on the next command.
  • 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.

      • It's tempting to attempt to fix that with $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, $__ always contains 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 $nulls leaves any previous $__ value intact.