5 Commits

Author SHA1 Message Date
PrincessPi 608e225833 WORKAN DEBUG 2026-09-25 16:10:17 -06:00
PrincessPi 4fea9dbccc waypoint debug 2026-09-25 16:01:49 -06:00
PrincessPi 4377cc6a45 waypoit debuguing 2026-09-25 15:56:47 -06:00
PrincessPi e5435d124e waypoit debuguing 2026-09-25 15:50:28 -06:00
PrincessPi 757f1775ff waypoit debuguing 2026-09-25 15:43:25 -06:00
+156 -112
View File
@@ -5,16 +5,16 @@ param(
[Parameter(Position = 0, ParameterSetName = 'Match', ValueFromPipeline = $true)] [Parameter(Position = 0, ParameterSetName = 'Match', ValueFromPipeline = $true)]
[string[]]$FilePath, [string[]]$FilePath,
# Output file switch (-o) - auto generates file based on rules # Custom output file (-f / -OutFile)
[Parameter(Mandatory = $false, ParameterSetName = 'Generate')]
[Alias('o', 'out')]
[switch]$SaveToFile,
# Custom Output file name (-f / -OutFile)
[Parameter(Mandatory = $false, ParameterSetName = 'Generate')] [Parameter(Mandatory = $false, ParameterSetName = 'Generate')]
[Alias('f')] [Alias('f')]
[string]$OutFile, [string]$OutFile,
# Auto output file switch (-o)
[Parameter(Mandatory = $false, ParameterSetName = 'Generate')]
[Alias('o')]
[switch]$AutoOut,
# File containing checksums to verify (-c / -Check) # File containing checksums to verify (-c / -Check)
[Parameter(Mandatory = $false, ParameterSetName = 'Verify')] [Parameter(Mandatory = $false, ParameterSetName = 'Verify')]
[Alias('c')] [Alias('c')]
@@ -49,57 +49,63 @@ NAME
checksum - Compute and verify message digests / file checksums checksum - Compute and verify message digests / file checksums
SYNOPSIS SYNOPSIS
.\checksum.ps1 [-FilePath] <string[]> [-o] [-OutFile <string>] [-Algorithm <string>] [-r] .\checksum.ps1 [-FilePath] <string[]> [-o] [-f <string>] [-Algorithm <string>] [-r]
.\checksum.ps1 [-FilePath] <string[]> -Match <string> [-Algorithm <string>] [-r] .\checksum.ps1 [-FilePath] <string[]> -Match <string> [-Algorithm <string>] [-r]
.\checksum.ps1 -Check <string> [-Algorithm <string>] [-r] .\checksum.ps1 -Check <string> [-Algorithm <string>] [-r]
.\checksum.ps1 -Help .\checksum.ps1 -Help
DESCRIPTION DESCRIPTION
Computes or verifies checksums using various cryptographic algorithms. Computes or verifies checksums using cryptographic hash algorithms (SHA256, SHA512, SHA1, MD5, SHA384).
Outputs hash values in standard Linux utility format (<hash> <filename>). Outputs hash values in standard GNU coreutils format (<hash> <filename>).
Ignores checksum files (.md5, .sha1, .sha256, .sha384, .sha512) unless explicitly passed. Ignores checksum metadata files (.md5, .sha1, .sha256, .sha384, .sha512) during wildcards unless passed explicitly.
PARAMETERS PARAMETERS
-FilePath <string[]> -FilePath <string[]>
Specifies the path to one or more files to hash. Accepts wildcards (*). Specifies the target file(s) or wildcard pattern (*).
-o, -Out, --Out <switch> -o, -O
Enables writing checksum results to an auto-named file. Auto-saves checksum results. (Takes no arguments).
- If input has a wildcard (*), outputs to 'checksums.<algo>' - If input filename contains a wildcard (*), saves to 'checksums.<algo>'.
- If no wildcard is used, outputs to '<filename>.<algo>' per file. - If input filename does NOT contain a wildcard, saves to '<filename>.<algo>'.
When combined with -r and *, it auto-generates checksum files When combined with -r and *, recursively auto-generates checksums per directory.
inside the current working directory and each subdirectory recursively.
-f, -OutFile, --OutFile <string> -f, -F, -OutFile <string>
Specifies an explicit output file name to save results to. Saves checksum results to a specific custom filename.
Overrides the auto-naming behavior of -o if both are passed.
-r, -Recursive, --Recursive <switch> -c, -C, -Check <string>
Recursively generate or verify checksums in subdirectories. Reads hashes from a specified checksum file and verifies target files on disk.
If -r is specified, recursively looks for and validates checksum files by name across subdirectories.
-c, -Check, --Check <string> -m, -M, -Match <string>
Read checksums from the specified file and verify them against files on disk. Compares the computed hash of target file(s) directly against a given hash string.
If -r is used, searches for the specified filename recursively in subdirectories.
-m, -Match, --Match <string> -a, -A, -Algo, -Algorithm <string>
Compare the computed hash of the target file(s) against a specific hash string. Specifies the hash algorithm to use.
Supported options: MD5, SHA1, SHA256 (default), SHA384, SHA512.
In -c or -m mode, auto-detects algorithm from hash length if omitted.
-a, -Algorithm, --Algorithm <string> -r, -R, -Recursive <switch>
Specifies the cryptographic hash algorithm to use. Processes target files or verification files recursively across directory structures.
Supported values: SHA1, SHA256 (default), SHA384, SHA512, MD5.
If omitted in -c or -m mode, the algorithm is auto-detected by hash length.
-h, -Help, --Help <switch> -h, -H, -Help <switch>
Display this help message. Displays this help documentation.
EXAMPLES EXAMPLES
1. Compute SHA256 checksum for a single file: 1. Compute SHA256 for a single file and auto-save as 'myfile.iso.sha256':
.\checksum.ps1 myfile.iso .\checksum.ps1 myfile.iso -o
2. Compute checksums for all files and auto-write to files (-o flag): 2. Compute SHA512 recursively and auto-save as 'checksums.sha512' in each folder:
.\checksum.ps1 * -r -o .\checksum.ps1 * -r -o -a SHA512
3. Verify checksums from verification files recursively: 3. Compute SHA256 checksums and save to a specific custom file:
.\checksum.ps1 -c checksums.sha256 -r .\checksum.ps1 * -f my_hashes.txt
4. Verify checksums against a verification file:
.\checksum.ps1 -c checksums.sha256
5. Compare file directly against an expected hash string:
.\checksum.ps1 myfile.bin -m 406653a68bd3538975656831f33f031b
'@ '@
}; };
@@ -121,39 +127,39 @@ EXAMPLES
} }
process { process {
$helpInPath =$false; $helpInPath = $false;
if ($FilePath) { if ($FilePath) {
foreach ($p in ($FilePath)) { foreach ($p in ($FilePath)) {
if ($p -match '^(?i)[-/]{1,2}(h\vert{}help)$') { if ($p -match '^(?i)[-/]{1,2}(h|help|\?)$') {
$helpInPath =$true; $helpInPath = $true;
break; break;
} }
}; };
}; };
if ($Help.IsPresent -or$helpInPath) { if ($Help.IsPresent -or $helpInPath) {
Show-Help; Show-Help;
return; return;
}; };
if (-not [string]::IsNullOrWhiteSpace($Algorithm)) { if (-not [string]::IsNullOrWhiteSpace($Algorithm)) {
$Algorithm =$Algorithm.ToUpper(); $Algorithm = $Algorithm.ToUpper();
}; };
# --- ITEM GATHERING (Generate & Match Modes) --- # --- ITEM GATHERING (Generate & Match Modes) ---
if ($PSCmdlet.ParameterSetName -in @('Generate', 'Match')) { if ($PSCmdlet.ParameterSetName -in @('Generate', 'Match')) {
if (-not $FilePath -or$FilePath.Count -eq 0) { if (-not $FilePath -or $FilePath.Count -eq 0) {
Write-Error "checksum: Missing file path parameter. Use -Help for usage."; Write-Error "checksum: Missing file path parameter. Use -Help for usage.";
return; return;
}; };
$allItems = @(); $allItems = @();
$isWildcardGlobal =$false; $isWildcardGlobal = $false;
$skipExtensions = @('.md5', '.sha1', '.sha256', '.sha384', '.sha512'); $skipExtensions = @('.md5', '.sha1', '.sha256', '.sha384', '.sha512');
foreach ($pathEntry in ($FilePath)) { foreach ($pathEntry in ($FilePath)) {
$isWildcard = ($pathEntry -match '\*'); $isWildcard = ($pathEntry -match '\*');
if ($isWildcard) { $isWildcardGlobal =$true; }; if ($isWildcard) { $isWildcardGlobal = $true; };
$resolvedItems = @(); $resolvedItems = @();
if ($Recursive) { if ($Recursive) {
@@ -167,7 +173,7 @@ process {
}; };
if (-not $resolvedItems) { if (-not $resolvedItems) {
Write-Error "checksum: $($pathEntry)`: No such file or directory"; Write-Error "checksum: $($pathEntry): No such file or directory";
continue; continue;
}; };
@@ -202,7 +208,7 @@ process {
$actualHash = (Get-FileHash -Path ($item.FullName) -Algorithm ($Algorithm)).Hash.ToLower(); $actualHash = (Get-FileHash -Path ($item.FullName) -Algorithm ($Algorithm)).Hash.ToLower();
$targetFile = Resolve-Path -Path ($item.FullName) -Relative -ErrorAction 'SilentlyContinue'; $targetFile = Resolve-Path -Path ($item.FullName) -Relative -ErrorAction 'SilentlyContinue';
if (-not $targetFile) { $targetFile = $item.Name; }; if (-not $targetFile) { $targetFile = $item.Name; };
if ($targetFile.StartsWith(".\")) { $targetFile = $targetFile.Substring(2); }; if ($targetFile.StartsWith(".\") -or $targetFile.StartsWith("./")) { $targetFile = $targetFile.Substring(2); };
if ($actualHash -eq $expectedHash) { if ($actualHash -eq $expectedHash) {
Write-Host "${targetFile}: " -NoNewline; Write-Host "${targetFile}: " -NoNewline;
@@ -226,38 +232,57 @@ process {
}; };
if (-not $checkFiles -or $checkFiles.Count -eq 0) { if (-not $checkFiles -or $checkFiles.Count -eq 0) {
Write-Error "checksum: $($Check)`: No such file or directory"; Write-Error "checksum: $($Check): No such file or directory";
return; return;
}; };
foreach ($cf in ($checkFiles)) { foreach ($cf in ($checkFiles)) {
$lines = Get-Content -Path ($cf.FullName); $lines = Get-Content -Path ($cf.FullName);
$baseDir =$cf.DirectoryName; $baseDir = $cf.DirectoryName;
$fileAlgo =$Algorithm; $fileAlgo = $Algorithm;
if ([string]::IsNullOrWhiteSpace($fileAlgo)) { if ([string]::IsNullOrWhiteSpace($fileAlgo)) {
foreach ($line in ($lines)) { foreach ($line in ($lines)) {
if ([string]::IsNullOrWhiteSpace($line) -or$line.StartsWith("#")) { continue; }; if ([string]::IsNullOrWhiteSpace($line) -or $line.StartsWith("#")) { continue; };
if ($line -match '^([a-fA-F0-9]+)\s+') { if ($line -match '^([a-fA-F0-9]+)\s+') {
$fileAlgo = Get-AlgorithmFromHashLength -HashString ($Matches[1]); $fileAlgo = Get-AlgorithmFromHashLength -HashString ($Matches[1]);
break; break;
} }
elseif ($line -match '^([a-fA-F0-9]{128}|[a-fA-F0-9]{96}|[a-fA-F0-9]{64}|[a-fA-F0-9]{40}|[a-fA-F0-9]{32})') {
$fileAlgo = Get-AlgorithmFromHashLength -HashString ($Matches[1]);
break;
}
}; };
if ([string]::IsNullOrWhiteSpace($fileAlgo)) {$fileAlgo = 'SHA256'; }; if ([string]::IsNullOrWhiteSpace($fileAlgo)) { $fileAlgo = 'SHA256'; };
}; };
foreach ($line in ($lines)) { foreach ($line in ($lines)) {
if ([string]::IsNullOrWhiteSpace($line) -or$line.StartsWith("#")) { continue; }; if ([string]::IsNullOrWhiteSpace($line) -or $line.StartsWith("#")) { continue; };
if ($line -match '^([a-fA-F0-9]+)\s+[* ]?(.*)$') {$expectedHash = $Matches[1].ToLower();$targetFile = $Matches[2].Trim().TrimStart('*');$targetFullPath = Join-Path -Path ($baseDir) -ChildPath ($targetFile); $expectedHash = $null;
$targetFile = $null;
if (Test-Path -Path ($targetFullPath) -PathType 'Leaf') {$actualHash = (Get-FileHash -Path ($targetFullPath) -Algorithm ($fileAlgo)).Hash.ToLower(); if ($line -match '^([a-fA-F0-9]+)\s+[* ]?(.*)$') {
$expectedHash = $Matches[1].ToLower();
$targetFile = $Matches[2].Trim().TrimStart('*');
}
elseif ($line -match '^([a-fA-F0-9]{128}|[a-fA-F0-9]{96}|[a-fA-F0-9]{64}|[a-fA-F0-9]{40}|[a-fA-F0-9]{32})[* ]?(.*)$') {
$expectedHash = $Matches[1].ToLower();
$targetFile = $Matches[2].Trim().TrimStart('*');
};
if ($expectedHash -and $targetFile) {
$targetFullPath = Join-Path -Path ($baseDir) -ChildPath ($targetFile);
if (Test-Path -Path ($targetFullPath) -PathType 'Leaf') {
$actualHash = (Get-FileHash -Path ($targetFullPath) -Algorithm ($fileAlgo)).Hash.ToLower();
$displayPath = Resolve-Path -Path ($targetFullPath) -Relative -ErrorAction 'SilentlyContinue'; $displayPath = Resolve-Path -Path ($targetFullPath) -Relative -ErrorAction 'SilentlyContinue';
if (-not $displayPath) { $displayPath =$targetFile; }; if (-not $displayPath) { $displayPath = $targetFile; };
if ($displayPath.StartsWith(".\")) { $displayPath =$displayPath.Substring(2); }; if ($displayPath.StartsWith(".\") -or $displayPath.StartsWith("./")) { $displayPath = $displayPath.Substring(2); };
if ($actualHash -eq$expectedHash) { if ($actualHash -eq $expectedHash) {
Write-Host "${displayPath}: " -NoNewline; Write-Host "${displayPath}: " -NoNewline;
Write-Host "OK" -ForegroundColor Green; Write-Host "OK" -ForegroundColor Green;
} else { } else {
@@ -265,9 +290,10 @@ process {
Write-Host "FAILED" -ForegroundColor Red; Write-Host "FAILED" -ForegroundColor Red;
}; };
} else { } else {
$displayPath =$targetFile; $displayPath = $targetFile;
if ($baseDir -ne (Get-Location).Path) {$displayPath = Join-Path -Path (Resolve-Path -Path ($baseDir) -Relative -ErrorAction 'SilentlyContinue') -ChildPath ($targetFile); if ($baseDir -ne (Get-Location).Path) {
if ($displayPath.StartsWith(".\")) { $displayPath =$displayPath.Substring(2); }; $displayPath = Join-Path -Path (Resolve-Path -Path ($baseDir) -Relative -ErrorAction 'SilentlyContinue') -ChildPath ($targetFile);
if ($displayPath.StartsWith(".\") -or $displayPath.StartsWith("./")) { $displayPath = $displayPath.Substring(2); };
}; };
Write-Host "${displayPath}: " -NoNewline; Write-Host "${displayPath}: " -NoNewline;
Write-Host "FAILED open or read" -ForegroundColor Red; Write-Host "FAILED open or read" -ForegroundColor Red;
@@ -278,82 +304,100 @@ process {
} }
# --- GENERATION MODE --- # --- GENERATION MODE ---
else { else {
if ([string]::IsNullOrWhiteSpace($Algorithm)) {$Algorithm = 'SHA256'; if ([string]::IsNullOrWhiteSpace($Algorithm)) {
$Algorithm = 'SHA256';
}; };
$wantOutFile = $SaveToFile.IsPresent -or (-not [string]::IsNullOrWhiteSpace($OutFile)); $wantCustomOut = $PSBoundParameters.ContainsKey('OutFile');
$wantAutoOut = $AutoOut.IsPresent;
if ($wantOutFile) { if ($wantCustomOut -or $wantAutoOut) {
if ($Recursive -and$isWildcardGlobal) { # Recursive wildcard auto-saves per directory
$groupedItems =$allItems | Group-Object DirectoryName; if ($Recursive -and $isWildcardGlobal) {
$groupedItems = $allItems | Group-Object DirectoryName;
foreach ($group in ($groupedItems)) { foreach ($group in ($groupedItems)) {
$dirPath =$group.Name; $dirPath = $group.Name;
$filesInDir =$group.Group; $filesInDir = $group.Group;
if ([string]::IsNullOrWhiteSpace($OutFile)) { if ($wantCustomOut) {
$currentOutFile = Join-Path -Path ($dirPath) -ChildPath "checksums.$($Algorithm.ToLower())";
} else {
$currentOutFile = Join-Path -Path ($dirPath) -ChildPath ($OutFile); $currentOutFile = Join-Path -Path ($dirPath) -ChildPath ($OutFile);
} else {
$currentOutFile = Join-Path -Path ($dirPath) -ChildPath "checksums.$($Algorithm.ToLower())";
}; };
$null = New-Item -Path ($currentOutFile) -ItemType 'File' -Force; $linesToWrite = @();
foreach ($item in ($filesInDir)) {
$hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($Algorithm)).Hash.ToLower();
$relativePath = $item.Name;
foreach ($item in ($filesInDir)) {$hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($Algorithm)).Hash.ToLower(); $outputLine = "${hash} ${relativePath}";
$relativePath =$item.Name; $linesToWrite += $outputLine;
$outputLine = "$hash$relativePath";
Add-Content -Path ($currentOutFile) -Value ($outputLine);
Write-Output $outputLine; Write-Output $outputLine;
}; };
Set-Content -Path ($currentOutFile) -Value $linesToWrite -Encoding utf8;
}; };
} }
else { else {
$singleOutFile =$null; # Custom file OR Auto file with a wildcard
if ($wantCustomOut -or ($wantAutoOut -and $isWildcardGlobal)) {
if ([string]::IsNullOrWhiteSpace($OutFile)) { if ($wantCustomOut) {
if ($isWildcardGlobal) {$singleOutFile = "checksums.$($Algorithm.ToLower())"; $singleOutFile = $OutFile;
}
} else {
$singleOutFile =$OutFile;
};
if ($singleOutFile) {
$null = New-Item -Path ($singleOutFile) -ItemType 'File' -Force;
};
foreach ($item in ($allItems)) {$hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($Algorithm)).Hash.ToLower();
$relativePath = Resolve-Path -Path ($item.FullName) -Relative -ErrorAction 'SilentlyContinue';
if (-not $relativePath) { $relativePath =$item.Name; };
if ($relativePath.StartsWith(".\")) {
$relativePath =$relativePath.Substring(2);
};
$outputLine = "$hash$relativePath";
if ($singleOutFile) {
Add-Content -Path ($singleOutFile) -Value ($outputLine);
} else { } else {
$currentOutFile = "$($item.FullName).$($Algorithm.ToLower())"; $singleOutFile = "checksums.$($Algorithm.ToLower())";
$null = New-Item -Path ($currentOutFile) -ItemType 'File' -Force;
Add-Content -Path ($currentOutFile) -Value ($outputLine);
}; };
Write-Output $outputLine; $linesToWrite = @();
foreach ($item in ($allItems)) {
$hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($Algorithm)).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);
};
$outputLine = "${hash} ${relativePath}";
$linesToWrite += $outputLine;
Write-Output $outputLine;
};
Set-Content -Path ($singleOutFile) -Value $linesToWrite -Encoding utf8;
}
# Auto file for explicit individual files (No wildcard)
else {
foreach ($item in ($allItems)) {
$hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($Algorithm)).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);
};
$outputLine = "${hash} ${relativePath}";
Write-Output $outputLine;
# Save directly next to the original file: <filename>.<algo>
$itemOutFile = "$($item.FullName).$($Algorithm.ToLower())";
Set-Content -Path ($itemOutFile) -Value $outputLine -Encoding utf8;
};
}; };
}; };
} }
# Standard console output (No save flags passed)
else { else {
foreach ($item in ($allItems)) {$hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($Algorithm)).Hash.ToLower(); foreach ($item in ($allItems)) {
$hash = (Get-FileHash -Path ($item.FullName) -Algorithm ($Algorithm)).Hash.ToLower();
$relativePath = Resolve-Path -Path ($item.FullName) -Relative -ErrorAction 'SilentlyContinue'; $relativePath = Resolve-Path -Path ($item.FullName) -Relative -ErrorAction 'SilentlyContinue';
if (-not $relativePath) { $relativePath =$item.Name; }; if (-not $relativePath) { $relativePath = $item.Name; };
if ($relativePath.StartsWith(".\")) { if ($relativePath.StartsWith(".\") -or $relativePath.StartsWith("./")) {
$relativePath =$relativePath.Substring(2); $relativePath = $relativePath.Substring(2);
}; };
$outputLine = "$hash$relativePath"; $outputLine = "${hash} ${relativePath}";
Write-Output $outputLine; Write-Output $outputLine;
}; };
}; };