Skip to content

Instantly share code, notes, and snippets.

@Qazeer
Created August 2, 2023 14:03
Show Gist options
  • Save Qazeer/3a6d43a117bbece6d83e7e79687e0870 to your computer and use it in GitHub Desktop.
Save Qazeer/3a6d43a117bbece6d83e7e79687e0870 to your computer and use it in GitHub Desktop.
Recursively process the specified input folder to execute bmc-tools.exe over each Bitmap Cache subfolder(s) found.
<#
.SYNOPSIS
Recursively process the specified input folder to execute bmc-tools.exe over each Bitmap Cache subfolder(s) found.
This PowerShell script is basically a wrapper to make bmc-tools.exe output results to user specific folders.
bmc-tools is a RDP Bitmap Cache parser from ANSSI (https://github.com/ANSSI-FR/bmc-tools).
.PARAMETER bmcToolsBinary
Specify the bmc-tools.exe binary full path. Can be found on GitHub, with instruction to compile from source using PyInstaller: https://github.com/Qazeer/bmc-tools-compiled
.PARAMETER InputDir
Specify the folder which contains the Bitmap cache file(s). Ideally, the C:\ or C:\Users|Utilisateurs|Usuarios|Benutzer directory in order to process the file(s) from all users.
.PARAMETER OutputDir
Specify the folder where the outputs will be placed.
#>
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true,
Position = 1,
HelpMessage = 'Specify the bmc-tools.exe binary full path.')]
[String]$bmcToolsBinary,
[Parameter(Mandatory = $true,
Position = 2,
HelpMessage = 'Specify the folder which contains the Bitmap cache file(s). Ideally, the C:\ or C:\Users|Utilisateurs|Usuarios|Benutzer directory in order to process the file(s) from all users.')]
[String]$InputDir,
[Parameter(Mandatory = $true,
Position = 3,
HelpMessage = 'Specify the folder where the outputs will be placed.')]
[String]$OutputDir
)
try {
# Check if $bmcToolsBinary exists.
if (-not (Test-Path -Path $bmcToolsBinary -PathType Leaf)) {
throw "The $bmcToolsBinary binary does not exist."
}
# Check if $InputDir exists.
if (-not (Test-Path -Path $InputDir -PathType Container)) {
throw "The directory $InputDir does not exist."
}
# Create the $OutputDir path if it does not exist.
if (-not (Test-Path -Path $OutputDir -PathType Container)) {
# Create the directory, but do not prompt for confirmation (-Confirm:$false).
[void] (New-Item -ItemType Directory -Path $OutputDir -Confirm:$false)
}
# Regex pattern to extract username from file path.
$usernameRegex = "\\(Users|Utilisateurs|Usuarios|Benutzer)\\(.+?)\\AppData\\"
# Look for bitmap cache files in $InputDir.
$files = Get-ChildItem -Path $InputDir -Recurse -ErrorAction Stop | Where-Object { $_.name -match "^bcache[0-9]*\.bmc$" -or $_.name -match "^Cache[0-9]*\.bin$" }
# Retrieve the folder(s) containg bitmap cache files, in a set to only retrieve each folder once.
$bitmapCacheFolders = New-Object System.Collections.Generic.HashSet[string]
foreach ($file in $files) {
$null = $bitmapCacheFolders.Add($file.Directory)
}
# Check if files and folders were found.
if ($null -eq $files -or $files.Count -eq 0) {
Write-Host "No bitmap cache file(s) were found in $InputDir"
}
else {
Write-Host "Found $($files.Count) bitmap cache file(s) accross $($bitmapCacheFolders.Count) directories in $InputDir"
}
# Parse the bitmap cache files from each folders, one folder by one folder.
foreach ($bitmapCacheFolder in $bitmapCacheFolders) {
$folderItem = Get-Item $bitmapCacheFolder
# Extract username from file path.
$folderItem -match $usernameRegex | Out-Null
$username = $matches[2]
# Output folder, specific for each user.
$outputPath = $([IO.Path]::Combine($OutputDir, "RDP_BitmapCache_$username"))
if (-not (Test-Path -Path $outputPath -PathType Container)) {
[void] (New-Item -ItemType Directory -Path $outputPath -Confirm:$false)
}
Start-Process -NoNewWindow -Wait $bmcToolsBinary -ArgumentList "-s `"$bitmapCacheFolder`" -d `"$outputPath`"" -RedirectStandardOutput "$(Join-Path $OutputPath "bmc-tools_stdout.log")"
}
}
catch [System.Exception] {
# If an error occurred, print error details
Write-Error "An error occurred while running this script"
Write-Error "Exception type: $($_.Exception.GetType().FullName)"
Write-Error "Exception message: $($_.Exception.Message)"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment