<#
===========================================================================================
| |
| Variables |
| |
===========================================================================================
#>
$rarExecutablePath = "${env:ProgramFiles}\WinRAR\rar.exe"
$dictionarySizesMb = @(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048)
$toleranceSizeDiff = 100kb
$keepOnlySmallestRarFile = $true
$sendRarFilesToRecycleBin = $false
$compressedFileTypesArchive = @(
"7z" , "arc", "bz2" , "bzip", "bzip2",
"gz" , "gz2", "gza" , "gzi" , "gzip" ,
"lha", "lz" , "lz4" , "lzh" , "lzma" ,
"rar", "sfx", "tgz" , "tlz" , "tlzma",
"uha", "zip", "zipx", "zpaq"
)
$compressedFileTypesAudio = @(
"aac", "ac3", "fla","flac",
"m4a", "mp3", "ogg", "ogm",
"usm", "wma"
)
$compressedFileTypesVideo = @(
"asf", "avc", "avi" , "bik" , "bk2" , "f4v" , "flv" ,
"m1v", "m2t", "m2ts", "m2v" , "m4v" , "mpv4",
"mkv", "mov", "mp4" , "mpeg", "mpg" , "mts" ,
"qt" , "ts" , "vob" , "vp6" , "webm", "wmv"
)
$compressedFileTypesOther = @(
"avif", "jpeg", "jpg" , "gif" , "pdf",
"pam" , "paq6", "paq7", "paq8",
"par" , "par2", "wad"
)
[string]$fileTypesToKeepUncompressed = (
$compressedFileTypesArchive +
$compressedFileTypesAudio +
$compressedFileTypesVideo +
$compressedFileTypesOther
) -join ';'
<#
===========================================================================================
| |
| rar.exe commands (only those used in this script) |
| |
===========================================================================================
<Commands>
a Add files to archive
<Switches>
-am[s,r] Archive name and time [save, restore]
-c- Disable comments show
-cfg- Ignore configuration file and RAR environment variable.
-dh Open shared files
-ep1 Exclude base directory from names
-ht[b|c] Select hash type [BLAKE2,CRC32] for file checksum
-id[c,d,n,p,q] Display or disable messages
-ilog[name] Log errors to file
-isnd[-] Control notification sounds
-m<0..5> Set compression level (0-store...3-default...5-maximal)
-ma[4|5] Specify a version of archiving format
-md<n>[k,m,g] Dictionary size in KB, MB or GB
-ms[list] Specify file types to store.
-o[+|-] Set the overwrite mode
-oc Set NTFS Compressed attribute.
-oh Save hard links as the link instead of the file
-oi[0-4][:min] Save identical files as references
-ol[a] Process symbolic links as the link [absolute paths]
-oni Allow potentially incompatible names
-qo[-|+] Add quick open information [none|force]
-r Recurse subdirectories
-ri<P>[:<S>] Set priority (0-default,1-min..15-max) and sleep time in ms
-s- Disable solid archiving
-t Test files after archiving
-tk Keep original archive time
-tl Set archive time to newest file
-ts[m,c,a,p] Save or restore time (modification, creation, access, preserve)
-u Update files
-w<path> Assign work directory
#>
<#
===========================================================================================
| |
| .NET Code |
| |
===========================================================================================
#>
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class Win32Functions {
[DllImport("Shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern long StrFormatByteSizeW(long fileSize, System.Text.StringBuilder buffer, int bufferSize);
}
"@
<#
===========================================================================================
| |
| Functions |
| |
===========================================================================================
#>
function Format-FileSize {
param(
[long]$fileSize
)
$buffer = New-Object System.Text.StringBuilder 260
[Win32Functions]::StrFormatByteSizeW($fileSize, $buffer, $buffer.Capacity) | Out-Null
return $buffer.ToString()
}
function Show-WelcomeScreen {
Clear-Host
Write-Host ""
Write-Host " $($host.ui.RawUI.WindowTitle)"
Write-Host " +========================================================+"
Write-Host " | |"
Write-Host " | This script will use RAR.exe to compress each file in |"
Write-Host " | the current working directory individually, each using |"
Write-Host " | different dictionary sizes, with max. compression, |"
Write-Host " | generating this way multiple RAR files for evaluating |"
Write-Host " | compression rates on these dictionary sizes. |"
Write-Host " | |"
Write-Host " +=========================================================+"
Write-Host ""
Write-Host " Script Settings " -ForegroundColor DarkGray
Write-Host " ===========================" -ForegroundColor DarkGray
Write-Host " RAR Executable Path: $([System.IO.Path]::GetFullPath($rarExecutablePath))" -ForegroundColor Gray
Write-Host "" -ForegroundColor DarkGray
Write-Host " Dictionary Sizes (Megabyte): $($dictionarySizesMb -join ', ')" -ForegroundColor Gray
Write-Host " The script will create a RAR archive for each specified dictionary size." -ForegroundColor DarkGray
Write-Host "" -ForegroundColor DarkGray
Write-Host " File Types To Keep Uncompressed: `$keepCompressedFileTypesUncompressed" -ForegroundColor Gray
Write-Host " The script will instruct RAR to don't compress the specified known compressed file types." -ForegroundColor DarkGray
Write-Host " (See `$keepCompressedFileTypesUncompressed variable definition to manage the file types)" -ForegroundColor DarkGray
Write-Host "" -ForegroundColor DarkGray
Write-Host " Tolerance File Size Difference: $(Format-FileSize -fileSize $toleranceSizeDiff)" -ForegroundColor Gray
Write-Host " Any newly created RAR file whose file size compared to previously " -ForegroundColor DarkGray
Write-Host " created RAR files is within the specified tolerance value, it will be deleted." -ForegroundColor DarkGray
Write-Host " For example, if `$toleranceSizeDiff value is 1MB:" -ForegroundColor DarkGray
Write-Host " If a created RAR file of 32 MB dict. size has a file size of 100 MB," -ForegroundColor DarkGray
Write-Host " and then a newly created RAR file of 64 MB dict. size has a file size of 99 MB, " -ForegroundColor DarkGray
Write-Host " the RAR file of 64 MB dict. size will be deleted because it only differs in 1MB or less." -ForegroundColor DarkGray
Write-Host "" -ForegroundColor DarkGray
Write-Host " Keep only smallest RAR file: $keepOnlySmallestRarFile" -ForegroundColor Gray
Write-Host " If True, the script will delete any newly created RAR file " -ForegroundColor DarkGray
Write-Host " whose file size is bigger than previously created RAR files." -ForegroundColor DarkGray
Write-Host " Note: it takes into account the specified `$toleranceSizeDiff value." -ForegroundColor DarkGray
Write-Host "" -ForegroundColor DarkGray
Write-Host " Send RAR files to recycle bin: $sendRarFilesToRecycleBin" -ForegroundColor Gray
Write-Host " If True, the script will send RAR files to recycle bin instead of permanently deleting them." -ForegroundColor DarkGray
Write-Host ""
}
function Confirm-Continue {
Write-Host " Press 'Y' key to continue or 'N' to exit."
Write-Host ""
Write-Host " -Continue? (Y/N)"
do {
$key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
$char = $key.Character.ToString().ToUpper()
if ($char -ne "Y" -and $char -ne "N") {
[console]::beep(1500, 500)
}
} while ($char -ne "Y" -and $char -ne "N")
if ($char -eq "N") {Exit(1)} else {Clear-Host}
}
function Compress-Files {
Add-Type -AssemblyName Microsoft.VisualBasic
$dictionarySizesMb = $dictionarySizesMb | Sort-Object
# Partir y formatear la cadena de file types para acomodarlo a la linea de argumentos de rar.exe
if (-not [String]::IsNullOrEmpty($fileTypesToKeepUncompressed)) {
$fileTypeTokens = $fileTypesToKeepUncompressed -split ';'
$fileTypesArgumentLines = @()
for ($i = 0; $i -lt $fileTypeTokens.Count; $i += 20) {
$fileTypesArgumentLines += "-ms" + ($fileTypeTokens[$i..($i + 19)] -join ';') + [Environment]::NewLine
}
if ($fileTypesArgumentLines.Count -gt 0) {
$fileTypesArgumentLines[-1] = $fileTypesArgumentLines[-1] -replace [Environment]::NewLine, ''
}
} else {
$fileTypesArgumentLines = "-ms "
}
foreach ($inputFile in Get-ChildItem -LiteralPath "$PSScriptRoot" -File) {
if ($inputFile.Name -eq [System.IO.Path]::GetFileName($PSCommandPath)) {
continue
}
# Keeps track of created rar files by rar.exe
$createdRarFiles = New-Object System.Collections.Generic.List[System.IO.FileInfo]
foreach ($size in $dictionarySizesMb) {
if (($size -ne $dictionarySizesMb[0]) -and ($inputFile.Length * 4) -le ($size * 1MB)) {
$formattedSize = Format-FileSize -fileSize $inputFile.Length
Write-Host "Ignoring compression with too big dictionary size of $size mb for a $formattedSize file: `"$($inputFile.Name)`"..." -ForegroundColor Yellow
continue
}
$outputRarFilePath = "$($inputFile.FullName)_$($size)mb.rar"
$errorLogFilePath = "$($inputFile.FullName)_$($size)mb_error.log"
$arguments = @(
" a -u -ams -c- -cfg- -dh -ep1 -htb -idcdn -isnd- -iver -m5 -ma5 -md$($size)m",
" -o+ -oc -oh -oi2 -ol -oni -qo+ -r -ri0:0 -s- -t -tk -tl -tsmca+",
" $fileTypesArgumentLines",
" -x`"*\$($MyInvocation.MyCommand.Name)`"",
" -w`"$($env:TEMP)`"",
" -ilog`"$errorLogFilePath`"",
" -- `"$outputRarFilePath`"",
" -- `"$($inputFile.FullName)`""
)
Write-Host "Compressing file with $size mb dictionary size: `"$($inputFile.Name)`"..."
#Write-Host ""
#Write-Host "rar.exe arguments:" -ForegroundColor DarkGray
#Write-Host ($arguments -join [Environment]::NewLine) -ForegroundColor DarkGray
$previousForegroundColor = $host.UI.RawUI.ForegroundColor
$host.UI.RawUI.ForegroundColor = "DarkGray"
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $rarExecutablePath
$psi.Arguments = $arguments -join ' '
$psi.RedirectStandardOutput = $false
$psi.UseShellExecute = $false
$psi.CreateNoWindow = $false
$process = [System.Diagnostics.Process]::Start($psi)
$process.WaitForExit()
$host.UI.RawUI.ForegroundColor = $previousForegroundColor
$outputRarFile = New-Object System.IO.FileInfo($outputRarFilePath)
$formattedOutputRarFileSize = Format-FileSize -fileSize $outputRarFile.Length
Write-Host ""
Write-Host "Created rar with file name: $($outputRarFile.Name) ($formattedOutputRarFileSize) ($($outputRarFile.Length) bytes)" -ForegroundColor DarkGreen
if ($toleranceSizeDiff -ne $null) {
if ($createdRarFiles.Count -ne 0) {
$outputRarFileSize = $outputRarFile.Length
$formattedOutputRarFileSize = Format-FileSize -fileSize $outputRarFileSize
$formattedToleranceFileSize = Format-FileSize -fileSize $toleranceSizeDiff
foreach ($createdRarFile in $createdRarFiles) {
if ($createdRarFile.Exists) {
$createdRarFileSize = $createdRarFile.Length
$formattedCreatedRarFileSize = Format-FileSize -fileSize $createdRarFileSize
$diffSize = [Math]::Abs($createdRarFileSize - $outputRarFileSize)
$formattedDiffSize = Format-FileSize -fileSize $diffSize
if (($outputRarFileSize + $toleranceSizeDiff) -ge $createdRarFileSize) {
Write-Host ""
Write-Host "Size of this created RAR file ($formattedOutputRarFileSize) ($outputRarFileSize bytes) is within the $formattedToleranceFileSize tolerance difference" -ForegroundColor Yellow
Write-Host "than a previously created RAR file of $formattedCreatedRarFileSize ($createdRarFileSize bytes) with smaller dictionary size..." -ForegroundColor Yellow
Write-Host "Size of this created RAR file only differs by $formattedDiffSize ($diffSize bytes)." -ForegroundColor Yellow
Write-Host "Deleting file: `"$($outputRarFile.Name)`"..." -ForegroundColor Yellow
if ($sendRarFilesToRecycleBin) {
[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($outputRarFile.FullName, 'OnlyErrorDialogs', 'SendToRecycleBin')
} else {
[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($outputRarFile.FullName, 'OnlyErrorDialogs', 'DeletePermanently')
}
Write-Host "Deletion completed." -ForegroundColor Yellow
break
}
}
}
}
}
if (Test-Path -LiteralPath $outputRarFile.FullName -PathType Leaf) {
$createdRarFiles.Add($outputRarFile)
}
Write-Host ""
}
if ($keepOnlySmallestRarFile -and $createdRarFiles.Count -gt 0) {
$existingFiles = $createdRarFiles | Where-Object { $_.Exists }
if ($existingFiles.Count -gt 0) {
Write-Host "`$keepOnlySmallestRarFile variable is `$True. Comparing file sizes of created RAR files..." -ForegroundColor Yellow
Write-Host ""
$smallestFile = $existingFiles | Sort-Object Length | Select-Object -First 1
foreach ($file in $existingFiles) {
if ($file -ne $smallestFile) {
$formattedFileSize = Format-FileSize -fileSize $file.Length
Write-Host "Deleting file: `"$($file.Name)`" ($formattedFileSize)..." -ForegroundColor Yellow
if ($sendRarFilesToRecycleBin) {
[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($file.FullName, 'OnlyErrorDialogs', 'SendToRecycleBin')
} else {
[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($file.FullName, 'OnlyErrorDialogs', 'DeletePermanently')
}
Write-Host "Deletion completed." -ForegroundColor Yellow
Write-Host ""
}
}
$formattedSmallestFileSize = Format-FileSize -fileSize $smallestFile.Length
Write-Host "Smallest file kept: $($smallestFile.Name) ($formattedSmallestFileSize)" -ForegroundColor Green
Write-Host ""
}
}
}
}
function Show-GoodbyeScreen {
Write-Host "Operation Completed!" -BackgroundColor Black -ForegroundColor Green
Write-Host ""
Write-Host "Press any key to exit..."
$key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown")
Exit(0)
}
<#
===========================================================================================
| |
| Main |
| |
===========================================================================================
#>
[System.Console]::Title = "RAR Multi-Compression Test Tool (Files) - by Elektro"
#[System.Console]::SetWindowSize(150, 45)
[CultureInfo]::CurrentUICulture = "en-US"
try { Set-ExecutionPolicy -ExecutionPolicy "Unrestricted" -Scope "Process" } catch { }
Show-WelcomeScreen
Confirm-Continue
Compress-Files
Show-GoodbyeScreen