I thought I'd share a short but useful PowerShell utility. This is something that is very handy when I am writing. As you know, PowerShell maintains a command history in your PowerShell session. You can view history with the Get-History cmdlet or its alias h. To re-rerun a command use Invoke-History or its alias r, specifying the history ID. You can also use PSReadline and Ctrl+R to search history. An advantage with this approach is that you are technically searching your saved history which can include commands from previous sessions. I use this all the time but sometimes, I have slightly different needs. That's where today's function comes into play.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
There are many times when I want the command line from a history item. Run this to see what I'm talking about.
Get-History | Select ID,Commandline
I either need to copy the command line so I can paste it into a document or I want to bring it back to my prompt to either re-run or edit and then run. Running Invoke-History is simple enough for re-running the command, but I can't tweak it. Or I can use PSReadline and search for the command. Once I find it, I can adjust it and then run it. But I need something in-between. The answer is a utility to copy the command line from the specified history item to the clipboard. Lee Holmes has a similar utility described in the PowerShell Cookbook. This is my version.
Function Copy-HistoryCommand {
[CmdletBinding(SupportsShouldProcess)]
[alias("ch")]
[outputtype("None", "System.String")]
Param(
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty()]
[int]$ID = $(Get-History).Count,
[switch]$Passthru)
Begin {
Write-Verbose "[BEGIN ] Starting: $($MyInvocation.Mycommand)"
} #begin
Process {
Write-Verbose "[PROCESS] Getting commandline from history item: $id"
$cmdstring = (Get-History -Id $id).CommandLine
If ($PSCmdlet.ShouldProcess("ID #$id [$cmdstring]")) {
$cmdstring | Microsoft.PowerShell.Management\Set-Clipboard
If ($Passthru) {
#write the command to the pipeline
$cmdstring
} #If passthru
}
} #process
End {
Write-Verbose "[END ] Ending: $($MyInvocation.Mycommand)"
} #end
} #close function
The command is pretty simple. It takes the commandline property and copies it to the clipboard using Set-Clipboard. The function merely makes this easier by defining an alias and adding a few features like -Passthru and -WhatIf.
In this example, I'm copying the command from history item #3 to the clipboard. I used -Passthru so you can see for yourself. In my Windows Terminal session, I can use Ctrl+V or the right mouse button to paste the command at my prompt. That's what I love about this. It only takes a few simple keystrokes to bring back a command I want to edit and re-run. I haven't found a way to copy the command and automatically paste it into the next prompt. But the current process is simple and quick enough.
This command will eventually be part of the PSScriptTools module. But for now, feel free to use this code if this is something you would find useful.
> I haven’t found a way to copy the command and automatically paste it into the next prompt.
I don’t know what exactly you are trying to accomplish with pasting it into the next prompt but if you are just trying to rerun it what don’t you just call invoke history with the number?
Also, windows only you can use sendkeys to send ctrl-v
> > I haven’t found a way to copy the command and automatically paste it into the next prompt.
I don’t know what exactly you are trying to accomplish with pasting it into the next prompt but if you are just trying to rerun it what don’t you just call invoke history with the number?
Also, windows only you can use sendkeys to send ctrl-v
As I mentioned in the article, sometimes I want to bring the command back and edit it first. Invoke-History simply re-runs the command. And I am using keyboard shortcuts to quickly paste which is not that much of burden,
I use the following in my profile to allow the ability to quickly grab multiple lines and then paste to run them all again. Very useful for pasting into my time entry notes or to create a script based on my interactive command line edits.
I add the alias ch to make it quick to type
function get-selectedhistorytoclipboard {
((h).where({$_.executionstatus -match “c”}).commandline|ogv -p).foreach{$_}|clip}
new-alias ch get-selectedhistorytoclipboard
I see having the history maintain overtime about commands in your PowerShell sessions as a potential security risk. I’ve put together a several cmdlets to deal with cleaning up the history information. The cmdlet, Clear-PSKConsole (KB-Bye) will remove the existing console log and exit the current PowerShell session. The cmdlet, Get-PSKConsole (KB-Console) displays the current console log records.
These cmdlets are in a module I wrote called, PSKeyBase which is published here: https://cadayton.keybase.pub/PSGallery/Modules/PSKeyBase/PSKeyBase.html
You are correct that maintaining history between sessions is not without risk. But it really isn’t any different than any other risk. If you don’t keep a secure desktop, access to previous history commands is not your only concern. But thanks for the links and suggestions.