Skip to content

Instantly share code, notes, and snippets.

@tsmarvin
Last active November 10, 2023 03:46
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 tsmarvin/77350ac4ca11715b0e7b3d0fde6472e5 to your computer and use it in GitHub Desktop.
Save tsmarvin/77350ac4ca11715b0e7b3d0fde6472e5 to your computer and use it in GitHub Desktop.
TM-SessionHistory

TM-SessionHistory Module

Introduction

TM-SessionHistory is a PowerShell module that provides functionality for recording and managing session command histories. It is designed to enhance the capability to review commands executed within a PowerShell session, or across different PowerShell sessions.

This module is part of a suite of tools designed to improve and streamline the PowerShell command line and scripting experience.
Check out the rest of the modules by visiting my page on the PowerShell Gallery.

Features

  • Get-SessionHistory: Retrieves the command history from a PowerShell or Bash shell session. It allows for extracting commands based on the session GUID or retrieving all commands from the session history.
  • Remove-SessionHistory: Provides the ability to delete specific commands from the session history or entire session histories, in case sensitive information like passwords are accidentally included.
  • Set-SessionHistory: Automatically invoked during the prompt execution to record details about the last executed command into the session history file.

Requirements

  • Windows PowerShell 5.1+, or PowerShell Core 7+.
  • Required module: TM-ProfileUtility.

Installation

Install TM-SessionHistory from the PowerShell Gallery:

Install-Module TM-SessionHistory -Scope CurrentUser -Repository PSGallery

For manual installation, download the module files and place them in a "TM-SessionHistory" folder in your PowerShell modules directory ($Env:PSModulePath).

