Sure, PowerShell had that 'hash tag + hit TAB' crap, but they've never had 'up arrow' access to the command history. Well, not anymore...
To get started, you'll need three things:
- A script to backup and restore your command history each time you start/exit a PowerShell instance. (don't worry, the execution time is negligible)
- This backup/restore script will require the PSReadLine module.
- The easiest way to get the PSReadLine module is to install PsGet.
Let's do this in reverse...
Step 1: Install PsGet here: http://psget.net/. For the security conscious people, alternate methods of installation are available, OR you take the security-lite approach and download/inspect the files before execution.(new-object Net.WebClient).DownloadString("http://psget.net/GetPsGet.ps1") | iex
Step 2: Install/Import the PSReadLine module.
install-module PSReadline
Step 3: Add a script to your profile that loads/saves your command history. Be sure to have the path ready (HistoryDirPath). For me, I like to put his into a dropbox location and share it amongst my other workstations. Or if you want to have some level of separation, change the file name (HistoryFileName)
$MaximumHistoryCount = 31KB
$ImportedHistoryCount = 0
$HistoryDirPath = "c:\dropbox\powershell\history\"
$HistoryFileName = "history.clixml"
if (!(Test-Path $HistoryDirPath -PathType Container))
{ New-Item $HistoryDirPath -ItemType Directory }
Register-EngineEvent PowerShell.Exiting –Action {
$TotalHistoryCount = 0
Get-History | ? {$TotalHistoryCount++;$true}
$RecentHistoryCount = $TotalHistoryCount - $ImportedHistoryCount
$RecentHistory = Get-History -Count $RecentHistoryCount
if (!(Test-path ($HistoryDirPath + $HistoryFileName)))
{
Get-History | Export-Clixml ($HistoryDirPath + $HistoryFileName)
}else
{
$OldHistory = Import-Clixml ($HistoryDirPath + $HistoryFileName)
$NewHistory = @($OldHistory + $RecentHistory)
$NewHistory | Export-Clixml ($HistoryDirPath + $HistoryFileName)
}
}
if (Test-path ($HistoryDirPath + $HistoryFileName))
{
Import-Clixml ($HistoryDirPath + $HistoryFileName) | ? {$count++;$true} |Add-History
Write-Host -Fore Green "`nLoaded $count history item(s).`n"
$ImportedHistoryCount = $count
}
# Importing PSReadline must come AFTER you load your command history
if ($host.Name -eq 'ConsoleHost')
{
Import-Module PSReadline
}
# if you don't already have this configured...
Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward
Your profile location will be something like:
C:\Users\username\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
Now for the fiiixins...
Redirect your default profile to your tricked-out profile.http://orsontyrell.blogspot.com/2013/11/saurons-powershell-profile-in-3-easy.html
Since you're putting your command history and profile on dropbox, don't forget to add your modules as well!
Setup a command line installer like Scoop or Chocolatey.
https://github.com/lukesampson/scoop/
http://chocolatey.org/
With one of these installer you're one line away from all sorts of cool tools, stuff like: 7zip, curl, grep, nano, git, openssh, vim, wget. With Chocolately you can install goodies like Notepad++, Chrome, VLC, etc.
bunch of sources:
http://psget.net/
https://github.com/lzybkr/PSReadLine
http://stackoverflow.com/questions/17862618/loading-powershell-history
http://blog.clintarmstrong.net/2011/05/powershell-history-persistence.html
http://rkeithhill.wordpress.com/2013/10/18/psreadline-a-better-line-editing-experience-for-the-powershell-console/
I'm not sure why you use
ReplyDeleteGet-History | ? {$TotalHistoryCount++;$true}
to count the history items, when that basically outputs the entire history. using $false instead of $true is slightly better as it avoids unnecessary output, but how about simply:
(Get-History).Length
?
Also (I was posting before - blogspot's openid support is horrible), I don't understand why you go to such lengths to extract only the recent history from the current session. It would make sense if you want to only append to the history file, but as it is an XML format, and you need to read all of it anyway, why not just dump all the available history every time?
ReplyDeleteIf we get rid of the test for the history directory (I'm storing my history in the user's home, like bash does), not modify the maximum history (PS v3 has 4096 by default, which is good enough for me), and all the other unneeded code, we are left with these 3 lines - which work great (note the piping to out-null to suppress the reg-event output):
$HistoryFilePath = Join-Path ([Environment]::GetFolderPath('UserProfile')) .ps_history
Register-EngineEvent PowerShell.Exiting –Action { Get-History | Export-Clixml $HistoryFilePath } | out-null
if (Test-path $HistoryFilePath) { Import-Clixml $HistoryFilePath | Add-History }
So in summary:
1. Thanks for a great introduction to persistent history
2. Shorter code - especially in the profile script (which tends to accumulate junk) is better.
I know this is old but I am just amazed that I cannot find anything on a great new feature in Powershell 5! Ctrl+R (bck-i-search like bash) lets you search your history ACROSS sessons. Yay!
ReplyDelete