Skip to main content

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
ValueMeaning
EnableTranscripting = 1Transcripts enabled
OutputDirectoryWhere 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

SourceLocation
TranscriptsC:\Transcripts\ or OutputDirectory in registry
PSReadLine historyAppData\...\PSReadLine\ConsoleHost_history.txt
Module logsEvent Log: Microsoft-Windows-PowerShell/Operational
Script block logsEvent ID 4104
Hardcoded creds.ps1 files with ConvertTo-SecureString