MIT License
Copyright (c) 2023 Taylor Marvin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@{
# Script module or binary module file associated with this manifest.
RootModule = 'TM-SessionHistory.psm1'
# Version number of this module.
ModuleVersion = '0.0.6'
# Supported PSEditions
CompatiblePSEditions = @('Desktop','Core')
# ID used to uniquely identify this module
GUID = '36bfd560-f6e5-4f85-84e8-edf1cb0e0250'
# Author of this module
Author = 'Taylor Marvin'
# Company or vendor of this module
CompanyName = 'N/A'
# Copyright statement for this module
Copyright = 'Taylor Marvin (2023)'
# Description of the functionality provided by this module
Description = 'Provides session history utility functionality to make it easier to pull command history for documentation purposes.'
# Minimum version of the PowerShell engine required by this module
PowerShellVersion = '5.1'
# Modules that must be imported into the global environment prior to importing this module
RequiredModules = @(@{ModuleName='TM-ProfileUtility'; ModuleVersion='0.0.13'; GUID='82c4123f-77ae-497f-849c-a9a549d42984'})
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = @('Get-SessionHistory', 'Remove-SessionHistory', 'Set-SessionHistory')
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = @()
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{
PSData = @{
# Tags applied to this module. These help with module discovery in online galleries.
Tags = @('Profile', 'Session', 'History')
# A URL to the license for this module.
LicenseUri = 'https://gist.github.com/tsmarvin/77350ac4ca11715b0e7b3d0fde6472e5#file-license'
# A URL to the main website for this project.
ProjectUri = 'https://gist.github.com/tsmarvin/77350ac4ca11715b0e7b3d0fde6472e5'
# Prerelease string of this module
# Prerelease = ''
# Flag to indicate whether the module requires explicit user acceptance for install/update/save
RequireLicenseAcceptance = $false
}
}
}
using namespace Microsoft.PowerShell.Commands
using namespace System.Collections.Generic
using namespace System.IO
$script:IsAdmin = Test-Admin
# Create the HistoryPath variable for use within the functions.
$script:HistoryPath = Join-Path -Path (Get-ShellPath).FullName -ChildPath 'history.log'
# Create a SessionGuid variable containing a guid to identify the session by. Used by the SessionHistory commands.
$script:SessionGuid = (New-Guid).Guid
# Set local PSVersion variable for use within the functions.
$script:PSVersion = Get-PSVersionString
class SessionHistory {
<#
.SYNOPSIS
This class represents a PowerShell session history item.
.DESCRIPTION
A SessionHistory object encapsulates the properties related to a single command executed in a PowerShell session.
It includes distinguishing information about the current powershell session by pulling profile script variables
($script:PSVersion, $script:SessionGuid, $script:IsAdmin) and gathering current runtime state and history
information.
This class, combined with the Get-SessionHistory, Set-SessionHistory, and Remove-SessionHistory Commands facilitates
easy and safe documentation of a sessions command history.
Session History values are saved to the $script:HistoryPath by the Set-SessionHistory function which is called
during prompt execution.
The Get-SessionHistory command facilitates easy extraction of commands from a given session history.
This can be used after an iterative design/testing session to pull out specific commands for documentation purposes.
The Remove-SessionHistory command provides options for removing specific commands, or entire session histories from
the $script:HistoryPath in case you accidentally paste a password into your session.
#>
$Client
$Guid
$Admin
$Provider
$CurrentPath
$ExecutionTime
$ExecutionDuration
$Command
SessionHistory([HistoryInfo]$HistoryInfo) {
$this.Client = $script:PSVersion
$this.Guid = $script:SessionGuid
$this.Admin = $script:IsAdmin
$this.Provider = $pwd.Provider.Name
$this.CurrentPath = (Get-CurrentPath)
$this.ExecutionTime = $HistoryInfo.StartExecutionTime.ToString('yyyy-MM-ddTHH:mm:ss K')
$this.ExecutionDuration = (Get-LastExecutionDuration $HistoryInfo)
$this.Command = $HistoryInfo.CommandLine
}
SessionHistory([PSCustomObject]$CustomObject) {
$this.Client = $CustomObject.Client
$this.Guid = $CustomObject.Guid
$this.Admin = $CustomObject.Admin
$this.Provider = $CustomObject.Provider
$this.CurrentPath = $CustomObject.CurrentPath
$this.ExecutionTime = $CustomObject.ExecutionTime
$this.ExecutionDuration = $CustomObject.ExecutionDuration
$this.Command = $CustomObject.Command
}
[boolean] Equals($otherHistory) {
if (
($null -ne $otherHistory) -and
($otherHistory.GetType().FullName -eq 'SessionHistory') -and
($this.Client -eq $otherHistory.Client) -and
($this.Guid -eq $otherHistory.Guid) -and
($this.Admin -eq $otherHistory.Admin) -and
($this.Provider -eq $otherHistory.Provider) -and
($this.CurrentPath -eq $otherHistory.CurrentPath) -and
($this.ExecutionTime -eq $otherHistory.ExecutionTime) -and
($this.ExecutionDuration -eq $otherHistory.ExecutionDuration) -and
($this.Command -eq $otherHistory.Command)
) {
return $true
} else {
return $false
}
}
[string] ToString() {
# This prevents "The script failed due to call depth overflow." on Windows PowerShell.
# This was "return ($this | ConvertTo-Json -Compress)" but that had depth issues.
return (
[PsCustomObject]@{
Client = $this.Client
Guid = $this.Guid
Admin = $this.Admin
Provider = $this.Provider
CurrentPath = $this.CurrentPath
ExecutionTime = $this.ExecutionTime
ExecutionDuration = $this.ExecutionDuration
Command = $this.Command
} | ConvertTo-Json -Compress
)
}
}
function Get-SessionHistory {
<#
.SYNOPSIS
Retrieves PowerShell session history.
.DESCRIPTION
Get-SessionHistory is a function that retrieves the history of commands executed in a previous PowerShell or
Bash shell session. To get this functionality in your bash sessions you will also need to edit your .bashrc file
as shown in GISTLINKGOESHERE.
The SessionHistory items are retrieved from a script defined JSON file ($script:HistoryPath).
The function can retrieve the history associated with a specific session by GUID or all available history entries
from the file.
.PARAMETER Guid
The unique identifier associated with a specific PowerShell session.
If specified, only the history from this session is retrieved.
By Default this is populated with the profile script defined SessionGuid.
.PARAMETER All
If this switch is used then all available session history is returned.
.OUTPUTS
List[SessionHistory] - The function returns a list of SessionHistory objects.
.EXAMPLE
# The retrieved SessionHistory items can be parsed to easily select commands for reuse from your current session.
Get-SessionHistory | Select-Object -ExpandProperty Command
.EXAMPLE
# Retrieve the commands from the 5 latest sessions.
Get-SessionHistory -All | Select-Object -ExpandProperty Guid -Unique | Select-Object -Last 5 | %{
Write-Host "`n`nGuid: $_"
Get-SessionHistory -Guid $_ | Select-Object -ExpandProperty Command
}
#>
[CmdletBinding()]
[CmdletBinding(DefaultParameterSetName = 'Guid')]
[OutputType([List[SessionHistory]])]
param(
[Parameter(
Mandatory = $false,
ParameterSetName = 'Guid',
ValueFromPipeline,
ValueFromPipelineByPropertyName
)]
[string]$Guid = $script:SessionGuid,
[Parameter(
Mandatory,
ParameterSetName = 'All'
)]
[switch]$All
)
$SessionHistory = [List[SessionHistory]]::New()
$HistoryContent = Get-Content -Path $script:HistoryPath | ConvertFrom-Json
foreach ($item in $HistoryContent) {
if (($PSCmdlet.ParameterSetName -eq 'All') -or ($item.Guid -eq $Guid)) {
$SessionHistory.Add([SessionHistory]::New($item))
}
}
return $SessionHistory
}
function Remove-SessionHistory {
<#
.SYNOPSIS
Deletes specified entries from the PowerShell session history.
.DESCRIPTION
The Remove-SessionHistory function can either delete all entries associated with a specific session GUID or a single
specified history item from the session history stored in the JSON history file ($script:HistoryPath).
This function helps enhance the security of your scripting environment by providing the ability to remove commands
from the session history that may have exposed sensitive information, such as passwords.
Please note that this function does not replace any session history information stored in PowerShell's built-in
history location, which is accessible via (Get-PSReadLineOption).HistorySavePath. When removing sensitive
information users should also manage their PSReadLine history from that location as well.
.PARAMETER Guid
Specifies the unique session GUID to remove history entries for.
.PARAMETER HistoryItem
Specifies a particular SessionHistory item to remove from the $script:HistoryPath file.
.EXAMPLE
# Remove the previously run command from the session history.
Get-SessionHistory | Select-Object -Last 1 | Remove-SessionHistory
#>
[CmdletBinding()]
[CmdletBinding(DefaultParameterSetName = 'HistoryItem')]
[OutputType([Void])]
param(
[Parameter(
Mandatory,
ParameterSetName = 'Guid',
ValueFromPipelineByPropertyName
)]
[string]$Guid,
[Parameter(
Mandatory,
ParameterSetName = 'HistoryItem',
ValueFromPipeline,
ValueFromPipelineByPropertyName
)]
[SessionHistory]$HistoryItem
)
$OutputHistory = [List[SessionHistory]]::New()
$SessionHistory = Get-SessionHistory -All
foreach ($item in $SessionHistory) {
if (
(($PSCmdlet.ParameterSetName -eq 'Guid') -and ($item.Guid -ine $Guid)) -or
(($PSCmdlet.ParameterSetName -eq 'HistoryItem') -and ($HistoryItem.Equals($HistoryValue) -eq $false))
) {
$OutputHistory.Add($item)
}
}
$OutputContent = foreach ($element in $OutputHistory) { $element.ToString() }
$OutputContent | Out-File $script:HistoryPath -Force
}
function Set-SessionHistory {
<#
.SYNOPSIS
This function is run automatically during prompt execution. It records details about the last executed command's and
appends them to the $script:HistoryPath (session history file).
.DESCRIPTION
Set-SessionHistory is used to capture the details of the last executed command in a PowerShell session and append
them as a new SessionHistory entry to a dedicated JSON file, identified by the $script:HistoryPath variable.
If no HistoryInfo information is provided, then the function captures the details of the most recently run command.
If no $CommandHistory can be found then the function does nothing at all.
This function is run at the end of the prompt, so if you close out your powershell session while a command is
executing the commands history will not be saved.
This function is run in addition to any functionality you have configured via PSReadLine.
.PARAMETER CommandHistory
The HistoryInfo object for an command executed in a PowerShell session.
If not specified, the function will automatically retrieve the most recent command history (if any exists).
#>
[CmdletBinding()]
[OutputType([System.Void])]
param(
[Parameter(Mandatory = $false)]
[HistoryInfo]$CommandHistory
)
$ErrorActionPreference = 'Ignore'
if ($null -eq $CommandHistory) { $CommandHistory = Get-History -Count 1 }
if (($null -ne $CommandHistory) -and ([string]::IsNullOrWhiteSpace($script:HistoryPath) -eq $false)) {
[SessionHistory]::New($CommandHistory).ToString() | Out-File $script:HistoryPath -Append -Encoding UTF8
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment