PowerShellTranscripts

Author: Andrew Rathbun and Chad Tilbury

PowerShell Transcripts

Paths

6 paths
Paths use Windows environment variable syntax
CyberChef recipes

Open in CyberChef to decode values extracted from this artifact.

References

Notes

These logs appear when auditing is turned on via Group Policy or Start-Transcript is used during PowerShell execution

As more locations are observed, they will be added here

Example location: C:\Users\USERNAME\Documents\20220301\PowerShell_transcript.DEVICENAME.qp9EOTN2.20220301132612.txt

Example location 2: C:\PSTranscript\20250311\PowerShell_transcript.DEVICENAME.1234AbCd.20250311212612.txt

Collection commands

# PowerShell Artifact Collection Script
# Target: PowerShellTranscripts
# Run as Administrator

#Requires -RunAsAdministrator

$ErrorActionPreference = "Continue"
$SourceRoot = "C:"
$DestBase   = "D:\Evidence"
$Summary = @{ Copied = 0; Missed = 0; Errors = 0 }

function Collect-Artifact {
    param(
        [Parameter(Mandatory)][string]$SourceDir,
        [Parameter(Mandatory)][string]$FolderName,
        [string]$FileMask = "*"
    )
    # Expand wildcards in any path segment (e.g. 'Program Files*',
    # 'ScreenConnect Client*'). robocopy itself does not glob the source.
    $sources = @(Get-Item -Path $SourceDir -ErrorAction SilentlyContinue |
        Where-Object { $_.PSIsContainer })
    if ($sources.Count -eq 0) {
        $Summary.Missed++
        return
    }
    $FullDest = Join-Path -Path $DestBase -ChildPath $FolderName
    $null = New-Item -ItemType Directory -Force -Path $FullDest -ErrorAction SilentlyContinue
    foreach ($src in $sources) {
        robocopy $src.FullName "$FullDest" "$FileMask" /E /COPY:DAT /R:0 /W:0 /NP /NFL /NDL /NJH /NJS 2>$null | Out-Null
        if ($LASTEXITCODE -le 7) { $Summary.Copied++ } else { $Summary.Errors++ }
    }
}

# 1. PowerShell Transcripts - Observed Location
Collect-Artifact -SourceDir "C:\Windows\SysWOW64\*" -FileMask "PowerShell_transcript.*.txt" -FolderName "PowerShell_Transcripts_Observed_Location"

# 2. PowerShell Transcripts - Observed Location
Collect-Artifact -SourceDir "C:\Program Files\Amazon\Ec2ConfigService\Scripts\*" -FileMask "PowerShell_transcript.*.txt" -FolderName "PowerShell_Transcripts_Observed_Location"

# 3. PowerShell Transcripts - Observed Location
Collect-Artifact -SourceDir "C:\Windows\System32\*" -FileMask "PowerShell_transcript.*.txt" -FolderName "PowerShell_Transcripts_Observed_Location"

# 4. PowerShell Transcripts - Observed Location
Collect-Artifact -SourceDir "C:\PSTranscript\20*" -FileMask "PowerShell_transcript.*.txt" -FolderName "PowerShell_Transcripts_Observed_Location"

# Iterate every user profile under the source drive
Get-ChildItem "$SourceRoot\Users" -Directory -ErrorAction SilentlyContinue |
    Where-Object { $_.Name -notin @('All Users', 'Default', 'Default User', 'Public') } |
    ForEach-Object {
        $UserName = $_.Name
        # PowerShell Transcripts - Default Location
        $UserPath = "$($_.FullName)\Documents"
        Collect-Artifact -SourceDir $UserPath -FileMask "PowerShell_transcript.*.txt" -FolderName "PowerShell_Transcripts_Default_Location_$UserName"
        # PowerShell Transcripts - Observed Location
        $UserPath = "$($_.FullName)\Documents\20*"
        Collect-Artifact -SourceDir $UserPath -FileMask "PowerShell_transcript.*.txt" -FolderName "PowerShell_Transcripts_Observed_Location_$UserName"
    }

Write-Host ("Collection complete. Copied: {0}  Missed: {1}  Errors: {2}" -f $Summary.Copied, $Summary.Missed, $Summary.Errors) -ForegroundColor Green

Save as .ps1 and run as Administrator. Use: powershell -ExecutionPolicy Bypass -File script.ps1

Included in collections: SANS_TriageCombinedLogsProgramExecution