По-умолчанию в Windows, все команды, введенные в консоли PowerShell, сохраняются в текстовый лог-файл. Благодаря этому вы можете в любой момент повторно выполнить любую команду и просмотреть историю выполненных команд PowerShell даже после закрытия консоли или перезагрузки компьютера. В PowerShell сейчас используются два провайдера истории команда: история команд в текущей сессии (выводит командлет Get-History) и текстовый лог с предыдущими командами, которые сохраняет модуль PSReadLine.
Содержание:
- Просмотр история команд в PowerShell
- Поиск в истории команд PowerShell
- Настройка истории команд PowerShell с помощью модуля PSReadLine
- Как не сохранять определенные команды в историю PoweShell?
- Использование Predictive IntelliSense для набора команд по истории
- Очистка истории предыдущих команд в PowerShell
- Импорт истории команд PowerShell в другую сессию
Просмотр история команд в PowerShell
Если нажать клавишу “вверх” в консоли PowerShell, перед вами появится последняя введенная вами команда. Если продолжить нажать клавишу «вверх» — вы увидите все команды, выполненные вами ранее. Таким образом с помощью клавиш «вверх» и «вниз» вы можете прокручивать историю команд PowerShell и повторно выполнять ранее набранные команды. Это удобно, если вам нужно быстро выполнить одну из предыдущих команд, не набирая ее заново.
Консоль PowerShell сохраняет полную историю команд, начиная с версии Windows PowerShell 5.1 (устанавливается по умолчанию начиная с Windows 10). В более ранних версиях Windows PowerShell (как и командная строка cmd) сохраняет историю выполненных команд только в текущей сессии PowerShell. Для просмотра истории предыдущих команд в текущей сессии используется командлет
Get-History
.
Чтобы вывести подробную информацию о ранее выполненных командах в текущей сессии PowerShell, в том числе время запуска/окончания команды:
Get-History | Format-List -Property *
Вы можете выполнить команду по ее ID:
Invoke-History 4
Если вы закрыли консоль PowerShell, то история команд сбрасывается и список в Get-History очищается.
Однако PowerShell 5.1 и PowerShell Core также сохраняют последние 4096 команд в тестовом файле в профиле каждого пользователя
%userprofile%\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt
.
Вы можете открыть этот файл и просмотреть историю команд в любом текстовом редакторе. Например, чтобы открыть файл с журналом команд с помощью блокнота:
notepad (Get-PSReadLineOption | select -ExpandProperty HistorySavePath)
История ведется отдельно для консоли PowerShell, отдельно для ISE.
Если команда PowerShell требует длительное время на выполнение, вы увидите ее в истории команд только по ее завершении.
В cmd вы можете вывести историю команд в текущей сессии с помощью:
doskey /history
Для поиска используется клавиша
F7
.
Поиск в истории команд PowerShell
Если вы не хотите пролистывать всю историю команд PowerShell, вы можете выполнить поиск по истории команд с помощью комбинаций клавиш CTRL+R (поиск в обратном направлении) и CTRL+S (поиск вперед). Нажмите сочетание клавиш и начните вводить часть команды, которую вы хотите найти в ранее выполненных командах. Выполняется поиск указанного текста на любой позиции в команде (в отличии от поиска в консоли PowerShell по F8 или Shift+F8, которые ищут совпадения только с начала строки). В консоли PowerShell должна появится предыдущая команда, соответствующая поисковой строке. Совпадения строки подсвечивается в команде.
Если найденная команда вас не устраивает, чтобы продолжить поиск по истории, нажмите сочетание
CTRL+R
/
CTRL+S
еще раз. В результате на экране появится следующая команда, соответствующая шаблону поиска.
С помощью клавиши
F8
можно найти в истории команду, соответствующую тексту в текущей командной строке. Например, наберите
get-
и нажмите
F8
. В истории будет найдена последняя команда, соответствующая строке. Чтобы перейти к следующей команде истории, нажмите F8 еще раз.
Также можно использовать символ
#
для поиска в истории команд. Например, чтобы найти последнюю команду, начинающуюся с
Get-WMI
, наберите
#get-wmi
и нажмите клавишу
Tab
. В консоли появится последняя команда, соответствующая шаблону:
Для вывода списка команд в истории, соответствующих запросу, можно использовать:
Get-History | Select-String -Pattern "Get-"
и
Get-Content (Get-PSReadlineOption).HistorySavePath| Select-String -Pattern "Get-"
Настройка истории команд PowerShell с помощью модуля PSReadLine
Функционал хранения истории команд в PowerShell встроен не в сам Windows Management Framework, а основан на дополнительном модуле PSReadLine, который существенно расширяет функционал консоли PowerShell. Модуль PSReadLine в Windows находится в каталоге C:\Program Files\WindowsPowerShell\Modules\PSReadline и автоматически импортируется при запуске консоли PowerShell.
PSReadLine осуществляет подсветку синтаксиса в консоли, отвечает за возможность использования выделения текста мышкой и его копирование/вставку с помощью CTRL+C и CTRL+V.
Проверьте, что модуль загружен в вашу сессию PowerShell:
Get-Module
Если модуль PSReadline не загружен, проверьте что он установлен и если нужно, установите его из онлайн репозитория PowerShell Gallery:
Get-Module -ListAvailable | where {$_.name -like "*PSReadline*"}
Install-Module PSReadLine
Полный список функций модуля PSReadLine для управления историей команд PowerShell и привязанных к ним клавишам можно вывести командой:
Get-PSReadlineKeyHandler | ? {$_.function -like '*hist*'}
Key Function Description --- -------- ----------- Key Function Description --- -------- ----------- UpArrow PreviousHistory Заменить введенные данные предыдущим элементом журнала DownArrow NextHistory Заменить введенные данные следующим элементом журнала Ctrl+R ReverseSearchHistory Выполнить интерактивный поиск по журналу в обратном направлении Ctrl+S ForwardSearchHistory Выполнить интерактивный поиск по журналу в направлении вперед Alt+F7 ClearHistory Удалить все элементы из журнала командной строки (не из журнала PowerShell) F8 HistorySearchBackward Искать предыдущий элемент журнала, который начинается с текущего ввода, например P... Shift+F8 HistorySearchForward Искать следующий элемент журнала, который начинается с текущего ввода, например Ne... Unbound ViSearchHistoryBackward Запускает новый поиск по журналу в направлении назад. Unbound BeginningOfHistory Перейти к первому элементу журнала Unbound EndOfHistory Перейти к последнему элементу (текущий ввод) в журнале
Выведите текущие настройки истории команд PowerShell модуля PSReadLine:
Get-PSReadlineOption | select HistoryNoDuplicates, MaximumHistoryCount, HistorySearchCursorMovesToEnd, HistorySearchCaseSensitive, HistorySavePath, HistorySaveStyle
Здесь могут быть интересны настройки следующих параметров:
- HistoryNoDuplicates – нужно ли сохранять в истории PowerShell одинаковые команды;
- MaximumHistoryCount – максимальное число сохраненных команд (по умолчанию сохраняются 4096 команд);
- HistorySearchCursorMovesToEnd — нужно ли переходить в конец команды при поиске;
- HistorySearchCaseSensitive – нужно ли учитывать регистр при выполнении поиска (по умолчанию при поиске в история команд регистр не учитывается);
- HistorySavePath – путь к текстовому файлу, в который сохраняется история команд PowerShell;
- HistorySaveStyle – особенности сохранения команд:
- SaveIncrementally — команды сохраняются при выполнении (по-умолчанию)
- SaveAtExit — сохранение истории при закрытии консоли
- SaveNothing — не сохранять историю команд
Вы можете изменить настройки модуля PSReadLine с помощью команды Set-PSReadlineOption. Например, чтобы увеличить количество сохраняемых команд PowerShell в логе:
Set-PSReadlineOption -MaximumHistoryCount 10000
Если вам нужно, чтобы в историю команд PowerShell сохранялись не только выполненные команды, но и их вывод, вы можете настроить транскрибирование с помощью следующей функции. Просто добавьте ее в PowerShell профиль пользователя (notepad $profile.CurrentUserAllHosts):
Function StartTranscript {
Trap {
Continue
}
$TranScriptFolder = $($(Split-Path $profile) + '\TranscriptLog\')
if (!(Test-Path -Path $TranScriptFolder )) { New-Item -ItemType directory -Path $TranScriptFolder }
Start-Transcript -Append ($($TranScriptFolder + $(get-date -format 'yyyyMMdd-HHmmss') + '.txt')) -ErrorVariable Transcript -ErrorAction stop
}
StartTranscript
Теперь в профиле пользователя в каталоге
%USERPROFILE%\Documents\WindowsPowerShell\TranscriptLog
для каждого сенаса PowerShell будет содержаться подробный лог-файл.
Как не сохранять определенные команды в историю PoweShell?
В командной оболочке bash в Linux вы можете запретить сохранять в истории команды, которые начинаются с пробела (используется параметр HISTCONTROL= ignorespace). Вы можете настроить такое же поведение и для PowerShell.
Для этого, добавьте в PowerShell профиль текущего пользователя (
$profile.CurrentUserAllHosts
) следующий код:
Set-PSReadLineOption -AddToHistoryHandler { param($command) if ($command -like ' *') { return $false } return $true }
Теперь, если вы не хотите, чтобы ваша команда была сохранена в историю команд PowerShell, просто начните ее с пробела.
Также, начиная с версии модуля PSReadline v2.0.4, автоматически игнорируются и не сохраняются в историю команды, содержащие следующие ключевые слова: Password, Asplaintext, Token, Apikey, Secret. При этом вы можете командлеты из модуля управления паролями SecretManagement считаются безопасными и разрешены для сохранения.
Использование Predictive IntelliSense для набора команд по истории
В версии PSReadLine 2.2.2+ доступна новая функция PowerShell Predictive IntelliSense. Данная функция при наборе команды в консоли выводит наиболее подходящие команды из локальной истории команд.
В этом примере я набрал в консоли get-wm и функция Predictive IntelliSense предложила мне одну из команд, введенных ранее, которая соответствует моему вводу. Если эта команда мне подходит. Если меня устраивает эта команда, нужно нажать клавишу вправо чтобы принять эту команду и не набирать оставшиеся символы вручную.
По умолчанию подсказки Predictive IntelliSense выводятся серым текстом и не очень хорошо читаются на черном фоне консоли PowerShell. Вы можете сделать текст подсказок более контрастным с помощью команды:
Set-PSReadLineOption -Colors @{ InlinePrediction = '#7A957A'}
Predictive IntelliSense по умолчанию включена начиная с PSReadLine 2.2.6. Чтобы включить ее вручную, выполните:
Set-PSReadLineOption -PredictionSource History
Чтобы сбросить предложение Predictive IntelliSense, нажмите Esc.
С помощью клавиши F2 можно переключиться в другое представление. Теперь вместо вывода одной наиболее подходящей команды (
InlineView
) будет выводится выпадающий список со всеми похожими командами (
ListView
).
С помощью клавиш вверх/вниз вы можете быстро выбрать нужную команду из истории команд.
Predictive IntelliSense буте работать как в обычной командной строке pwsh.exe/powershell.exe, так и в Windows Terminal и Visual Studio Code.
Очистка истории предыдущих команд в PowerShell
Как мы рассказали выше, модуль PSReadline сохраняет все консольные команды PowerShell в текстовый файл. Однако в некоторых случаях администратору приходится вводить в консоли PowerShell различную конфиденциальную информацию (имена и пароли учетных записей, токены, адреса, и т.д.). Другой администратор сервера или атакующий может получить доступ к этим чувствительным данным в текстовом файле. В целях безопасности вы можете очистить журнал выполненных команд PowerShell или совсем отключить историю команд.
Командлет
Clear-History
позволяет очистить историю команд только в текущем сеансе PowerShell (очищается список предыдущих команд, которые выводит командлет Get-History).
Можно удалить из истории только одну предыдущую команду:
Clear-History -count 1 -newest
Или все команды по определенной маске:
Clear-History -CommandLine *set-ad*
Чтобы полностью удалить историю предыдущих команд PowerShell, нужно удалить текстовый файл, в который они сохраняются модулем PSReadline. Проще всего это сделать командой:
Remove-Item (Get-PSReadlineOption).HistorySavePath
После этого закройте сессию PoSh.
Чтобы полностью отключить ведение истории команд PowerShell, выполните команду:
Set-PSReadlineOption -HistorySaveStyle SaveNothing
Импорт истории команд PowerShell в другую сессию
В некоторых случаях бывает удобно иметь под рукой один и тот же список часто-используемых команд PowerShell на различных компьютерах. Вы можете экспортировать текущую историю команд в xml файл и импортировать его на других компьютерах. Это можно сделать, скопировав файл ConsoleHost_history.txt в профиле пользователей на нужные компьютеры.
Также для экспорта команд из текущей сессии в файл можно использовать командлет
Export-Clixml
:
Get-History | Export-Clixml -Path c:\ps\commands_hist.xml
Для импорта команд из файла в другую сессию PoSh (на локальном или другом компьютере), выполните:
Add-History -InputObject (Import-Clixml -Path c:\ps\commands_hist.xml)
Для автоматического импорта команд в файл при завершении сессии PoSh, можно привязать скрипт к событию завершения сессии PoSh (!! Сессия обязательно должна завершаться командной exit , а не простым закрытием окна PoSh):
$HistFile = Join-Path ([Environment]::GetFolderPath('UserProfile')).ps_history
Register-EngineEvent PowerShell.Exiting -Action { Get-History | Export-Clixml $HistFile } | out-null
if (Test-path $HistFile) { Import-Clixml $HistFile | Add-History }
I came across a situation where I discovered a user’s PSReadline ConsoleHost_history.txt file, and it ended up giving me the information I needed at the time. Most people are aware of the .bash_history
file. But did you know that the PowerShell equivalent is enabled by default starting in PowerShell v5 on Windows 10? This means this file will become more present over time as systems upgrade.
PSReadline
The PSReadline module started as a stand-alone module, but became the default command line editing experience starting in PowerShell v3. A full list of the features are available on its GitHub page. It is responsible for, among other things, letting us hit up arrow to see previous commands from a PowerShell window. To do this, it records what is typed into the console. It can save this in memory, or to a file.
Starting in PowerShell v5 on Windows 10, the default option is to save history to a file. This setting gives the user the ability to start a new session with the history from the previous session.
History File Information
The default location for this file is $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
. You can get the location by running Get-PSReadlineOption
and looking at the options. There’s a few history related ones:
HistorySavePath
— The file locationHistorySaveStyle
— Options areSaveIncrementally
, which saves after each command;SaveAtExit
, which appends on exiting PowerShell, orSaveNothing
, which turns off the history file.MaximumHistoryCount
— The max number of entries to record.
You can modify the options with the Set-PSReadlineOption
commandlet.
What the History File Records
Everything I type into a PowerShell window. For example:
PS C:\> cd $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\
PS C:\Users\sansforensics408\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine> ls
Directory: C:\Users\sansforensics408\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 11/8/2018 2:11 AM 62 ConsoleHost_history.txt
PS C:\Users\sansforensics408\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine> type .\ConsoleHost_history.txt
cd $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\
ls
type .\ConsoleHost_history.txt
What It Does Not Record
Terminal-less PowerShell sessions. So if I manage to get remote code execution on a host and have it run a Nishang Reverse Shell or Meterpreter, nothing done there is recorded in the file.
Usefulness
For the red-teamer, this is a really interesting way to get information about the commands the user has been running, and files they interact with, and maybe even passwords. For the forensic analyst, having a history of a subject’s actions can be invaluable, and having it in a file is gold. For a blue teamer, this could be useful if you are very lucky, but you’re much better off enabling script-block logging for PowerShell. Most of the things an attacker does in PowerShell, unless they get RDP access, are not going to be recorded. For HackTheBox, you may find some part of an intended path, or you may find some history from the box’s creator who didn’t think or know to clear history.
Те, кто имеет навыки работы с командной строкой, наверняка знают о ее способности сохранять историю выполненных команд во временный лог. Так, просмотреть список всех выполненных во время сеанса команд можно нажатием клавиши F7 либо используя команду doskey /history. Тем более, подобным функционалом обладает PowerShell, позволяющая просматривать историю выполненных команд не только в рамках конкретной сессии, но и после закрытия консоли и даже перезагрузки компьютера.
История команд в текущей сессии
Просмотр истории выполненных команд в рамках текущей сессии PowerShell почти ничем не отличается от просмотра истории команд в классической командной строке.
- Кнопки-стрелки вверх-вниз позволяют переключаться между введенными ранее командами, то же самое делает клавиша F8.
- Клавиша F3 дублирует последнюю команду, клавиша F5 – первую.
- Клавиши F2 копирует, а F4 обрезает предыдущую команду до определенного символа.
- Клавиша F7 открывает окошко со списком выполненных команд, перемещаться между которыми можно с помощью клавиш-стрелок вверх-вниз.
Для вывода списка команд с указанием порядкового номера в PowerShell используется командлет:
Get-History
Или Get-History | Format-List -Property *, если нужно получить о выполненных командах подробные сведения.
Локальная история команд
По завершении сессии история выполненных команд автоматически очищается, однако начиная с версии 5.1, PowerShell научилась сохранять историю выполненных команд в отдельный текстовый файл ConsoleHost_history.txt , расположенный в папке профиля пользователя:
%userprofile%\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline
Открыть его можно Блокнотом.
Или вывести содержимое прямо в консоль командой:
cat (Get-PSReadlineOption).HistorySavePath
Функционал сохранения команд в обновляемый лог реализуется силами модуля PSReadLine, расположенном в системной папке %programfiles%\WindowsPowerShell\Modules\PSReadline.
В PowerShell 5.0 данный модуль отсуствует, но его можно установить из онлайнового репозитория PowerShell Gallery командой:
Install-Module -Name PSReadLine -AllowClobber -Force
Но более правильным решением станет установка актуальной версии PowerShell, уже включающую набор актуальных модулей.
Установка нового модуля для старой версии PowerShell может привести к тому, что у вас перестанет подгружаться старая версия PSReadLine.
Примечание: установить актуальную версию PowerShell можно командой iex «& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI». Инсталляция будет выполнена с помощью классического мастера-установщика.
Модуль PSReadLine
Модулем PSReadLine поддерживается множество настроек и опций управления историей команд, в частности очистка журнала и изменение его размера, интерактивный поиск по журналу в обоих направлениях, исключение определенных команд, изменение расположения лога и так далее.
Что касается работы с локальной историей, помимо выводящей сохраненные команды клавиши F8, особый интерес представляет функция прогнозирования Predictive IntelliSense, доступная и включенная по умолчанию в PSReadLine 2.2.6. Данная функция автоматически подбирает наиболее подходящие команды при наборе, используя историю ранее выполненных и сохраненных в локальном журнале команд. Если предложенная команда подходит, пользователю достаточно нажать клавишу правую стрелку, чтобы PowerShell выполнила автонабор.
Для отображения подсказок консоль по умолчанию использует серый цвет, плохо различимый на черном фоне, но это легко поправить командой Set-PSReadLineOption -Colors @{ InlinePrediction = ‘#63b0cc’}, где #63b0cc – шестнадцатеричный код нового цвета.
Также нужно отметить, что набор горячих клавиш в PowerShell 7.x отличается от набора в PowerShell 5.x.
Вывести список новых хоткеев вы можете командой:
Get-PSReadlineKeyHandler | ? {$_.function -like ‘*hist*’}
By default, Windows saves all of the commands that you type in the PowerShell console to a text log file. This allows you to re-run any command and view the history of the PowerShell commands that you have run, even after you close the console or restart your computer. PowerShell currently uses two command history providers: the history of commands in the current session (displayed by the Get-History cmdlet) and a text log with previous commands that the PSReadLine module saves.
Contents:
- Viewing PowerShell Command History on Windows
- How to Search in PowerShell Command History?
- Configure PowerShell Command History with the PSReadLine Module
- How to Run a PowerShell Command without Saving it to History?
- Using Predictive IntelliSense with PowerShell Command History
- How to Clear the Command History in PowerShell?
- How to Export/Import PowerShell Command History to Another Session?
Viewing PowerShell Command History on Windows
In the PowerShell console, the last command you typed appears when you press the Up key. If you continue to press the “up” key, you will see all the commands executed earlier. Thus, using the “Up arrow
” and “Down arrow
” keys you can scroll through the history of PowerShell commands and re-run previously typed commands. This is useful if you need to quickly execute one of the previous commands without typing it again.
The PowerShell console keeps a complete command history since Windows PowerShell 5.1 (installed by default in Windows 10). In previous versions of Windows PowerShell (and the cmd command prompt), the history of executed commands is available only in the current PowerShell session. Use the Get-History cmdlet to view the history of previous commands in the current session.
You can display more detailed information about previously executed commands in the current PowerShell session, including the command status and start/end/duration time:
Get-History | Format-List -Property *
You can run the previous command by its ID:
Invoke-History 6
The command history is reset and the list in Get-History is cleared when you close the PowerShell console.
However, Windows PowerShell 5.1 and PowerShell Core also save the last 4096 commands in a plain text file in each user’s profile %userprofile%\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt
.
You can open this file and view the command history using any text editor. For example, to open a command log file using Notepad:
notepad (Get-PSReadLineOption | select -ExpandProperty HistorySavePath)
The history log is kept separately for the PowerShell console and for PowerShell ISE.
In cmd.exe, you can display the command history in the current session with:
doskey /history
The F7
key is used to search through cmd history.
How to Search in PowerShell Command History?
If you don’t want to scroll through the entire PowerShell command history using up/down arrows, you can search the command history by using the keyboard shortcuts CTRL+R (reverse search) and CTR +S (forward search). Press the key combination and start typing part of the command you want to find in previously executed commands. The text you entered will be found in the command history in any position (unlike search in PowerShell using F8
or Shift+F8
, which allows looking for the matches from the beginning of the line only). The PowerShell console should display the previous command corresponding to the search string. Line matches are highlighted in the command.
Press CTRL+R
/CTRL+S
again to continue searching the history if the found command is not what you want. As a result, the following command corresponding to the search pattern will appear on the screen.
Using the F8
key, you can search for the command in history that matches the text on the current command line. For example, type get-
and press F8
. The last entry in the command history matching this text will be found. To go to the next command in history, press F8
again.
You can also use the #
character to search through the command history. For example, to find the last command that starts with Get-WMI, type #get-wmi
and press the Tab
key. The last command matching the pattern will appear in the console:
To display a list of commands in history that match a query, you can use:
Get-History | Select-String -Pattern "Get-"
And grep the results using the pipe:
Get-Content (Get-PSReadlineOption).HistorySavePath| Select-String -Pattern "Get-"
Configure PowerShell Command History with the PSReadLine Module
The command history functionality in PowerShell is not built into the Windows Management Framework itself but is based on the PSReadLine module, which greatly enhances the functionality of the PowerShell console. The PSReadLine module on Windows is located in C:\Program Files\WindowsPowerShell\Modules\PSReadline folder and is automatically imported when you start the PowerShell console.
PSReadLine provides syntax highlighting in the console, is responsible for the ability to use text selection with the mouse and its copy/paste using CTRL+C
and CTRL+V
.
Check that the module is loaded into your current PowerShell session:
Get-Module
If the PSReadline module is not loaded, verify that it is installed. If necessary, install it from the PowerShell Gallery online repository:
Get-Module -ListAvailable | where {$_.name -like "*PSReadline*"}
Install-Module PSReadLine
A complete list of functions of the PSReadLine module for managing the commands history in PowerShell and the keys assigned to them can be displayed with the command:
Get-PSReadlineKeyHandler | ? {$_.function -like '*hist*'}
Key Function Description --- -------- ----------- UpArrow PreviousHistory Replace the input with the previous item in the history DownArrow NextHistory Replace the input with the next item in the history Ctrl+r ReverseSearchHistory Search history backwards interactively Ctrl+s ForwardSearchHistory Search history forward interactively Alt+F7 ClearHistory Remove all items from the command line history (not PowerShell history) F8 HistorySearchBackward Search for the previous item in the history that starts with the current input - like NextHistory if the input is empty Shift+F8 HistorySearchForward Search for the next item in the history that starts with the current input - like NextHistory if the input is empty Unbound ViSearchHistoryBackward Starts a new seach backward in the history. Unbound BeginningOfHistory Move to the first item in the history Unbound EndOfHistory Move to the last item (the current input) in the history
List the current PowerShell command history settings in the PSReadLine module:
Get-PSReadlineOption | select HistoryNoDuplicates, MaximumHistoryCount, HistorySearchCursorMovesToEnd, HistorySearchCaseSensitive, HistorySavePath, HistorySaveStyle
You may want to consider the following PSReadline parameters:
- HistoryNoDuplicates – whether the same commands have to be saved;
- MaximumHistoryCount – the maximum number of the stored commands (by default the last 4096 commands are saved);
- HistorySearchCursorMovesToEnd — whether it is necessary to jump to the end of the command when searching;
- istorySearchCaseSensitive – whether a search is case sensitive (PowerShell command history is not case sensitive by default);
- HistorySavePath – path to a text file where the history of PowerShell commands is stored;;
- HistorySaveStyle – command history saving options:
- SaveIncrementally — the commands are saved when executed (by default);
- SaveAtExit —the history is saved when you close the PowerShell console;
- SaveNothing — disable saving command history.
You can change the PSReadLine module settings with the Set-PSReadlineOption command. For example, to increase the number of PowerShell commands stored in the log:
Set-PSReadlineOption -MaximumHistoryCount 10000
If you want to save not only the executed commands but also their output in the PowerShell command history, you can enable command transcription. Just add the following function to the user’s PowerShell profile (notepad $profile.CurrentUserAllHosts
):
Function StartTranscript {
Trap {
Continue
}
$TranScriptFolder = $($(Split-Path $profile) + '\TranscriptLog\')
if (!(Test-Path -Path $TranScriptFolder )) { New-Item -ItemType directory -Path $TranScriptFolder }
Start-Transcript -Append ($($TranScriptFolder + $(get-date -format 'yyyyMMdd-HHmmss') + '.txt')) -ErrorVariable Transcript -ErrorAction stop
}
StartTranscript
The user profile now contains a detailed log file for each PowerShell session in the %USERPROFILE%\Documents\WindowsPowerShell\TranscriptLog
directory.
How to Run a PowerShell Command without Saving it to History?
In the Linux bash shell, you can disable history for commands starting with spaces (with HISTCONTROL= ignorespace
). You can configure similar behavior for PowerShell.
To do this, add the following code to the current user’s PowerShell profile ( $profile.CurrentUserAllHosts
):
Set-PSReadLineOption -AddToHistoryHandler { param($command) if ($command -like ' *') { return $false } return $true }
This feature requires that you set the PowerShell Execution policy on your computer to Remotesigned:
Set-ExecutionPolicy Remotesigned
Now, just start your command with a space if you don’t want it to be saved in the PowerShell command history.
Also, starting with the Readline v2.0.4 module version, commands containing the following keywords are automatically ignored and not saved to the history: Password
, Asplaintext
, Token
, Apikey
, Secret
.
Using Predictive IntelliSense with PowerShell Command History
A new PowerShell Predictive IntelliSense feature is available in PSReadLine 2.2.2+. This feature displays the most appropriate commands from the local command history when you type a command in the PowerShell console.
In this example, I typed get-wm
in the console, and Predictive IntelliSense suggested one of the commands I typed earlier that matched my input. If this command suits me, I need to press the right arrow key
to accept this command and not type the rest of the characters manually.
By default, Predictive IntelliSense hints are displayed in gray text and are difficult to read against the black background of the PowerShell console. This command makes the suggested text more contrasting:
Set-PSReadLineOption -Colors @{ InlinePrediction = '#7A957B'}
Since PSReadLine 2.2.6, Predictive IntelliSense is enabled by default. You can enable it manually:
Set-PSReadLineOption -PredictionSource History
To reset the IntelliSense predictive suggestion, press the Esc key.
You can switch to another view by pressing the F2 key. Now, instead of displaying one most appropriate command (InlineView
), a drop-down list with all similar commands will be displayed (ListView
).
Use the up/down keys to quickly select a command you need from the command history.
Predictive IntelliSense works in the standard pwsh.exe/powershell.exe command line, as well as in the Windows Terminal and Visual Studio code.
How to Clear the Command History in PowerShell?
As we explained above, the PSReadline module saves all PowerShell console commands to a text file. However, in some cases, the administrator has to enter various sensitive information into the PowerShell console (credentials, passwords, tokens, addresses, personal data, etc.). History data in a plain text file can be accessed by another server administrator or attacker. For security reasons, you might have to clear the history of the PowerShell commands that you have run or turn off the command history completely.
The Clear-History cmdlet allows you to clear the history of commands only in the current PowerShell session. It only deletes the previous command list that Get-History returns.
You can remove only one previous command from the history:
Clear-History -count 1 -newest
Or clear all commands with a specific pattern:
Clear-History -CommandLine *set-ad*
To completely clear the history of previous PowerShell commands, you need to delete the ConsoleHost_history.txt file that the PSReadline module writes to. You can get the current PowerShell history file location and remove it with the command:
Remove-Item (Get-PSReadlineOption).HistorySavePath
After that, close the PowerShell console window.
If you want to completely disable saving the history of PowerShell commands to a text file, run the command:
Set-PSReadlineOption -HistorySaveStyle SaveNothing
How to Export/Import PowerShell Command History to Another Session?
Sometimes it is convenient to have the same set of frequently used PowerShell commands on different computers. You can export the current command history on your computer to an XML file and import it to other computers. You can do this by copying the ConsoleHost_history.txt file in the user’s profile to the target computers.
You can also use the Export-Clixml
cmdlet
to export command history from the current session to a text file:
Get-History | Export-Clixml -Path c:\ps\commands_hist.xml
To import command history from a file into another PowerShell session (on a local computer or on a different computer):
Add-History -InputObject (Import-Clixml -Path c:\ps\commands_hist.xml)
To automatically export the previous commands to a file when the PowerShell session ends, you can bind the script to the PoSh session end event (!! The session must be terminated with the exit
command, r, not by simply closing the PowerShell console):
$HistFile = Join-Path ([Environment]::GetFolderPath('UserProfile')) .ps_history
Register-EngineEvent PowerShell.Exiting -Action { Get-History | Export-Clixml $HistFile } | out-null
if (Test-path $HistFile) { Import-Clixml $HistFile | Add-History }
There are a few PowerShell EventLogs and some files containing your PowerShell history and the commands, script blocks, etc., that you have used. This can be very helpful if your computer or servers are hacked at your office. Or, if you want to check things 😉 In this blog post, I will show you how to retrieve all those events locally and remotely and save those in an Excel sheet.
- What are the PowerShell logs being collected?
- How does the script work?
- Running the script
- Example Excel file
- The script
What are the PowerShell logs being collected?
In Windows, there are a few default PowerShell EventLogs available:
- Windows PowerShell
- PowerShellCore/Operational
- Microsoft-Windows-PowerShell/Admin
- Microsoft-Windows-PowerShell/Operational
- Microsoft-Windows-PowerShell-DesiredStateConfiguration-FileDownloadManager/Operational
- Microsoft-Windows-WinRM/Operational
These EventLogs contain information about scripts and script blocks used on the system or DSC information. (The script can modify the list to include other EventLogs if needed.)
There are also logs containing all the commands typed in your PowerShell sessions, which were recorded by the PSReadline module. The location of these files is C:\Users\{UserName}\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine.
How does the script work?
You can start the script and specify these parameters:
- -Computername You can specify one (W2K22DC, for example) or multiple separated by a comma (“W2K22DC, W2K22Member”, for example). If not specified, it will be your local system.
- -Filename You can specify the location of the Excel sheet in which the results will be saved. C:\Temp\Events.xlsx, for example. The FileName parameter is Mandatory.
- -PowerShellEventLogOnly When specified, the script will only export events from the EventLogs and not from the PSReadLine history.
- -PSReadLineHistoryOnly When specified, the script will only export the command lines found in the PSReadLine history files, not the EventLogs data.
The data is being saved to an Excel file in two tabs, one for the EventLog data and one for the PSReadline history. When you run it against multiple computers, you can filter those on the ComputerName column.
The script also checks if the specified Excel file is already present and will append data to it if that’s the case. Both tabs have a time and date suffix, including the time you ran it so that it won’t insert the same date twice.
If the script can’t access something, it will show that on screen as a warning message. Green lines are good, and grey ones are information (That it couldn’t find events in a certain log, for example)
Running the script
Below is the screen status output when I ran the script on my Windows Server 2022 Domain Controller and specified (using the -ComputerName parameter) to scan that and the Windows 2022 member server. The output is saved to c:\temp\events.csv (Using the -Filename parameter).
Screen output of the script
Example Excel file
Based on the two scanned servers above, the Excel file looks like this:
The PowerShell Eventlogs
Some of the messages are very long. To view it in the cell, you can double-click it or use the Wrap Text button to let it expand for you:
An expanded cell to view its contents
You can use the Filter on the ComputerName, for example, to display only a specific machine or to filter for a specific keyword:
Filtering computers or text
Below is a screenshot of the PSReadLine history; as you can see, it shows all your history. 🙂 (This is dangerous if you have credentials, API keys in it, etc.)
PSReadLine History
The script
Below are the contents of the Get-PowerShellLogs script. Save it somewhere (c:\scripts\Get-PowerShellLogs.ps1, for example) and run it with the abovementioned parameters. For example:
C:\Scripts\Get-PowerShellLogs.ps1 -ComputerName w2k22member -Filename C:\Temp\events.xlsx -PowerShellEventlogOnly
Get-PowerShellLogs.ps1
#Requires -RunAsAdministrator [CmdletBinding(DefaultparameterSetname = 'All')] param( [parameter(Mandatory = $false)][string[]]$ComputerName = $env:COMPUTERNAME, [parameter(Mandatory = $true)][string]$Filename, [parameter(Mandatory = $false, parameterSetname = "EventLog")][switch]$PowerShellEventlogOnly, [parameter(Mandatory = $false, parameterSetname = "History")][switch]$PSReadLineHistoryOnly ) #Validate output $filename if (-not ($Filename.EndsWith('.xlsx'))) { Write-Warning ("Specified {0} filename does not end with .xlsx, exiting..." -f $Filename) return } #Check access to the path, and if the file already exists, append if it does or test the creation of a new one if (-not (Test-Path -Path $Filename)) { try { New-Item -Path $Filename -ItemType File -Force:$true -Confirm:$false -ErrorAction Stop | Out-Null Remove-Item -Path $Filename -Force:$true -Confirm:$false | Out-Null Write-Host ("Specified {0} filename is correct, and the path is accessible, continuing..." -f $Filename) -ForegroundColor Green } catch { Write-Warning ("Path to specified {0} filename is not accessible, correct or file is in use, exiting..." -f $Filename) return } } else { Write-Warning ("Specified file {0} already exists, appending data to it..." -f $Filename) } #Check if the ImportExcel module is installed. Install it if not if (-not (Get-Module -ListAvailable -Name ImportExcel)) { Write-Warning ("The ImportExcel module was not found on the system, installing now...") try { Install-Module -Name ImportExcel -SkipPublisherCheck -Force:$true -Confirm:$false -Scope CurrentUser -ErrorAction Stop Import-Module -Name ImportExcel -Scope Local -ErrorAction Stop Write-Host ("Successfully installed the ImportExcel module, continuing..") -ForegroundColor Green } catch { Write-Warning ("Could not install the ImportExcel module, exiting...") return } } else { try { Import-Module -Name ImportExcel -Scope Local -ErrorAction Stop Write-Host ("The ImportExcel module was found on the system, continuing...") -ForegroundColor Green } catch { Write-Warning ("Error importing the ImportExcel module, exiting...") return } } #List of PowerShell event logs to search in $Eventlogs = @( 'Windows PowerShell' 'PowerShellCore/Operational' 'Microsoft-Windows-PowerShell/Admin' 'Microsoft-Windows-PowerShell/Operational' 'Microsoft-Windows-PowerShell-DesiredStateConfiguration-FileDownloadManager/Operational' 'Microsoft-Windows-WinRM/Operational' ) #Set dateformat for the Excel tabs $date = Get-Date -Format ddMMyyhhmm #Loop through all computers specified in $ComputerName. If not specified, it will use your local computer foreach ($computer in $ComputerName | Sort-Object) { #Check if the computer is reachable if (Test-Path -Path "\\$($computer)\c$" -ErrorAction SilentlyContinue) { Write-Host ("`nComputer {0} is accessible, continuing..." -f $computer) -ForegroundColor Green #Eventlogs if (-not $PSReadLineHistoryOnly) { #Search all EventLogs specified in the $eventlogs variable $TotalEventLogs = foreach ($Eventlog in $Eventlogs) { $events = Get-WinEvent -LogName $Eventlog -ComputerName $computer -ErrorAction SilentlyContinue if ($events.count -gt 0) { Write-Host ("- Exporting {0} events from the {1} EventLog" -f $events.count, $Eventlog) -ForegroundColor Green foreach ($event in $events) { [PSCustomObject]@{ ComputerName = $computer EventlogName = $Eventlog TimeCreated = $event.TimeCreated EventID = $event.Id Message = $event.Message } } } else { Write-Host ("- No events found in the {0} Eventlog" -f $Eventlog) -ForegroundColor Gray } } #Create an Excel file and add an Eventlog tab containing the events for the computer if ($TotalEventLogs.count -gt 0) { try { $TotalEventLogs | Export-Excel -Path $Filename -WorksheetName "PowerShell_EventLog_$($date)" -AutoFilter -AutoSize -Append Write-Host ("Exported Eventlog data to {0}" -f $Filename) -ForegroundColor Green } catch { Write-Warning ("Error exporting Eventlog data to {0} (File in use?), exiting..." -f $Filename) return } } } #PSreadLineHistory if (-not $EventlogOnly) { #Search for all PSReadLine history files in all Windows User profiles on the system if (-not $PowerShellEventlogOnly) { Write-Host ("Checking for Users/Documents and Settings folder on {0}" -f $computer) -ForegroundColor Green try { if (Test-Path "\\$($computer)\c$\Users") { $UsersFolder = "\\$($computer)\c$\Users" } else { $UsersFolder = "\\$($computer)\c$\Documents and Settings" } } catch { Write-Warning ("Error finding Users/Documents and Settings folder on {0}. Exiting..." -f $computer) return } Write-Host ("Scanning for PSReadLine History files in {0}" -f $UsersFolder) -ForegroundColor Green $HistoryFiles = foreach ($UserProfileFolder in Get-ChildItem -Path $UsersFolder -Directory) { $list = Get-ChildItem -Path "$($UserProfileFolder.FullName)\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\*.txt" -ErrorAction SilentlyContinue if ($list.count -gt 0) { Write-Host ("- {0} PSReadLine history file(s) found in {1}" -f $list.count, $UserProfileFolder.FullName) -ForegroundColor Green foreach ($file in $list) { [PSCustomObject]@{ HistoryFileName = $file.FullName } } } else { Write-Host ("- No PSReadLine history file(s) found in {0}" -f $UserProfileFolder.FullName) -ForegroundColor Gray } } #Get the contents of the found PSReadLine history files on the system $TotalHistoryLogs = foreach ($file in $HistoryFiles) { $HistoryData = Get-Content -Path $file.HistoryFileName -ErrorAction SilentlyContinue if ($HistoryData.count -gt 0) { Write-Host ("- Exporting {0} PSReadLine History events from the {1} file" -f $HistoryData.count, $file.HistoryFileName) -ForegroundColor Green foreach ($line in $HistoryData) { if ($line.Length -gt 0) { [PSCustomObject]@{ ComputerName = $computer FileName = $File.HistoryFileName Command = $line } } } } else { Write-Warning ("No PSReadLine history found in the {0} file" -f $Log) } } #Create an Excel file and add the PSReadLineHistory tab containing PowerShell history if ($TotalHistoryLogs.count -gt 0) { try { $TotalHistoryLogs | Export-Excel -Path $Filename -WorksheetName "PSReadLine_History_$($date)" -AutoFilter -AutoSize -Append Write-Host ("Exported PSReadLine history to {0}" -f $Filename) -ForegroundColor Green } catch { Write-Warning ("Error exporting PSReadLine history data to {0} (File in use?), exiting..." -f $Filename) return } } } } } else { Write-Warning ("Specified computer {0} is not accessible, check permissions and network settings. Skipping..." -f $computer) continue } }
Download the script(s) from GitHub here