<#
===========================================================================================
| |
| Variables |
| |
===========================================================================================
#>
$rarExecutablePath = "C:\Program Files\WinRAR\rar.exe"
$dictionarySizes = @(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048)
$toleranceSizeDiff = "1MB"
$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 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 directory |"
Write-Host " | in the current working directory individually, each |"
Write-Host " | using 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): $($dictionarySizes -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: $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
$dictionarySizes = $dictionarySizes | 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 ($dir in Get-ChildItem -LiteralPath "$PSScriptRoot" -Directory) {
$dirSizeBytes = (Get-ChildItem -LiteralPath "$($dir.FullName)" -Recurse | Measure-Object -Property Length -sum).Sum
# Keeps track of created rar files by rar.exe
$createdRarFiles = New-Object System.Collections.Generic.List[System.IO.FileInfo]
foreach ($size in $dictionarySizes) {
if (($size -ne $dictionarySizes[0]) -and ($dirSizeBytes * 4) -le ($size * 1MB)) {
$formattedDirSize = Format-FileSize -fileSize $dirSizeBytes
Write-Host "Ignoring compression with too big dictionary size of $size mb for a $formattedDirSize directory: `"$($dir.FullName)`"..." -ForegroundColor Yellow
continue
}
$outputRarFilePath = "$($dir.FullName)_$($size)mb.rar"
$errorLogFilePath = "$($dir.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`"",
" -- `"$($dir.FullName)\*`""
)
Write-Host "Compressing directory with $size mb dictionary dize: `"$($dir.Name)`"..."
#Write-Host ""
#Write-Host "rar.exe arguments:" -ForegroundColor DarkGray
#Write-Host ($arguments -join [Environment]::NewLine) -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()
$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)" -ForegroundColor DarkGreen
if ($toleranceSizeDiff -ne $null) {
if ($createdRarFiles.Count -ne 0) {
$outputRarFileMB = [Math]::Floor($outputRarFile.Length / $toleranceSizeDiff)
$formattedOutputRarFileSize = Format-FileSize -fileSize $outputRarFile.Length
foreach ($rarFile in $createdRarFiles) {
if ($rarFile.Exists) {
$sizeMB = [Math]::Floor($rarFile.Length / $toleranceSizeDiff)
$formattedRarFileSize = Format-FileSize -fileSize $rarFile.Length
if ($outputRarFileMB -eq $sizeMB) {
Write-Host ""
Write-Host "File size of this created RAR file ($formattedOutputRarFileSize) is within the $toleranceSizeDiff tolerance difference" -ForegroundColor DarkGray
Write-Host "than a previously created RAR file ($formattedRarFileSize) with smaller dictionary size..." -ForegroundColor DarkGray
Write-Host "Deleting file: `"$($outputRarFile.Name)`" ($formattedOutputRarFileSize)..." -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
}
}
}
}
}
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 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-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 (Directories) - 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