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?
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