PowerShell's Clear-History doesn't clear history
Asked Answered
R

9

162

Recently I had to run a command that unfortunately required me to type a password right on the command line.

Afterwards, I cleared my screen with "Clear", but also wanted to clear the command history so the offending command wouldn't show up in the session history. Unfortunately, the Clear-History cmdlet doesn't seem to actually do what its documentation claims - running Clear-History doesn't seem to have any impact on the session history whatsoever.

I can still see previous commands in the pop-up history menu, and scroll through old commands by pressing the up key. Here's a screengrab demonstrating the problem:

PowerShell clear history failure

I've verified with Get-Command that Clear-History is indeed executing the expected built-in PowerShell cmdlet.

I've tried a few variations, such as "Clear-History -count 10 -newest", all failing to show any effect. When I specify an exact history ID, such as "Clear-History -id 3", I receive an error like this:

Clear-History : Cannot locate history for Id 3.

Even if I can see command #3 on the screen.

Rangel answered 6/11, 2012 at 19:13 Comment(1)
Just a side note, but the history you're actually clearing with Clear-History is the one you see with Get-History.Gertie
P
121

tl;dr

  • There are two histories to clear:

    • PowerShell's own (Clear-History)
    • Additionally, in consoles (terminals), that of the PSReadLine module that is used for command-line editing by default in PowerShell v5+ ([Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory())
  • In versions 1.2+ of PSReadLine (verify with Get-Module PSReadLine) pressing Alt+F7 performs both calls for you, and therefore fully clears the in-session history.

    • However, it does not clear the saved history that has accumulated up to this point, so even the cleared session's history will resurface in future sessions.

    • To also clear the saved history, you have to manually delete the file in which the saved session is stored ((Get-PSReadlineOption).HistorySavePath), as discussed below, and as wrapped by the Clear-SavedHistory function in the bottom section.


To complement CB.'s helpful answer and JVimes's helpful answer:

  • PowerShell's own history mechanism (Get-History, Clear-History) is host-independent, which is why - somewhat unexpectedly - you also need to clear the hosts's command history separately.

  • As for the console host's own history feature:

    • doskey-style history feature, before module PSReadline shipped with PowerShell (see below):

      • There is no saved history - a history is kept only for the duration of the current session.
      • Alt+F7 must be used to clear the console's history, with no (obvious) programmatic way to do it (in a cmd.exe console window you could use doskey /reinstall, but that doesn't work in PS).
      • CB.'s answer shows you how to simulate this keyboard combination; remember: this must be used in addition to Clear-History.
    • The PSReadline module comes with PowerShell v5 and v5.1 on Windows 10 and will also ship with Windows Server 2016, and also ships with the cross-platform Powershell (Core) v7+ edition; it replaces the doskey-style line-editing and command-history features with more sophisticated functionality; it is also possible to retrofit older Windows editions / PS versions (>= v3) versions with it, using the PowerShell Gallery (PSv3 and PSv4 must first install PowerShellGet).

      • Command history is now saved across sessions, in file
        (Get-PSReadlineOption).HistorySavePath.
      • [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory() can be used to clear the current session's history (note that v1.2+ also supports Alt+F7 for interactive clearing of the current history).
        • CAVEAT: With PSReadline's default history-saving style, SaveIncrementally, any sensitive commands have already been saved by the time to you call [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory(), and will reappear in the next session.
        • The only way to handle this is to remove the saved-history file, as demonstrated in JVimes's answer which, however, invariably wipes out the entire history.
        • IF you set up your profile to call Set-PSReadlineOption -HistorySaveStyle SaveAtExit every time a session starts - the setting apparenly does NOT "stick" by itself - you should be able to get away with only calling [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory() (in addition to Clear-History) without also having to delete the saved-history file, in which case you won't lose your saved history from previous sessions. HOWEVER, AS OF v2.1.0 (the latest as of this writing), SaveAtExit is BROKEN ALTOGETHER - no history is saved at all; see https://github.com/lzybkr/PSReadLine/issues/262

The following advanced function bundles all commands necessary to clear the command history (both for PowerShell itself and the console), both for doskey-style and PSReadline-module PowerShell console windows:

Note:

  • Because it's (currently) the only safe option, PSReadline's saved-history file is deleted as well, which means the entire history, including from previous sessions, is cleared.

  • Therefore, a confirmation prompt is shown by default.

<#
# .SYNOPSIS
#  Clears the command history, including the saved-to-file history, if applicable.
#>
function Clear-SavedHistory {
  [CmdletBinding(ConfirmImpact='High', SupportsShouldProcess)]
  param(    
  )

  # Debugging: For testing you can simulate not having PSReadline loaded with
  #            Remove-Module PSReadline -Force
  $havePSReadline = ($null -ne (Get-Module -EA SilentlyContinue PSReadline))

  Write-Verbose "PSReadline present: $havePSReadline"

  $target = if ($havePSReadline) { "entire command history, including from previous sessions" } else { "command history" } 

  if (-not $pscmdlet.ShouldProcess($target))
  {
        return
  }

  if ($havePSReadline) {
    
    Clear-Host

    # Remove PSReadline's saved-history file.
    if (Test-Path (Get-PSReadlineOption).HistorySavePath) { 
      # Abort, if the file for some reason cannot be removed.
      Remove-Item -EA Stop (Get-PSReadlineOption).HistorySavePath 
      # To be safe, we recreate the file (empty). 
      $null = New-Item -Type File -Path (Get-PSReadlineOption).HistorySavePath
    }

    # Clear PowerShell's own history 
    Clear-History

    # Clear PSReadline's *session* history.
    # General caveat (doesn't apply here, because we're removing the saved-history file):
    #   * By default (-HistorySaveStyle SaveIncrementally), if you use
    #    [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory(), any sensitive
    #    commands *have already been saved to the history*, so they'll *reappear in the next session*. 
    #   * Placing `Set-PSReadlineOption -HistorySaveStyle SaveAtExit` in your profile 
    #     SHOULD help that, but as of PSReadline v1.2, this option is BROKEN (saves nothing). 
    [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()

  } else { # Without PSReadline, we only have a *session* history.

    Clear-Host
    
    # Clear the doskey library's buffer, used pre-PSReadline. 
    # !! Unfortunately, this requires sending key combination Alt+F7.
    # Thanks, https://mcmap.net/q/149762/-powershell-39-s-clear-history-doesn-39-t-clear-history
    $null = [system.reflection.assembly]::loadwithpartialname("System.Windows.Forms")
    [System.Windows.Forms.SendKeys]::Sendwait('%{F7 2}')

    # Clear PowerShell's own history 
    Clear-History

  }

}
Plumcot answered 6/8, 2016 at 18:49 Comment(1)
Thank you for providing this very thorough explanation and solution. This is the approach that should be used to ensure that Powershell's history is properly and fully cleared.Rangel
D
299

On Windows 10, the history and sensitive data show up in future sessions, even after Alt+F7 and Clear-History. It turns out the history is stored in a text file found at:

(Get-PSReadlineOption).HistorySavePath

"$env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt"

Delete the offending line from that file and end the current session (or clear it via CB's answer).

You can upvote this request for an easier way to temporarily disable the history.

Donar answered 27/4, 2016 at 20:17 Comment(7)
Just for the lazy admin, the default path for the text file where the commands are saved is: C:\Users[username]\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline The file is recreated the next time the console is started. I went so far as to run Remove-Module PSReadline -Force, but the module was re-added (and the history file recreated) when I restarted the console again. Is there some uber-module remove function?Parmer
Maybe when they ship the module w/PowerShell, they do too good of a job importing it. If the persistent history is all you want to disable (not all the other psreadline goodies), it looks like the way is to add Set-PSReadlineOption -HistorySaveStyle SaveNothing to your profile. For removing the module, maybe putting that command in your profile would work "good enough" for now.Donar
Great tip, but for clearing the current session's history it's safer to use [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory() (as an aside: sending Alt+F7 doesn't actually work at all in PSReadline v1.1, which is the version that shipped with Windows 10 (Alt+F7 was introduced in v1.2).Plumcot
@mklement0, is that different than Clear-History?Donar
Yes: Clear-History is a PowerShell-internal feature that is unrelated to the host (but should also be called); by contrast, [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory() clears the host's history buffer - it's the PSReadline equivalent to pressing Alt+F7 in the pre-PSReadline days (doskey-style). My answer provides background.Plumcot
FYI: You can upvote this request for an easier way to temporarily disable the history.Donar
The best way to handle this currently is running Set-PSReadLineOption -HistorySaveStyle SaveNothing in your current session, then run everything you don't want in your history. Then just close and start a new session, which will save everything by default again.Cessation
P
121

tl;dr

  • There are two histories to clear:

    • PowerShell's own (Clear-History)
    • Additionally, in consoles (terminals), that of the PSReadLine module that is used for command-line editing by default in PowerShell v5+ ([Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory())
  • In versions 1.2+ of PSReadLine (verify with Get-Module PSReadLine) pressing Alt+F7 performs both calls for you, and therefore fully clears the in-session history.

    • However, it does not clear the saved history that has accumulated up to this point, so even the cleared session's history will resurface in future sessions.

    • To also clear the saved history, you have to manually delete the file in which the saved session is stored ((Get-PSReadlineOption).HistorySavePath), as discussed below, and as wrapped by the Clear-SavedHistory function in the bottom section.


To complement CB.'s helpful answer and JVimes's helpful answer:

  • PowerShell's own history mechanism (Get-History, Clear-History) is host-independent, which is why - somewhat unexpectedly - you also need to clear the hosts's command history separately.

  • As for the console host's own history feature:

    • doskey-style history feature, before module PSReadline shipped with PowerShell (see below):

      • There is no saved history - a history is kept only for the duration of the current session.
      • Alt+F7 must be used to clear the console's history, with no (obvious) programmatic way to do it (in a cmd.exe console window you could use doskey /reinstall, but that doesn't work in PS).
      • CB.'s answer shows you how to simulate this keyboard combination; remember: this must be used in addition to Clear-History.
    • The PSReadline module comes with PowerShell v5 and v5.1 on Windows 10 and will also ship with Windows Server 2016, and also ships with the cross-platform Powershell (Core) v7+ edition; it replaces the doskey-style line-editing and command-history features with more sophisticated functionality; it is also possible to retrofit older Windows editions / PS versions (>= v3) versions with it, using the PowerShell Gallery (PSv3 and PSv4 must first install PowerShellGet).

      • Command history is now saved across sessions, in file
        (Get-PSReadlineOption).HistorySavePath.
      • [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory() can be used to clear the current session's history (note that v1.2+ also supports Alt+F7 for interactive clearing of the current history).
        • CAVEAT: With PSReadline's default history-saving style, SaveIncrementally, any sensitive commands have already been saved by the time to you call [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory(), and will reappear in the next session.
        • The only way to handle this is to remove the saved-history file, as demonstrated in JVimes's answer which, however, invariably wipes out the entire history.
        • IF you set up your profile to call Set-PSReadlineOption -HistorySaveStyle SaveAtExit every time a session starts - the setting apparenly does NOT "stick" by itself - you should be able to get away with only calling [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory() (in addition to Clear-History) without also having to delete the saved-history file, in which case you won't lose your saved history from previous sessions. HOWEVER, AS OF v2.1.0 (the latest as of this writing), SaveAtExit is BROKEN ALTOGETHER - no history is saved at all; see https://github.com/lzybkr/PSReadLine/issues/262

The following advanced function bundles all commands necessary to clear the command history (both for PowerShell itself and the console), both for doskey-style and PSReadline-module PowerShell console windows:

Note:

  • Because it's (currently) the only safe option, PSReadline's saved-history file is deleted as well, which means the entire history, including from previous sessions, is cleared.

  • Therefore, a confirmation prompt is shown by default.

<#
# .SYNOPSIS
#  Clears the command history, including the saved-to-file history, if applicable.
#>
function Clear-SavedHistory {
  [CmdletBinding(ConfirmImpact='High', SupportsShouldProcess)]
  param(    
  )

  # Debugging: For testing you can simulate not having PSReadline loaded with
  #            Remove-Module PSReadline -Force
  $havePSReadline = ($null -ne (Get-Module -EA SilentlyContinue PSReadline))

  Write-Verbose "PSReadline present: $havePSReadline"

  $target = if ($havePSReadline) { "entire command history, including from previous sessions" } else { "command history" } 

  if (-not $pscmdlet.ShouldProcess($target))
  {
        return
  }

  if ($havePSReadline) {
    
    Clear-Host

    # Remove PSReadline's saved-history file.
    if (Test-Path (Get-PSReadlineOption).HistorySavePath) { 
      # Abort, if the file for some reason cannot be removed.
      Remove-Item -EA Stop (Get-PSReadlineOption).HistorySavePath 
      # To be safe, we recreate the file (empty). 
      $null = New-Item -Type File -Path (Get-PSReadlineOption).HistorySavePath
    }

    # Clear PowerShell's own history 
    Clear-History

    # Clear PSReadline's *session* history.
    # General caveat (doesn't apply here, because we're removing the saved-history file):
    #   * By default (-HistorySaveStyle SaveIncrementally), if you use
    #    [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory(), any sensitive
    #    commands *have already been saved to the history*, so they'll *reappear in the next session*. 
    #   * Placing `Set-PSReadlineOption -HistorySaveStyle SaveAtExit` in your profile 
    #     SHOULD help that, but as of PSReadline v1.2, this option is BROKEN (saves nothing). 
    [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()

  } else { # Without PSReadline, we only have a *session* history.

    Clear-Host
    
    # Clear the doskey library's buffer, used pre-PSReadline. 
    # !! Unfortunately, this requires sending key combination Alt+F7.
    # Thanks, https://mcmap.net/q/149762/-powershell-39-s-clear-history-doesn-39-t-clear-history
    $null = [system.reflection.assembly]::loadwithpartialname("System.Windows.Forms")
    [System.Windows.Forms.SendKeys]::Sendwait('%{F7 2}')

    # Clear PowerShell's own history 
    Clear-History

  }

}
Plumcot answered 6/8, 2016 at 18:49 Comment(1)
Thank you for providing this very thorough explanation and solution. This is the approach that should be used to ensure that Powershell's history is properly and fully cleared.Rangel
E
51

To clear the on screen display history (F7) you have to press Alt + F7.

This history is managed by the console buffer, not by PowerShell that has its history clearable by the Clear-History cmdlet.

To script it, try:

[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.SendKeys]::Sendwait('%{F7 2}')
Erivan answered 6/11, 2012 at 19:24 Comment(3)
Wild. Any idea if that functionality could be replicated programatically so I can alias clear-history to do both?Rangel
I've changed the accepted answer to mklement0's to reflect that additional action is now needed to fully clear the history in versions of Windows later than 7. Thank you, CB, for providing the original answer that seems to have served so many very well.Rangel
How do one undo the script; ``` [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") [System.Windows.Forms.SendKeys]::Sendwait('%{F7 2}') ```Democritus
S
8

At the moment my only solution will be to delete the psreadline.txt text from the folder periodically by running an automated Job. The file path to the command is @

PS C:\Users\{{user}}\appdata\roaming\microsoft\windows\powershell\psreadline>

and the filename is history.txt

Svetlana answered 16/6, 2022 at 15:37 Comment(0)
L
2

By the best answer from @mklement0 I ended up with the next function, that is placed in my $PROFILE

I don't really care about any other sessions, I just want that stupid history to be cleared and that's it.

Cmdlet name Clear-History confuses as much as it can.

# it's a default alias for Get-History cmdlet
Remove-Alias history

# Usage: history      - just print the history, same as call Get-History
# Usage: history -c   - really clears the history
function history {
    param (
        # Clears history
        [Parameter()]
        [Alias("c")]
        [Switch]
        $Clear
    )

    if ($Clear){
        Clear-History
        [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()
        return
    }

    Get-History
}
Liger answered 31/1, 2022 at 10:2 Comment(4)
...which doesn't at all help with remote PS sessions. SIGH.Chiaki
Get-PSReadlineOption : The term 'Get-PSReadlineOption' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:1 char:2 + (Get-PSReadlineOption).HistorySavePath + ~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (Get-PSReadlineOption:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundExceptionChiaki
...and your function failedChiaki
@PatrickBurwell well, life is a pain. I never tested it for all cases.Liger
H
1

First,

PS /root> Get-PSReadlineOption | grep MaximumHistoryCount

returned this:

MaximumHistoryCount                    : 4096

Then running this prevented up arrow from accessing past commands.

PS /root> Set-PSReadlineOption -MaximumHistoryCount 1
PS /root> Set-PSReadlineOption -MaximumHistoryCount 4096
Heteroplasty answered 9/1 at 20:51 Comment(0)
M
0

There is another way to remove the selected history entry in Prediction.I found this elegant way in PSReadLine issue

Set-PSReadLineKeyHandler -Key Shift+Delete `
    -BriefDescription RemoveFromHistory `
    -LongDescription "Removes the content of the current line from history" `
    -ScriptBlock {
    param($key, $arg)

    $line = $null
    $cursor = $null
    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)

    $toRemove = [Regex]::Escape(($line -replace "\n", "```n"))
    $history = Get-Content (Get-PSReadLineOption).HistorySavePath -Raw
    $history = $history -replace "(?m)^$toRemove\r\n", ""
    Set-Content (Get-PSReadLineOption).HistorySavePath $history
}
Metathesize answered 28/7, 2022 at 2:4 Comment(0)
W
0

Command History

PSReadLine maintains a history file containing all the commands and data you've entered from the command line. The history files are a file named $($host.Name)_history.txt.

On Windows systems the history file is stored at $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine.

On non-Windows systems, the history files are stored at

$env:XDG_DATA_HOME/powershell/PSReadLine or

$env:HOME/.local/share/powershell/PSReadLine.

use the following command to delete:

Remove-Item (Get-PSReadlineOption).HistorySavePath


deletes the command history from a PowerShell session.

Clear-History # It will delete itself after the window is closed. There is no need to delete it unless there is a special requirement.
Weslee answered 26/9, 2023 at 7:4 Comment(0)
B
0

Navigate to this path: $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt

and delete the content restart your Powershell and verify

Breakup answered 19/12, 2023 at 9:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.