Skip to content

Instantly share code, notes, and snippets.

@SQLvariant
Last active October 11, 2020 19:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SQLvariant/5d01a508574455412ec8d6c712c06cec to your computer and use it in GitHub Desktop.
Save SQLvariant/5d01a508574455412ec8d6c712c06cec to your computer and use it in GitHub Desktop.
I wish there was some kind of -GridThru functionality (`Out-GridView` with `-PassThru`) built into the Get-History command

Please 'Code Golf' this snippet

I like to get my code 'working' and then see if I can shorten the code, make it run faster, or maybe just reduce the number of variables I'm using.

However, sometimes I end up breaking things. At which point, I want to jump back to a version of the code that executed successfully. To do that, I sometimes use the code block below:

Get-History |
SELECT * |
Out-GridView -PassThru |
foreach { $_.CommandLine } | clip

I wish there was some kind of -GridThru functionality (Out-GridView with -PassThru) built into the Get-History command, but there isn't. I also realize I can put this into a function to shorten things up, but then I have to remember to run that function where I'm going to use it.

So with that said, I'm curious how much shorter I coule get this command (like swapping out Out-GridView with ogv)?

Can you please suggest the shortest thing you can come up with?

Functionality goals

  • Allow the user to see all of their command execution history
  • Allow the user to select the full command syntax of one (or maybe more) or their previously executed commands
  • Send the resulting selection to the clipboard

Note: When the code gets to the clipboard, I want to be able to paste it right back into my PowerShell editor and run it, without any extra steps.

Additional Note: To help me find the correct piece of code to grab, I need to tell that it had completed successfully (ExecutionStatus -eq 'Completed'), or just have that pre-filtered for me.

I can't wait to see what y'all come up with. I will update this gist with the 'leading' (read: shortest working) version of the code, and let everyone know who came up with it. Thanks in advance to everyone who tries! :-)

@SteveL-MSFT
Copy link

Is Select * really needed? Also, use set-clipboard instead of clip.exe to make it cross platform:

history|ogv -p|%{$_.commandline|set-clipboard}

@SQLvariant
Copy link
Author

Is Select * really needed?

Great point @SteveL-MSFT, I guess I could have amplified that a little better. I use the SELECT * because I'm trying to find the last time I ran the command successfully.

Although, would if be possible to modify the default output of Get-History to include the ExecutionStatus property?

@jdhitsolutions
Copy link

Not necessarily short, but it is a one-liner

((h).where({$_.executionstatus -match "f"}).commandline|ogv -p).foreach{$_ }|Set-Clipboard

@jdhitsolutions
Copy link

Or if you are using the history file with PSReadline, open up that and copy/paste

notepad (Get-PSReadLineOption).historysavepath

@kozloski
Copy link

kozloski commented Jul 7, 2020

If you move the clip (or set-clipboard) outside of the foreach-object, it will capture all commands selected in the gridview, rather than just the last output from the gridview.

h|ogv -p|%{$_.commandline}|clip

@jdhitsolutions
Copy link

Grab this version of Get-History from https://gist.github.com/jdhitsolutions/853492171218817ccaaa9fea9213c133.

hh -es c|ogv -p|%{$_.commandline}|scb

You should have an alias of scb for Set-Clipboard.

@SQLvariant
Copy link
Author

Or if you are using the history file with PSReadline, open up that and copy/paste

notepad (Get-PSReadLineOption).historysavepath

Not quite the direction I was looking for because it loses the context of when the command was executed, and if it was successful (unless there's another way to leverage PSReadLineOption I'm not familiar with). But wow, I learned something new today! 😀

@SQLvariant
Copy link
Author

If you move the clip (or set-clipboard) outside of the foreach-object, it will capture all commands selected in the gridview, rather than just the last output from the gridview.

h|ogv -p|%{$_.commandline}|clip

Great catch, I will update my code block above. Thanks for pointing this out @kozloski

@SQLvariant
Copy link
Author

Grab this version of Get-History from https://gist.github.com/jdhitsolutions/853492171218817ccaaa9fea9213c133.

hh -es c|ogv -p|%{$_.commandline}|scb

You should have an alias of scb for Set-Clipboard.

