PowerShell 的“清除历史”并不能清除历史

最近我不得不运行一个命令,不幸的是,这个命令要求我在命令行上输入密码。

之后,我用“ Clear”清除屏幕,但也想清除命令历史记录,这样违规命令就不会出现在会话历史记录中。不幸的是,Clear-History cmdlet 似乎并没有实现其文档声明的功能——运行 Clear-History 似乎对会话历史记录没有任何影响。

我仍然可以在弹出历史菜单中看到以前的命令,并通过按向上键滚动浏览旧命令。下面的屏幕截图展示了这个问题:

PowerShell clear history failure

我用 指挥官验证了 Clear-History 确实正在执行预期的内置 PowerShell cmdlet。

我尝试了一些变化,比如“清除历史记录-数10个最新的”,但都没有显示出任何效果。当我指定一个确切的历史 ID (比如“ Clear-History-ID 3”)时,我会收到如下错误:

Clear-History : Cannot locate history for Id 3.

即使我能在屏幕上看到命令 # 3。

99528 次浏览

要清除屏幕上的显示历史(F7) ,您必须按 Alt + F7

此历史记录由控制台缓冲区管理,而不是由具有可由 Clear-Historycmdlet 清除的历史记录的 PowerShell 管理。

要编写脚本,请尝试:

[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.SendKeys]::Sendwait('%{F7 2}')

在 Windows 10 中,历史记录和敏感数据在以后的会话中再次显示,即使在 Alt + F7和 clear-history之后也是如此。It turns out历史记录存储在一个文本文件中,位于:

(Get-PSReadlineOption).HistorySavePath

Delete the offending line from that file and end the current session (or clear it via CB 的回答).

您可以升级 这个要求,以更简单的方式暂时禁用历史记录。

博士

  • 还有 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())
  • 版本1.2 + 的 PSReadLine中(用 Get-Module PSReadLine验证) Alt+F7执行 < em > both 调用,因此是 完全清除会议记录

    • 但是,it does not clear the saved history that has accumulated up to this point,所以即使清除会话的历史将 重新露面在未来的会话。

    • 要清除 得救了历史记录 ,您必须使用 手动删除保存会话的文件((Get-PSReadlineOption).HistorySavePath) ,如下所述,并且如下面部分中的 Clear-SavedHistory函数所包装的那样。


为了补充 CB 的回答很有帮助JVimes 的回答很有帮助:

  • PowerShell 自己的历史机制(Get-HistoryClear-History)是 主机独立 ,这就是为什么——有点出乎意料地—— 您还需要分别清除 < em > hosts 的命令 history < em >

  • 至于 控制台主机自身的历史记录特性:

    • doskey风格的历史特性 ,在 PowerShell 模块 PSReadline发布之前(见下文) :

      • 有一个 no saved history-历史记录是保持只为期间的 目前会议。
      • 必须使用 Alt+F7来清除控制台的历史记录 ,没有(显而易见的)编程方式来做到这一点(在 cmd.exe控制台窗口中,您可以使用 doskey /reinstall,但是在 PS 中无法使用)。
      • CB. 的答案 向您展示了如何模拟这种键盘组合; 请记住: 这必须在 除了 Clear-History中使用。
    • PSReadline 模块带有 PowerShell v5和 Windows10版本的 v5.1,也将随 Windows Server 2016发布,还附带了跨平台的 一个 href = “ https://github.com/PowerShell/blob/master/README.md”rel = “ noReferrer”> Powershell (Core) v7 + 版本; 它是 replaces the doskey-style line-editing and command-history features with more sophisticated functionality; 也可以使用 PowerShell 图库(PSv3和 PSv4必须首先安装 PowerShellGet)改装旧的 Windows 版本/PS 版本(> = v3)。

      • 命令 历史记录现在是跨会话保存的,在文件中
        (Get-PSReadlineOption).HistorySavePath .
      • [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()可以用来清除 current会话的历史记录 (注意 v1.2 + 也支持 Alt+F7交互式清除当前历史记录)。
        • 警告 : 使用 PSReadline的默认历史保存样式,SaveIncrementally任何敏感的命令已经被保存按时间调用 [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()将重新出现在 < em > 下一个 会话中
        • 处理这个问题的唯一方法是使用 删除保存的历史文件,如 JVimes 的回答所示,然而,不可避免地抹去了整个历史
        • 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 应该 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. 然而,在 v2.1.0(撰写本文时的最新版本)中,SaveAtExit已经完全坏掉了 - no history is saved at all; see https://github.com/lzybkr/PSReadLine/issues/262

下面的 advanced function bundles all commands necessary to clear the command history (both for PowerShell itself and the console), both for ABC0-style and PSReadline-module PowerShell console windows:

注:

  • 因为它是(目前)唯一安全的选项,PSReadline的保存历史文件也被删除,这意味着 整个历史,包括之前的记录,都被清除了

  • 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://stackoverflow.com/a/13257933/45375
$null = [system.reflection.assembly]::loadwithpartialname("System.Windows.Forms")
[System.Windows.Forms.SendKeys]::Sendwait('%{F7 2}')


# Clear PowerShell's own history
Clear-History


}


}

By 最好的答案 from @ mklement0 I ended up with the next function, that is placed in my $PROFILE

我不在乎其他疗程,我只想澄清那段愚蠢的历史,就这样。

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
}

目前,我唯一的解决方案是通过运行一个自动的 Job,定期从文件夹中删除 psreadline.txt 文本。 命令的文件路径是@

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

文件名是 history.txt

还有另一种方法可以删除预测中选定的历史条目

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
}