Never Lose Your Work at the Console

If you’re like me, every once in a while you have a dash of brilliance, write the perfect one-liner, but forget to record your work. You know you solved this problem already, but none of your documentation bears witness. You’re a trapeze artist without a safety net when you work at the console. Now, between transcripts, saving previous output, and HistoryPX, you won’t have to worry.

Transcripts

Transcripts are exactly what you think they are. They are a character for character representations of what happened at the console. To start saving a transcript you run the Start-Transcript cmdlet with a filepath. Transcripts will store all of your commands as well as whatever is written to the pipeline using Out-Default. Stopping a transcript is as easy as running Stop-Transcript.

If you ever log a bug report with any open-source modules on GitHub attaching your transcript log is a great idea. The developer gets more than a vague error report and you’re more likely to get your bug squashed.

If your as lazy as I am, you likely don’t want to have to remember to run a transcript cmdlet at the beginning of every PowerShell session. That sounds too much like work. Instead, add the following code to your PowerShell profile.

$Date = (Get-Date -format "yyyy-MM-dd-hh-mm-ss")
Start-Transcript -Path ~\Documents\WindowsPowerShell\Transcripts-$Date.txt

No more remembering and you have a log of all of your work. Your transcripts will be stored in the Transcripts folder in WindowsPowerShell.

Out-Variable

For something less formal than a transcript you can use the OutVariable parameter for the Out-Default cmdlet. Out-Default runs whenever there is something left over in the pipeline. That is what writes to the console.

We can leverage a little-known feature called Default Parameter Values to save the output. Here, you specify what cmdlet, what parameter, and what value to pass to the parameter. Now whenever the cmdlet is run, the value is passed to the specified parameter.

PS:> $PSDefaultParameterValues['out-default:outvariable'] = 'PreviousOutput'

PS:> Get-Process -Name PowerShell

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    375      24    48072      90832       0.39   8116   8 powershell
    594      34    87088     132444       3.33   9196   8 powershell
    380      24    46064      88872       0.48   9336   8 powershell
    669      34    66748     110692       2.89  10784   8 powershell


PS:> $PreviousOutput

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    375      24    48072      90832       0.39   8116   8 powershell
    594      34    87088     132444       3.33   9196   8 powershell
    380      24    46064      88872       0.48   9336   8 powershell
    669      34    66748     110692       2.94  10784   8 powershell

After running the above code you can now retrieve any previous pipeline output that was sent to the console screen. This is also something you can put in your profile so you don’t have to remember.

HistoryPX

Kirk Munro has written a beautiful module for handling your PowerShell history. There is even talks with bringing HistoryPX into PowerShell so it is installed by default.

For now though, you install it using the following. Note: SnippetPx is also a module written by Kirk.

Install-Module -AllowClobber HistoryPx,SnippetPx

Then, all you have to do import the HistoryPx module and you’re off to the races. Notice how once you import the module you automatically get the previous output saved in the $__ variable. You also get the ability to grab the output from previous commands using Get-History AND you get measure-command statistics. All for simply importing HistoryPx.

Git:> Import-Module historypx
Git:> get-process -name powershell

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    375      24    48040      90816       0.39   8116   8 powershell
    594      34    87080     132440       3.33   9196   8 powershell
    380      24    46032      88856       0.48   9336   8 powershell
    889      36    73336     118452       3.97  10784   8 powershell


PS:> $__

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    375      24    48040      90816       0.39   8116   8 powershell
    594      34    87080     132440       3.33   9196   8 powershell
    380      24    46032      88856       0.48   9336   8 powershell
    889      36    73336     118452       3.97  10784   8 powershell


PS:> Get-History

  Id CommandLine                    Duration       Success #Err #Out #Src Output
  -- -----------                    --------       ------- ---- ---- ---- ------
  18 Clear-History                  00:00:00.002   True
  19 Import-Module historypx        00:00:00.010   True
  20 get-process -name powershell   00:00:00.021   True         4    1    {System.Diagnostics.Process (powershell),...
  21 $__                            00:00:00.019   True         4    1    {System.Diagnostics.Process (powershell),...


PS:> (Get-History -Id 20).Output

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    375      24    48040      90816       0.39   8116   8 powershell
    594      34    87080     132440       3.33   9196   8 powershell
    380      24    46032      88856       0.48   9336   8 powershell
    889      36    73336     118452       4.27  10784   8 powershell

With DefaultParameters, transcripts, and HistoryPx you no longer have an excuse to lose your work.