From 251c9aa06cfdf465e9323935187242ecd3c093bc Mon Sep 17 00:00:00 2001 From: Princess Pi Date: Fri, 25 Sep 2026 16:51:04 -0600 Subject: [PATCH] waypoit debuguing --- Windows-Scripts/checksum.ps1 | 328 +++++++++++++++++++++-------------- 1 file changed, 198 insertions(+), 130 deletions(-) diff --git a/Windows-Scripts/checksum.ps1 b/Windows-Scripts/checksum.ps1 index c10ebee..ebaf5b5 100644 --- a/Windows-Scripts/checksum.ps1 +++ b/Windows-Scripts/checksum.ps1 @@ -1,3 +1,13 @@ +<# +.SYNOPSIS + Princess Pi's Magical CHECKSUM! - Computes and verifies message digests / file checksums. +.DESCRIPTION + Computes or verifies checksums using cryptographic hash algorithms (SHA256, SHA512, SHA1, MD5, SHA384). + Supports parallel processing, recursive scanning, direct hash matching, and verification file parsing. +.NOTES + Requires PowerShell 7.0 or higher. +#> + [CmdletBinding(DefaultParameterSetName='Generate')] param( # File(s) or wildcard pattern to compute checksum for @@ -49,6 +59,13 @@ param( [switch]$Help ) +# --- ENVIRONMENT SANITY CHECK --- +# Ensure PowerShell 7+ is used since ForEach-Object -Parallel is required. +if ($PSVersionTable.PSVersion.Major -lt 7) { + Write-Error "checksum: This script requires PowerShell 7 or higher for parallel execution (-Parallel support). Current version is $($PSVersionTable.PSVersion)." + exit 1 +} + begin { function Show-Help { @' @@ -137,59 +154,59 @@ https://linktr.ee/princesspi3 function Show-PrincessPiArt { $art = @' - - =#= -- ##*+++++ *+ - -#=#- +# -*%%= ##++++++++++# ##*********# - #==#= *** %%++%% -++# #++++++++++++*+ *#***************# - #===#= %***+%++#*%%@+++++% #++++++++++++**+++#******++********# - ====+#%@*******###%=%++##++% #+++++++++++*++++++++#***====+****++# - =#=*==**#*#########%++#*+++@ *++++++++#+++++++++++#****==+******# - *#=====%####***%%++++#*+++**% ++++++++*+++++++++++++#************#******* - @****#==%####**#*+++++++#+++#**# #+++++++++++++++++++#####+*****************# - @****#######%**@+*%**#%+++++%##*** #+++++++++++++++++#+++++#****+======*****+ - #****##%####@**%+*******@@+++@###**% #+++++++++++++*++++++++++****========****# - ****#####%%*%*%+***@@@%%@*+++@####** *+++++++++++++++++++++#****=======****# - %***####%%**+%%*++*@=##@@%@++++%###*** +++++*+++++++++++#+**************# + + =#= -- ##*+++++ *+ + -#=#- +# -*%%= ##++++++++++# ##*********# + #==#= *** %%++%% -++# #++++++++++++*+ *#***************# + #===#= %***+%++#*%%@+++++% #++++++++++++**+++#******++********# + ====+#%@*******###%=%++##++% #+++++++++++*++++++++#***====+****++# + =#=*==**#*#########%++#*+++@ *++++++++#+++++++++++#****==+******# + *#=====%####***%%++++#*+++**% ++++++++*+++++++++++++#************#******* + @****#==%####**#*+++++++#+++#**# #+++++++++++++++++++#####+*****************# + @****#######%**@+*%**#%+++++%##*** #+++++++++++++++++#+++++#****+======*****+ + #****##%####@**%+*******@@+++@###**% #+++++++++++++*++++++++++****========****# + ****#####%%*%*%+***@@@%%@*+++@####** *+++++++++++++++++++++#****=======****# + %***####%%**+%%*++*@=##@@%@++++%###*** ++++*+++++++++++#+**************# @%%%@@##%%#++++++++==**@@**+++%*###**% +++++++++++#*+++++#*********#### - %###%++++++++====**#++++%**##**% @% ++++#+++++++++++++**************# - %###%++++++++++++++++++%**%##**%@###@ %++++++++++++++++***=====******** + %###%++++++++====**#++++%**##**% @% ++++#+++++++++++++**************# + %###%++++++++++++++++++%**%##**%@###@ %++++++++++++++++***=====******** ###%%++++++++%++++++*%%%%###***##%##@ +++++++++++++##**************# ###%%%%+++++##+++++++#*+%###***%%%##@ ++++++++++++++%********+############%@ @%%*@*%%%%###****+*%%****++%##***%##@@@ #+++++++++++++++*********###*****#########* #%%###***#####%**++++##**%#@@#@ ##+++++++++*###%#+***+***##*************####### - @#%%####%%####%+++++++##*######%++++++++++++++#*+++++#%###%#######*********######% - ##%########@%@+++@###%*%#####@+++++++++++%**++++++++++%%%%%%########***==**###%##% - %#%###%###########@@%#%#@@##++++++++****++++********+++ %########**===*###%*# - #**##%####@@####%@######%*++++++++++++++++#++**+*#++++# ########******###% % - @#***# ###%@@##%#######@+++++++++++++++++++++%*++**++++# *########******##% @ - *******% %##% =@#########++++++++++++++++++#++++*%++*#%#++# ########******##% - #@%@# %% *@#@@###*+++++++++++++++++++%+++##+++###++* ##*#####******##@ - **##%*++%++++++++++++++++++++++++++++++++% +#**#####******### - ##%#######*@***+#+++++++++++++++#***#++++++++++++ %**#####*******#% - *+++++$****##****++++++++##% #******#+++++++++++ %**#####*******#@ - #++++++++*******- ++++++++# *******#++++++++++# @**#####*******# - #@@+++++++******- *+++++++# #******#+++++++++* **####%**==+**@ - @@@@@+++ %+++++++# ******# %+++++++ %*###%***===**@ %= - @@@@@@@@@ #+++++++# =****** #++++++% *###%#***=+**% %** - @@@@@@@@@@ ++++++++# ******# #++++++# *##@%********% @*@ - @@+@@@++@@+ ++++++++# ******# #++++++# @## #*********@ #***# - @@+@@++@@@++ @@@++++++* @@@%**** #@@++++% +## %#****************% - @*@**@+++# @@@@+++++ @@@@@@**# @@@@++++# @# %#**************** - +#+++++# @@@@@@+++% @@@@@@@@# @@@@@@@++ @ %##************% - #+++** @@@@@@@@@@ @@@@@@@@@ @@@@@@@@@ %###********%* - @@@@@@@@@@+ @@@@@@@@@@ =@@@@@@@@@ %%#####%% - *@@@@@@@@@@ @+*@@@@@@@= @@++@@@@@@ - @++@@@@@@@@ #**@**@@@@@ *@@*#@@@@@@ -= - @%#@@@@@@@@ *#***@@@@@@ @+#+@++#@@@ - #+++@++@@@@@ **********# #+++++@+@@@@ - ##+#+++@@@@@@ ##****#### *+#+##+++@@%% - #+++++++++++# #++++++++++# - #########* + @#%%####%%####%+++++++##*######%++++++++++++++#*+++++#%###%#######*********######% + ##%########@%@+++@###%*%#####@+++++++++++%**++++++++++%%%%%%########***==**###%##% + %#%###%###########@@%#%#@@##++++++++****++++********+++ %########**===*###%*# + #**##%####@@####%@######%*++++++++++++++++#++**+*#++++# ########******###% % + @#***# ###%@@##%#######@+++++++++++++++++++++%*++**++++# *########******##% @ + *******% %##% =@#########++++++++++++++++++#++++*%++*#%#++# ########******##% + #@%@# %% *@#@@###*+++++++++++++++++++%+++##+++###++* ##*#####******##@ + **##%*++%++++++++++++++++++++++++++++++++% +#**#####******### + ##%#######*@***+#+++++++++++++++#***#++++++++++++ %**#####*******#% + *+++++$****##****++++++++##% #******#+++++++++++ %**#####*******#@ + #++++++++*******- ++++++++# *******#++++++++++# @**#####*******# + #@@+++++++******- *+++++++# #******#+++++++++* **####%**==+**@ + @@@@@+++ %+++++++# ******# %+++++++ %*###%***===**@ %= + @@@@@@@@@ #+++++++# =****** #++++++% *###%#***=+**% %** + @@@@@@@@@@ ++++++++# ******# #++++++# *##@%********% @*@ + @@+@@@++@@+ ++++++++# ******# #++++++# @## #*********@ #***# + @@+@@++@@@++ @@@++++++* @@@%**** #@@++++% +## %#****************% + @*@**@+++# @@@@+++++ @@@@@@**# @@@@@++++# @# %#**************** + +#+++++# @@@@@@+++% @@@@@@@@# @@@@@@@++ @ %##************% + #+++** @@@@@@@@@@ @@@@@@@@@ @@@@@@@@@ %###********%* + @@@@@@@@@@+ @@@@@@@@@@ =@@@@@@@@@ %%#####%% + *@@@@@@@@@@ @+*@@@@@@@= @@++@@@@@@ + @++@@@@@@@@ #**@**@@@@@ *@@*#@@@@@@ -= + @%#@@@@@@@@ *#***@@@@@@ @+#+@++#@@@ + #+++@++@@@@@ **********# #+++++@+@@@@ + ##+#+++@@@@@@ ##****#### *+#+##+++@@%% + #+++++++++++# #++++++++++# + #########* ____ ____ ____ _ _ ___ ____ ___ ___ ____ ____ ( _ \( _ \(_ _)( \( )/ __)( ___)/ __)/ __) ( _ \(_ _)/\/ - )___/ ) / _)(_ ) (( (__ )__) \__ \\__ \ )___/ _)(_ - (__) (_)\_)(____)(_)\_)\___)(____)(___/(___/ (__) (____) + )___/ ) / _)(_ ) (( (__ )__) \__ \\__ \ )___/ _)(_ + (__) (_)\_)(____)(_)\_)\___)(____)(___/(___/ (__) (____) Princess Pi https://linktr.ee/princesspi3 @@ -213,31 +230,6 @@ https://linktr.ee/princesspi3 } }; }; - - function Invoke-ParallelHashing { - param([array]$Items, [string]$Algorithm); - - $Items | ForEach-Object -Parallel { - $item = $_ - $algo = $using:Algorithm - - $hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($algo)).Hash.ToLower(); - - $relativePath = Resolve-Path -Path ($item.FullName) -Relative -ErrorAction 'SilentlyContinue'; - if (-not $relativePath) { $relativePath = $item.Name; }; - if ($relativePath.StartsWith(".\") -or $relativePath.StartsWith("./")) { - $relativePath = $relativePath.Substring(2); - }; - - [PSCustomObject]@{ - Item = $item - Hash = $hash - RelativePath = $relativePath - OutputLine = "${hash} ${relativePath}" - ItemOutFile = "$($item.FullName).$($algo.ToLower())" - } - } -ThrottleLimit 16 - }; } process { @@ -265,6 +257,15 @@ process { $Algorithm = $Algorithm.ToUpper(); }; + # Determine if progress bar should display (-r, -c/-Check, or wildcard input '*') + $isWildcardGlobal = $false; + if ($FilePath) { + foreach ($p in $FilePath) { + if ($p -match '\*') { $isWildcardGlobal = $true; } + } + } + $showProgress = $Recursive.IsPresent -or $isWildcardGlobal -or ($PSCmdlet.ParameterSetName -eq 'Verify'); + # --- ITEM GATHERING (Generate & Match Modes) --- if ($PSCmdlet.ParameterSetName -in @('Generate', 'Match')) { if (-not $FilePath -or $FilePath.Count -eq 0) { @@ -273,14 +274,12 @@ process { }; $allItems = @(); - $isWildcardGlobal = $false; $skipExtensions = @('.md5', '.sha1', '.sha256', '.sha384', '.sha512'); foreach ($pathEntry in ($FilePath)) { $isWildcard = ($pathEntry -match '\*'); - if ($isWildcard) { $isWildcardGlobal = $true; }; - $resolvedItems = @(); + if ($Recursive) { $resolvedItems = Get-ChildItem -Path ($pathEntry) -Recurse -File -ErrorAction 'SilentlyContinue'; } else { @@ -323,9 +322,10 @@ process { $expectedHash = $Match.Trim().ToLower(); $totalFiles = $allItems.Count; - $currentIndex = [ref]0; + $currentIndex = 0; - $results = $allItems | ForEach-Object -Parallel { + # Stream parallel results and update progress bar in real time + $allItems | ForEach-Object -Parallel { $item = $_ $algo = $using:Algorithm $exp = $using:expectedHash @@ -339,25 +339,22 @@ process { TargetFile = $targetFile IsMatch = ($actualHash -eq $exp) } - } -ThrottleLimit 16; - - $showProgressMatch = $Recursive.IsPresent -or $isWildcardGlobal; - - foreach ($res in $results) { - $currentIndex.Value++; - if ($showProgressMatch -and $totalFiles -gt 0) { - Write-Progress -Activity "Matching Checksums ($Algorithm)" -Status "Processing file $($currentIndex.Value) of $totalFiles" -PercentComplete (($currentIndex.Value / $totalFiles) * 100); + } -ThrottleLimit 16 | ForEach-Object { + $currentIndex++ + if ($showProgress -and $totalFiles -gt 0) { + Write-Progress -Activity "Matching Checksums ($Algorithm)" -Status "Processing file $currentIndex of $totalFiles" -PercentComplete (($currentIndex / $totalFiles) * 100); } - if ($res.IsMatch) { - Write-Host "$($res.TargetFile): " -NoNewline; + if ($_.IsMatch) { + Write-Host "$($_.TargetFile): " -NoNewline; Write-Host "OK" -ForegroundColor Green; } else { - Write-Host "$($res.TargetFile): " -NoNewline; + Write-Host "$($_.TargetFile): " -NoNewline; Write-Host "FAILED" -ForegroundColor Red; } }; - if ($showProgressMatch) { + + if ($showProgress) { Write-Progress -Activity "Matching Checksums ($Algorithm)" -Completed; } } @@ -428,10 +425,10 @@ process { } $totalFiles = $verifyItems.Count; - $currentIndex = [ref]0; + $currentIndex = 0; - # Run verification items in parallel - $verifyResults = $verifyItems | ForEach-Object -Parallel { + # Run verification items in parallel and stream progress live + $verifyItems | ForEach-Object -Parallel { $item = $_ $algo = $using:fileAlgo @@ -459,23 +456,21 @@ process { IsError = $true } } - } -ThrottleLimit 16; - - foreach ($res in $verifyResults) { - $currentIndex.Value++; + } -ThrottleLimit 16 | ForEach-Object { + $currentIndex++ if ($totalFiles -gt 0) { - Write-Progress -Activity "Verifying Checksums ($fileAlgo)" -Status "Processing file $($currentIndex.Value) of $totalFiles" -PercentComplete (($currentIndex.Value / $totalFiles) * 100); + Write-Progress -Activity "Verifying Checksums ($fileAlgo)" -Status "Processing file $currentIndex of $totalFiles" -PercentComplete (($currentIndex / $totalFiles) * 100); } - Write-Host "$($res.DisplayPath): " -NoNewline; - if ($res.IsError) { - Write-Host "$($res.Status)" -ForegroundColor Red; - } elseif ($res.Status -eq "OK") { + Write-Host "$($_.DisplayPath): " -NoNewline; + if ($_.IsError) { + Write-Host "$($_.Status)" -ForegroundColor Red; + } elseif ($_.Status -eq "OK") { Write-Host "OK" -ForegroundColor Green; } else { Write-Host "FAILED" -ForegroundColor Red; } - } + }; Write-Progress -Activity "Verifying Checksums ($fileAlgo)" -Completed; }; } @@ -488,9 +483,6 @@ process { $wantCustomOut = $PSBoundParameters.ContainsKey('OutFile'); $wantAutoOut = $Save.IsPresent; - # Show progress if wildcard used anywhere in inputs or recursive flag set - $showProgressGen = $Recursive.IsPresent -or $isWildcardGlobal; - if ($wantCustomOut -or $wantAutoOut) { # Recursive wildcard auto-saves per directory if ($Recursive -and $isWildcardGlobal) { @@ -510,17 +502,36 @@ process { $currentIndex = 0; $linesToWrite = @(); - $parallelResults = Invoke-ParallelHashing -Items $filesInDir -Algorithm $Algorithm; - foreach ($res in $parallelResults) { + $filesInDir | ForEach-Object -Parallel { + $item = $_ + $algo = $using:Algorithm + + $hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($algo)).Hash.ToLower(); + + $relativePath = Resolve-Path -Path ($item.FullName) -Relative -ErrorAction 'SilentlyContinue'; + if (-not $relativePath) { $relativePath = $item.Name; }; + if ($relativePath.StartsWith(".\") -or $relativePath.StartsWith("./")) { + $relativePath = $relativePath.Substring(2); + }; + + [PSCustomObject]@{ + Item = $item + Hash = $hash + RelativePath = $relativePath + OutputLine = "${hash} ${relativePath}" + ItemOutFile = "$($item.FullName).$($algo.ToLower())" + } + } -ThrottleLimit 16 | ForEach-Object { $currentIndex++; - if ($showProgressGen -and $totalFiles -gt 0) { + if ($showProgress -and $totalFiles -gt 0) { Write-Progress -Activity "Computing Checksums ($Algorithm)" -Status "Directory: $(Split-Path $dirPath -Leaf) [$currentIndex/$totalFiles]" -PercentComplete (($currentIndex / $totalFiles) * 100); } - $linesToWrite += $res.OutputLine; - Write-Output $res.OutputLine; - } - if ($showProgressGen) { + $linesToWrite += $_.OutputLine; + Write-Output $_.OutputLine; + }; + + if ($showProgress) { Write-Progress -Activity "Computing Checksums ($Algorithm)" -Completed; } @@ -540,17 +551,36 @@ process { $currentIndex = 0; $linesToWrite = @(); - $parallelResults = Invoke-ParallelHashing -Items $allItems -Algorithm $Algorithm; - foreach ($res in $parallelResults) { + $allItems | ForEach-Object -Parallel { + $item = $_ + $algo = $using:Algorithm + + $hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($algo)).Hash.ToLower(); + + $relativePath = Resolve-Path -Path ($item.FullName) -Relative -ErrorAction 'SilentlyContinue'; + if (-not $relativePath) { $relativePath = $item.Name; }; + if ($relativePath.StartsWith(".\") -or $relativePath.StartsWith("./")) { + $relativePath = $relativePath.Substring(2); + }; + + [PSCustomObject]@{ + Item = $item + Hash = $hash + RelativePath = $relativePath + OutputLine = "${hash} ${relativePath}" + ItemOutFile = "$($item.FullName).$($algo.ToLower())" + } + } -ThrottleLimit 16 | ForEach-Object { $currentIndex++; - if ($showProgressGen -and $totalFiles -gt 0) { + if ($showProgress -and $totalFiles -gt 0) { Write-Progress -Activity "Computing Checksums ($Algorithm)" -Status "Processing file $currentIndex of $totalFiles" -PercentComplete (($currentIndex / $totalFiles) * 100); } - $linesToWrite += $res.OutputLine; - Write-Output $res.OutputLine; - } - if ($showProgressGen) { + $linesToWrite += $_.OutputLine; + Write-Output $_.OutputLine; + }; + + if ($showProgress) { Write-Progress -Activity "Computing Checksums ($Algorithm)" -Completed; } @@ -561,17 +591,36 @@ process { $totalFiles = $allItems.Count; $currentIndex = 0; - $parallelResults = Invoke-ParallelHashing -Items $allItems -Algorithm $Algorithm; - foreach ($res in $parallelResults) { + $allItems | ForEach-Object -Parallel { + $item = $_ + $algo = $using:Algorithm + + $hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($algo)).Hash.ToLower(); + + $relativePath = Resolve-Path -Path ($item.FullName) -Relative -ErrorAction 'SilentlyContinue'; + if (-not $relativePath) { $relativePath = $item.Name; }; + if ($relativePath.StartsWith(".\") -or $relativePath.StartsWith("./")) { + $relativePath = $relativePath.Substring(2); + }; + + [PSCustomObject]@{ + Item = $item + Hash = $hash + RelativePath = $relativePath + OutputLine = "${hash} ${relativePath}" + ItemOutFile = "$($item.FullName).$($algo.ToLower())" + } + } -ThrottleLimit 16 | ForEach-Object { $currentIndex++; - if ($showProgressGen -and $totalFiles -gt 0) { + if ($showProgress -and $totalFiles -gt 0) { Write-Progress -Activity "Computing Checksums ($Algorithm)" -Status "Processing file $currentIndex of $totalFiles" -PercentComplete (($currentIndex / $totalFiles) * 100); } - Write-Output $res.OutputLine; - Set-Content -Path ($res.ItemOutFile) -Value $res.OutputLine -Encoding utf8; - } - if ($showProgressGen) { + Write-Output $_.OutputLine; + Set-Content -Path ($_.ItemOutFile) -Value $_.OutputLine -Encoding utf8; + }; + + if ($showProgress) { Write-Progress -Activity "Computing Checksums ($Algorithm)" -Completed; } }; @@ -582,16 +631,35 @@ process { $totalFiles = $allItems.Count; $currentIndex = 0; - $parallelResults = Invoke-ParallelHashing -Items $allItems -Algorithm $Algorithm; - foreach ($res in $parallelResults) { + $allItems | ForEach-Object -Parallel { + $item = $_ + $algo = $using:Algorithm + + $hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($algo)).Hash.ToLower(); + + $relativePath = Resolve-Path -Path ($item.FullName) -Relative -ErrorAction 'SilentlyContinue'; + if (-not $relativePath) { $relativePath = $item.Name; }; + if ($relativePath.StartsWith(".\") -or $relativePath.StartsWith("./")) { + $relativePath = $relativePath.Substring(2); + }; + + [PSCustomObject]@{ + Item = $item + Hash = $hash + RelativePath = $relativePath + OutputLine = "${hash} ${relativePath}" + ItemOutFile = "$($item.FullName).$($algo.ToLower())" + } + } -ThrottleLimit 16 | ForEach-Object { $currentIndex++; - if ($showProgressGen -and $totalFiles -gt 0) { + if ($showProgress -and $totalFiles -gt 0) { Write-Progress -Activity "Computing Checksums ($Algorithm)" -Status "Processing file $currentIndex of $totalFiles" -PercentComplete (($currentIndex / $totalFiles) * 100); } - Write-Output $res.OutputLine; - } - if ($showProgressGen) { + Write-Output $_.OutputLine; + }; + + if ($showProgress) { Write-Progress -Activity "Computing Checksums ($Algorithm)" -Completed; } };