UPDATE:
/\/\o\/\/ and Joel Bennet both chimed in and provided a much more elegant solution, just override out-default. This is really what I had wanted to do, but didn't know how. Thanks to both /\/\o\/\/ and Joel for your input. Please do check out their comments on this post. But here is the code they provided:
1: # From /\/\o\/\/
2:
3: function out-default {
4: $input | Tee-Object -var global:lastobject |
5: Microsoft.PowerShell.Utility\out-default
6: }
7:
8: # And from Joel
9: # In case you are using custom formatting
10: # You will need to override the format-* cmdlets and then
11: # add this to your prompt function
12:
13: if($LastFormat){$LastOut=$LastFormat; $LastFormat=$Null }
14:
15:
16:
A couple of days ago, an intern that is working for us, was helping me with a Powershell script to manage our Hyper V Cluster. The script ran fine but we were querying 7 different computers and then rolling up all the output into a custom object, so the thing took a while to run. It was just long enough to be annoying. During this process, he asked if there was a way to have PowerShell automatically store the output of the last command in a variable automatically.
I first went down the road of using Tee-object, According to the built-in help,
The Tee-Object cmdlet send the output of a command in two directions (like the letter T). It stores the output in a file or variable, and also sends it down the pipeline. If Tee-Object is the last command in the pipeline, the command output is displayed in the console.
Here's Tee-Object in action
PS C:\> get-process notepad | tee-object -variable note
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
50 2 1264 6596 60 0.06 6984 notepad
PS C:\> $note
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
50 2 1264 6596 60 0.06 6984 notepad
PS C:\>
But of course, my Intern (rightfully so) declares this to be unsatisfactory. He wants it to just happen automagically. Picky intern, huh?
Then on the bus ride home this afternoon, I was thinking about Jeffrey's post on Push-Noun. He basically shows us how to set up a loop that goes forever, taking input and executing it only for a specific noun in Powershell.
Considering this, I realized I could do something similar for my issue. So here's the code, stolen from Push-Noun.
function Set-LastObjectAvailable {
while ($TRUE)
{
Write-Host "[LASTOBJECT]> " -NoNewLine
$line = $Host.UI.ReadLine().trim()
switch ($line)
{
"exit" {return}
"quit" {return}
"?" {"Just type a command and the output will be displayed and stored in `$lastobject" }
{$_.StartsWith("!")}
{
$Cmd = $_.SubString(1)
Invoke-Expression $line |Tee-Object -varialbe lastobject | Out-Host
}
default {
Invoke-Expression $line |Tee-Object -Variable lastobject | out-host
}
}
}
}
And here it is in action:
PS C:\> Set-LastObjectAvailable
[LASTOBJECT]> get-process notepad
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
50 2 1264 6600 60 6984 notepad
52 2 1256 4412 58 0.06 10152 notepad
[LASTOBJECT]> $lastobject
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
50 2 1264 6600 60 6984 notepad
52 2 1256 4412 58 0.06 10152 notepad
[LASTOBJECT]> ?
Just type a command and the output will be displayed and stored in $lastobject
[LASTOBJECT]> gps notepad
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
50 2 1264 6600 60 6984 notepad
52 2 1256 4412 58 0.06 10152 notepad
[LASTOBJECT]> $lastobject.count
2
[LASTOBJECT]> exit
PS C:\>
This isn't exactly bulletproof. I think I would like to have an automatic variable that stores the output of the last command that was executed, just in case you want to mess with it and you don't want to have to run it again. Basically just override out-host to use a Tee-Object -variable lastcommandoutput or something along those lines.