This works as advertised. However, adding a function is a step I'm trying to avoid. @jdhitsolutions if you just propose that -es c bit as a PR to the Get-History cmdlet, I think this will be perfect 😋

@SQLvariant
Copy link
Author

SQLvariant commented Jul 7, 2020

Not necessarily short, but it is a one-liner

((h).where({$_.executionstatus -match "f"}).commandline|ogv -p).foreach{$_ }|Set-Clipboard

@jdhitsolutions I really like this one, even though I'm pretty sure I will never be able to memorize it 😁
Unfortunately, I can't get it to work as written. It looks like this part .where({$_.executionstatus -match "f"}) is filtering out 100% of my history. Is this maybe to do with the same reason I have to pipe to SELECT * in my original version?

@jdhitsolutions
Copy link

Try

((h).where({$_.executionstatus -match "c"}).commandline|ogv -p).foreach{$_ }|Set-Clipboard

My example was looking for failed. This is looking for "completed". You can create this is a function with its own alias.

function Get-MyHistoryCommands {
[cmdletbinding()]
[alias("an")]
Param()
#or insert whatever code you want
((h).where({$_.executionstatus -match "c"}).commandline|ogv -p).foreach{$_ }|Set-Clipboard
}

Now just run an. ;-)

@Jaykul
Copy link

Jaykul commented Jul 9, 2020

Ok, y'all have obviously not played enough code-golf!

Rule #1 is that you have to actually produce the expected output (no fair leaving off the selects and putting hashtables on the clipboard instead of command lines, or failing to put the right data in the GridView, @SteveL-MSFT )

Rule #2 is that your solution has to be actually shorter than the original script @jdhitsolutions 😜 (although honestly, I like just stuffing it in a function)

This might be the shortest it can be within those restrictions:

h|select *|ogv -p|% C*|scb

If you'd rather filter only Completed items, instead of showing the Status and time, you can use this instead (4 is the enum's int value for "Completed"), but it's not shorter:

h|? ex* -eq 4|ogv -p|% C*|scb

Personally, if I was going to be typing that really often, I'd stick it in a function like @jdhitsolutions did, or at least ... alias s for select, which will add a few characters up front, but will save you typing "elect" over and over:

sal s select
h|s *|ogv -p|% C*|scb

@romero126
Copy link

romero126 commented Jul 9, 2020

Or you can just type
#<ctrl+Spacebar>
and stop wasting your time with silly codegolf shenanigan's when we have PSReadline and its tab completions to solve our problem for us.

@Jaykul
Copy link

Jaykul commented Jul 9, 2020

Yeah, it's probably worth pointing out that what I normally do for this sort of thing is run h and scan the output, and then just enter the number from the history id and press tab, like #86{Tab}

However, the OGV method is a lot cleaner in the scrollback ;-)

@SQLvariant
Copy link
Author

Yeah, it's probably worth pointing out that what I normally do for this sort of thing is run h and scan the output, and then just enter the number from the history id and press tab, like #86{Tab}

Oh wow @Jaykul, thanks for sharing that. I learned something new today!
Your h|select *|ogv -p|% C*|scb submission seems to be the shortest that meets all the requirements, so far.

Using the #86{Tab} you mentioned, or the #ctrl+Spacebar @romero126 mentioned are excellent to know about. Two of the other reasons I'm looking for the shortest code possible, so I can memorize it, are:

  1. I help a lot of people when they get stuck coding, so I expect to need to tell someone else this sequence, to use on their own machine.
  2. I will be using this in Jupyter Notebooks where the # bit doesn't work. (or at least, it doesn't work as of today.)

@Jaykul
Copy link

Jaykul commented Jul 9, 2020

Yeah, in Jupyter you don't get PSReadLine or any of it's features

@romero126
Copy link

You should be able to do R 13 <the line #> as well

@eliassal
Copy link

HI, I am not so expert like you but I have a question, is there any possible way to get the history after closing and opening a PS session like linux bash?

@jdhitsolutions
Copy link

If you are using the PSReadline module and have it configured to maintain history, which I think is the default, then yes, you can access history between sessions. Use Ctrl+R to search, just as you do in Linux.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment