RBCmd
RBCmd copied to clipboard
FYI: PowerShell script to enumerate Recycle Bin contents with metadata
Hi Man , While using RBCmd for Recycle Bin analysis, I developed a PowerShell script that directly parses $I files and correlates them with nested $R items for forensic purposes. The script may be useful as a complement to RBCmd or could highlight potential functionality worth integrating.
Features
- Recursively scans all user Recycle Bin folders (
C:\$Recycle.Bin\<SID>). - Reads and parses
$I*files to extract:- Original file path before deletion
- File size (at deletion)
- Deletion timestamp (converted from FILETIME to UTC)
- Pairs each
$I*file with its corresponding$R*data folder/file. - Recursively enumerates all items within
$R*(up to 8 levels deep). - Collects forensic metadata for each deleted file/folder:
- User SID (who deleted the file)
- Original path
- Deleted Recycle Bin path
- Deletion timestamp (UTC)
- File name
- File size
- Creation, LastWrite, and LastAccess timestamps (UTC)
- Exports results to a UTF-8 CSV file (
RecycleBin_Forensics.csv).
powershell script :
# Recycle Bin forensic extractor
# Lists deleted files/folders with metadata and maps them to original paths
$results = @()
$Recycle = "$"+"Recycle"
function Get-FileTimeUtc([byte[]]$bytes, [int]$offset) {
$ft = [BitConverter]::ToInt64($bytes, $offset)
if ($ft -gt 0) {
return [DateTime]::FromFileTimeUtc($ft)
}
return $null
}
$recycleBin = "C:\$Recycle.Bin"
# Loop through each SID folder
foreach ($sidDir in Get-ChildItem $recycleBin -Directory -Force) {
$sid = $sidDir.Name
Write-Host "Processing SID: $($sidDir.FullName)"
# Find all $I files (metadata files)
foreach ($iFile in Get-ChildItem $sidDir.FullName -Filter '$I*' -Force) {
try {
$bytes = [System.IO.File]::ReadAllBytes($iFile.FullName)
if ($bytes.Length -lt 24) { continue }
$deletionTime = Get-FileTimeUtc $bytes 16
$pathLen = [BitConverter]::ToInt32($bytes, 24)
$origPath = [System.Text.Encoding]::Unicode.GetString($bytes, 28, $pathLen * 2)
$origPath = $origPath.TrimEnd([char]0) # remove trailing nulls
$origPath = $origPath -replace "^\u0003?","" # strip weird control chars like ␦
# Match the $R file/directory
$rName = $iFile.Name.Replace('$I', '$R')
$rPath = Join-Path $sidDir.FullName $rName
if (Test-Path $rPath) {
# Get all items inside (up to 8 levels)
$items = Get-ChildItem $rPath -Recurse -Force -ErrorAction SilentlyContinue -Depth 8
foreach ($item in $items) {
$results += [PSCustomObject]@{
SID = $sid
OriginalPath = $origPath
DeletedPath = $item.FullName
DeletionTimeUTC= $deletionTime
FileName = $item.Name
IsContainer = $item.PSIsContainer
Size = if ($item.PSIsContainer) { $null } else { $item.Length }
CreationTime = $item.CreationTimeUtc
LastWriteTime = $item.LastWriteTimeUtc
LastAccessTime = $item.LastAccessTimeUtc
}
}
}
} catch {
Write-Warning "Error parsing $($iFile.FullName): $_"
}
}
}
# Export results
$results | Export-Csv -Path .\RecycleBin_Forensics.csv -NoTypeInformation -Encoding UTF8
This isn’t a replacement for RBCmd by any means, but more of a quick-and-dirty helper script. It might be useful for quick triage, or maybe as inspiration for additional RBCmd functionality around nested $R* content.
mini output for illustration :
| SID | OriginalPath | DeletedPath | FileName | DeletionTimeUTC |
|---|---|---|---|---|
| S-1-5-21-2562676247-2455829573-1000 | C:\Users\user1 | C:$Recycle.Bin\S-1-5-21-2562676247-2455829573-1000$RZ9AYH3 | $RZ9AYH3 | 2022-03-20 16:20:00 |
| S-1-5-21-2562676247-2455829573-1000 | C:\Users\user1\host | C:$Recycle.Bin\S-1-5-21-2562676247-2455829573-1000$RZ9AYH3\host | host | 2022-03-20 16:20:00 |
| S-1-5-21-2562676247-2455829573-1000 | C:\Users\user1\host\file.txt | C:$Recycle.Bin\S-1-5-21-2562676247-2455829573-1000$RZ9AYH3\host\file.txt | file.txt | 2022-03-20 16:20:00 |
Feel free to test it and give feedback!