Friday, January 6, 2023

PoSh Command History - Create your own

I wasn't sure how helpful, or novel this approach is - but thought I would share it.

> I also posted this on reddit - And someone commented:

"Was Add-History on vacation?"

I replied:

~~~~~~~~~~~~~~~~~~~

You know - When I went looking for ways to do this - That command never presented itself.

I will have to play around with it.

~~~~~~~~~~~~~~~~~~~

Then I replied again the next day, after looking at that command:

~~~~~~~~~~~~~~~~~~~

From what I am seeing - playing around with 'Add-History'...

THAT is much more complicated... Actually a pain in the ass.

This thing I hacked together is MUCH simpler across the board.

Though, all the same - Thanks for pointing that out!

~~~~~~~~~~~~~~~~~~~

From that - I feel like what I put together is rather novel.

Explanation:
I have a script ("disabled termed expired.ps1") that I have scheduled to run at 8:15, am M-F.

It pops up a PoSh CLI window on top of everything else, names it, sizes it (and will kill off any previous instances of that window)*, lists out what AD accounts are disabled, or expired, the reason why (terminated, KnowBe4 training is late...), how long it has been that way, etc...

The meat of that script is wrapped in a function named 'dte' - This way, while the window is open, I can easily refresh the window, with updated results, just by typing 'dte'...

Then I got lazy, and wanted to see if there was a way for that 'dte' command to be in the command history, so I could just 'up-arrow' and hit enter...

You know, rather than having to go through the laborious tasks of finding each of the three letters on the keyboard and having to press each one...

Really - I just wanted to see if I could do it...

Anyway - I added the below to the bottom part of the 'dte' function...

It sets the history for that specific Posh session to 'dte' (I don't think it works / will cause errors if used in ISE).

Obviously - It can be used for all kinds of things...
If you wanted to have several items you want in the history you could do:

"dte
cls
Get-Process" | Out-File $HxPath -Encoding ascii -Force 

Or assign that text to a variable:

$Hx = "dte
cls
Get-Process"

$Hx | Out-File $HxPath -Encoding ascii -Force 

If ($Host.Name -NOTmatch "ISE") {
# This sets the command history for the PoSh session to 'dte',
# so you can just up arrow, and get the command that re-runs the 'dte' function

$HxPath = "$env:USERPROFILE\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\dte.txt" 
"dte" | Out-File $HxPath -Encoding ascii -Force 
Set-PSReadLineOption -HistorySavePath $HxPath
}

(Hit the up-arrow '▲' or, type 'dte', and hit 'ENTER' to refresh...)

* If anyone is interested - Here is what I use to create and control the PoSh CLI window:

NOTE:
I like to include the PID in my Posh instances 'WindowTitle' - In case they lock up, so I can easily 'Stop-Process -Id XXXX'

$Window_Title = "Disabled, Terminated, or Expired AD Accounts"

If ($Host.Name -NOTmatch "ISE") {

$ScrWidth = $null; $ScrHeight = $null
$ScrWidth = 135
$ScrHeight = 35

$Already = $null; $Already = Get-Process | ? { $_.MainWindowTitle -match $Window_Title }

If ($Already) { $Already | Stop-Process }
$host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size($ScrWidth,$ScrHeight)
$host.UI.RawUI.WindowSize = New-Object System.Management.Automation.Host.size($ScrWidth,$ScrHeight)
$Host.UI.RawUI.WindowTitle = "$Window_Title (PID: $PID)"

############ Keeps the Console window on top ###############
$signature = @'
[DllImport("user32.dll")]
public static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags);
'@

$type = Add-Type -MemberDefinition $signature -Name SetWindowPosition -Namespace SetWindowPos -Using System.Text -PassThru
$handle = (Get-Process -id $Global:PID).MainWindowHandle
$alwaysOnTop = New-Object -TypeName System.IntPtr -ArgumentList (-1)
$type::SetWindowPos($handle, $alwaysOnTop, 0, 0, 0, 0, 0x0003)
############## END - On top ################

} # END 'If ($Host.Name -NOTmatch "ISE")'