PowerShell的清除历史记录不会清除历史记录

PowerShell's Clear-History doesn't clear history

最近,我不得不运行一个命令,很不幸,该命令要求我在命令行上直接输入密码。

之后,我用"清除"清除了我的屏幕,但也想清除命令历史记录,这样就不会在会话历史记录中显示有问题的命令。不幸的是,Clear-History cmdlet似乎并没有真正执行其文档所声称的那样-运行Clear-History似乎对会话历史记录没有任何影响。

我仍然可以在弹出的历史记录菜单中看到以前的命令,并通过按向上键在旧命令之间滚动。这是展示问题的屏幕截图:

PowerShell clear history failure

我已经使用Get-Command验证了Clear-History确实在执行预期的内置PowerShell cmdlet。

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

1
Clear-History : Cannot locate history for Id 3.

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


在Windows 10上,即使在Alt + F7和Clear-History之后,历史记录和敏感数据也会在以后的会话中再次显示。事实证明,历史记录存储在以下位置的文本文件中:

1
(Get-PSReadlineOption).HistorySavePath

我从该文件中删除有问题的行或删除整个文件,然后结束当前会话或通过CB的答案将其清除


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

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

要编写脚本,请尝试:

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


为了补充CB。的有用答案和JVimes的有用答案:

  • PowerShell自己的历史记录机制(Get-HistoryClear-History)与主机无关,这就是为什么-有点意外-您还需要分别清除主机的命令历史记录。

  • 至于控制台主机自己的历史记录功能:

    • doskey样式的历史记录功能,在PowerShell随附的模块PSReadline之前(请参见下文):

      • 没有保存的历史记录-历史记录仅在当前会话的持续时间内保留。
      • 必须使用Alt + F7清除控制台的历史记录,而没有(显而易见的)编程方式来执行此操作(在cmd.exe控制台窗口中,您可以使用doskey /reinstall,但这在PS中不起作用)。
      • CB。的答案向您展示了如何模拟这种键盘组合。请记住:除Clear-History之外,还必须使用此选项。
    • PSReadline模块在Windows 10上随PowerShell v5一起提供,并且还将随Windows Server 2016一起提供;它以更复杂的功能取代了doskey样式的行编辑和命令历史记录功能。还可以使用PowerShell库(PowerShell库)(PSv3和PSv4必须首先安装PowerShellGet)使用它来更新较旧的Windows版本/ PS版本(> = v3)版本。

      • 现在,命令历史记录跨会话保存在文件中
        (Get-PSReadlineOption).HistorySavePath
      • [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()可用于清除当前会话的历史记录(请注意,v1.2 +还支持Alt + F7用于交互式清除当前历史记录。

        • 注意:使用PSReadline的默认历史保存样式SaveIncrementally,在您调用[Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()时,所有敏感命令都已保存,并将在下一个会话中重新出现。
        • 解决此问题的唯一方法是删除保存的历史文件,如JVimes的回答所示,该文件总是会擦除整个历史记录。
        • 如果您将个人资料设置为每次会话开始时都呼叫Set-PSReadlineOption -HistorySaveStyle SaveAtExit-设置本身似乎不会"粘"-您应该能够仅通过呼叫[Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()(除了Clear-History)而不必还必须删除保存的历史记录文件,在这种情况下,您将不会丢失以前会话中保存的历史记录。但是,从v1.2开始,SaveAtExit完全中断了-根本没有保存任何历史记录;参见https://github.com/lzybkr/PSReadLine/issues/262

以下高级功能捆绑了用于清除命令历史记录的所有命令(对于PowerShell本身和控制台)(对于doskey样式和PSReadline -module PowerShell控制台窗口):

注意:

  • 因为它是(当前)唯一安全的选项,所以PSReadline的保存历史文件也将被删除,这意味着将清除包括以前会话在内的整个历史记录。

  • 因此,默认情况下会显示确认提示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<#
# .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

  }

}