Public/IgugaChecksumUtility.ps1
function IgugaChecksumUtility { <# .SYNOPSIS Generates and validate checksums for files or directories .DESCRIPTION Generates and validate checksum file hashes for a variety of algorithms .PARAMETER Mode Sets the operation mode. The allowed modes are: Generate, Validate, Compare, SetMailerSetting, RemoveMailerSetting, ShowMailerSetting .PARAMETER Path Sets the path to a given file or directory .PARAMETER BasePath Used with Validate mode, sets the base path. This parameter is usefull when the paths inside of the checksum file are relative and the file being validated is located in a not related path. .PARAMETER Algorithm Sets the hashing algorithm to be used in the checksum operation. The allowed algotithms are: MD5, SHA1, SHA256, SHA384 and SHA512 .PARAMETER Hash Used with Compare mode, sets the specific previously known hash .PARAMETER Filter Used with Generate mode when the path is a directory, specifies a filter to qualify the Path parameter. Example: '*.txt' .PARAMETER Exclude Used with Generate mode when the path is a directory, specifies an array of one or more string patterns to be matched as the cmdlet gets child items. Any matching item is excluded from the output. Enter a path element or pattern, such as *.txt or A*. Wildcard characters are accepted .PARAMETER Depth Used with Generate mode when the path is a directory, allow you to limit the recursion to X levels. For example, -Depth 2 includes the Path parameter's directory, first level of subdirectories, and second level of subdirectories. .PARAMETER OutFile Used with Generate mode, sets whether it will generate a checksum file or not .PARAMETER OutFilePath Used with Generate mode, sets the path of the generated checksum file. If this parameter is not provided the default name will be "{Algorithm}SUMS.txt" and will be stored on the Path root directory .PARAMETER UseAbsolutePath Used with Generate mode, sets whether the checksum file path should be absolute or not .PARAMETER OutputFilePath Sets the file path to export the output. If the output file path is not provided the output will be printed to the console .PARAMETER Silent Omitte the progress status and the output will not be printed on the console .PARAMETER SendEmailNotification Used with Validate mode, indicates in which condition a notification email should be sent after the validation process. Please note that the email notification only supported Powershell version 7 or higher. The allowed values are: None, Always, Success, NotSuccess. 'None' means no notification mail will be sent. 'Always' means a notification will be sent after each validation process. 'Success' means a notification mail will be sent only if all file validation passed. 'NotSuccess' means a notification mail will be sent if at least one file validation failed or not found. .PARAMETER MailerSetting Used with SetMailerSetting mode, sets the mailer settings .PARAMETER From Used with the parameter SendEmailNotification, sets the from mail address .PARAMETER ToList Used with the parameter SendEmailNotification, sets the to list mail addresses .PARAMETER CcList Used with the parameter SendEmailNotification, sets the cc list mail addresses .PARAMETER BccList Used with the parameter SendEmailNotification, sets the bcc list mail addresses .EXAMPLE # Checksum a single file, and output to console IgugaChecksumUtility -Mode Generate -Path C:\Test\File.docx .EXAMPLE # Checksum an entire directory using the SHA512 algorithm and create a checksum file IgugaChecksumUtility -Mode Generate -Path C:\Test\ -Algorithm SHA512 -OutFile .EXAMPLE # Perform a validate operation on a checksum file IgugaChecksumUtility -Mode Validate -Path C:\Test\SHA512SUMS.txt -Algorithm SHA512 .EXAMPLE # Perform a validate operation on a checksum file when the paths inside the file being validated is located on a different path and send an email notification (only supported on PS 7 or higher) if there is any failed validation or file not found # First we need to set the Mailer settings. We just need to do this once. All this info will be stored on the user local computer. using module IgugaChecksumUtility $Credential = Get-Credential -Message "Please enter the SMTP Server username and password." $MailerSetting = [IgugaMailerSetting]::new("smtp.gmail.com", 587, $Credential) IgugaChecksumUtility -Mode SetMailerSetting -MailerSetting $MailerSetting # You can see all the Mailer settings and where the data is located if you run the following PS command line IgugaChecksumUtility -Mode ShowMailerSetting # If you wich to remove the Mailer setting, then run the follow PS command line IgugaChecksumUtility -Mode RemoveMailerSetting # Then, define the sender(From) and the recipents (ToList) and run the validation $From = [IgugaMailAddress]::new("My Name", "my.name@gmail.com") $ToList = @([IgugaMailAddress]::new("name1@example.com"), [IgugaMailAddress]::new("name2@example.com")) IgugaChecksumUtility -Mode Validate -Path "\\server1\checksums\apps\SHA256SUMS.txt" -BasePath "C:\Apps" -Algorithm SHA512 -SendMailNotification NotSuccess -From $From -ToList $ToList .EXAMPLE # Perform a compare operation on a file with a known hash IgugaChecksumUtility -Mode Compare -Path C:\Test\File.docx -Algorithm SHA1 -Hash ED1B042C1B986743C1E34EBB1FAF758549346B24 #> [CmdletBinding(SupportsShouldProcess)] Param( [Parameter(Position = 0, Mandatory = $true, HelpMessage = "The the operation mode. The allowed modes are: Generate, Validate, Compare, SetMailerSetting, RemoveMailerSetting and ShowMailerSetting")] [ValidateSet("Generate", "Validate", "Compare", "SetMailerSetting", "RemoveMailerSetting", "ShowMailerSetting")] [string] $Mode, [string] $Path, [string] $BasePath, [ValidateSet("MD5", "SHA1", "SHA256", "SHA384", "SHA512")] [string] $Algorithm = "SHA256", [string] $Hash, [string] $Filter, [string[]] $Exclude, [int] $Depth, [Switch] $OutFile, [string] $OutFilePath, [Switch] $UseAbsolutePath, [AllowEmptyString()] [string] $OutputFilePath, [Switch] $Silent, [string] [ValidateSet("None", "Always", "Success", "NotSuccess")] $SendEmailNotification = "None", [IgugaMailerSetting] $MailerSetting, [IgugaMailAddress] $From, [IgugaMailAddress[]] $ToList, [IgugaMailAddress[]] $CcList, [IgugaMailAddress[]] $BccList ) $Script:TotalOfItems = 0 $Script:ReportItemsGenerated = 0 $Script:ReportItemsValid = 0 $Script:ReportItemsInvalid = 0 $Script:ReportItemsFileNotFound = 0 $SettingsFilePath = [Environment]::GetFolderPath([System.Environment+SpecialFolder]::ApplicationData) $SettingsFilePath = Join-Path -Path $SettingsFilePath -ChildPath "$($MyInvocation.MyCommand.Module.Name)\Settings.clixml" if ($Mode -notin @("SetMailerSetting", "RemoveMailerSetting", "ShowMailerSetting")) { if ([string]::IsNullOrWhiteSpace($Path)) { Write-IgugaColorOutput "[-] $($Script:LocalizedData.ErrorUtilityParameterRequiredMode -f $Mode, 'Path')" -ForegroundColor Red return } if (-not(Test-Path -LiteralPath $Path -PathType Any)) { Write-IgugaColorOutput "[-] $($Script:LocalizedData.ErrorUtilityPathNotFound -f $Mode, $Path)" -ForegroundColor Red return } $Path = Get-IgugaCanonicalPath -Path $Path } $OutputFilePathDefinedByUser = $true if ([string]::IsNullOrWhiteSpace($OutFilePath)) { $OutputFilePathDefinedByUser = $false } if (-not($SendEmailNotification -eq "None")) { if ($PSVersionTable.PSVersion.Major -lt 7) { Write-IgugaColorOutput "[-] $($Script:LocalizedData.ErrorPSVersionFunctionNotSupported -f 'Send-IgugaMailMessage', '7.0')" -ForegroundColor Red return } if (-not(Test-Path -LiteralPath $SettingsFilePath -PathType Leaf)) { Write-IgugaColorOutput -Message "[-] $($Script:LocalizedData.ErrorUtilitySettingsFileDoesNotExists -f 'SendEmailNotification', 'SetMailerSetting')" -ForegroundColor Red return } if ($null -eq $From) { Write-IgugaColorOutput "[-] $($Script:LocalizedData.ErrorUtilityParameterRequired -f 'SendEmailNotification', 'From')" -ForegroundColor Red return } if ($ToList.Count -eq 0) { Write-IgugaColorOutput "[-] $($Script:LocalizedData.ErrorUtilityParameterRequired -f 'SendEmailNotification', 'ToList')" -ForegroundColor Red return } if (-not($OutputFilePathDefinedByUser)) { $OutputFilePath = Join-Path -Path $([System.IO.Path]::GetTempPath()) -ChildPath "IgugaChecksumReport.$(Get-Random).txt" } } if (-not([string]::IsNullOrWhiteSpace($OutputFilePath))) { $OutputFilePath = Get-IgugaCanonicalPath -Path $OutputFilePath -NonExistentPath:$(-not(Test-Path -LiteralPath $OutputFilePath -PathType Leaf)) } Write-IgugaReporSummary -Mode $Mode -OutputFilePath $OutputFilePath -Algorithm $Algorithm -Path $Path -Verbose:($PSBoundParameters['Verbose'] -eq $true) if ($Mode -eq "Validate") { try { $Results = Test-IgugaChecksumFile -FilePath $Path -BasePath $BasePath -Algorithm $Algorithm -Silent:$Silent $Script:TotalOfItems = $Results.Length foreach ($Result in $Results) { switch ($Result.Status) { "PASS" { $Script:ReportItemsValid++ Write-IgugaReportContent -Text $($Script:LocalizedData.ValidationPassed -f $Result.FilePath) -ForegroundColor Green -OutputFilePath $OutputFilePath -Silent:$Silent break } "FAIL" { $Script:ReportItemsInvalid++ Write-IgugaReportContent -Text $($Script:LocalizedData.ValidationFailed -f $Result.FilePath, $Result.Hash, $Result.ExpectedHash) -ForegroundColor Red -OutputFilePath $OutputFilePath -Silent:$Silent break } "NOT_FOUND" { $Script:ReportItemsFileNotFound++ Write-IgugaReportContent -Text "[-] $($Script:LocalizedData.ErrorUtilityValidateFileNotFound -f $Result.FilePath)" -ForegroundColor Red -OutputFilePath $OutputFilePath -Silent:$Silent break } } } } catch { Write-IgugaColorOutput "[-] $($_.Exception)" -ForegroundColor Red return } } elseif ($Mode -eq "Compare") { try { $Result = Compare-IgugaFileHash -FilePath $Path -Algorithm $Algorithm -Hash $Hash -Silent:$Silent $Script:TotalOfItems = 1 switch ($Result.Status) { "PASS" { $Script:ReportItemsValid++ Write-IgugaReportContent -Text $($Script:LocalizedData.ValidationPassed -f $Result.FilePath) -ForegroundColor Green -OutputFilePath $OutputFilePath -Silent:$Silent break } "FAIL" { $Script:ReportItemsInvalid++ Write-IgugaReportContent -Text $($Script:LocalizedData.ValidationFailed -f $Result.FilePath, $Result.Hash, $Result.ExpectedHash) -ForegroundColor Red -OutputFilePath $OutputFilePath -Silent:$Silent break } } } catch { if ($_.CategoryInfo -eq [ErrorCategory]::ObjectNotFound) { Write-IgugaColorOutput "[-] $($Script:LocalizedData.ErrorUtilityPathNotValidFile -f $Mode, $Path)" -ForegroundColor Red } elseif ($_.CategoryInfo -eq [ErrorCategory]::InvalidArgument) { Write-IgugaColorOutput "[-] $($Script:LocalizedData.ErrorUtilityPathNotValidFile -f $Mode, 'Hash')" -ForegroundColor Red } else { Write-IgugaColorOutput "[-] $($_.Exception)" -ForegroundColor Red } return } } elseif ($Mode -eq "Generate") { $Parameters = @{ Path = $Path Algorithm = $Algorithm UseAbsolutePath = $UseAbsolutePath.IsPresent Silent = $Silent.IsPresent } if ($PSBoundParameters.ContainsKey("Filter")) { $Parameters.Filter = $Filter } if ($PSBoundParameters.ContainsKey("Exclude")) { $Parameters.Exclude = $Exclude } if ($PSBoundParameters.ContainsKey("Depth")) { $Parameters.Depth = $Depth } $Checksums = Get-IgugaPathChecksum @Parameters $OutFileName = "" # If OutFile is to be generated, then set the outfile name to match the algorithm if ($OutFile.IsPresent) { $OutFileName = $Algorithm.ToUpper() + "SUMS.txt" } if ($OutFile.IsPresent) { if ([string]::IsNullOrWhiteSpace($OutFilePath)) { $OutFilePath = Join-Path -Path $Path -ChildPath $OutFileName } if (Test-Path -LiteralPath $OutFilePath -PathType Leaf) { Remove-Item $OutFilePath } } if (-not($Silent.IsPresent)) { Write-Progress -Activity $Script:LocalizedData.PrintChecksumProgressMessage -Status $Script:LocalizedData.PrintChecksumProgressStatus } $Script:TotalOfItems = $Checksums.Length foreach ($Checksum in $Checksums) { $Script:ReportItemsGenerated++ if ($OutFile.IsPresent) { Add-Content $OutFilePath $Checksum.Checksum } Write-IgugaReportContent -Text $Checksum.Checksum -ForegroundColor Green -OutputFilePath $OutputFilePath -Silent:$Silent } if (-not($Silent.IsPresent)) { Write-Progress -Activity $Script:LocalizedData.PrintChecksumProgressCompleted -Completed } } elseif ($Mode -eq "SetMailerSetting") { if ($null -eq $MailerSetting) { Write-IgugaColorOutput "[-] $($Script:LocalizedData.ErrorUtilityParameterRequiredMode -f $Mode, 'MailerSetting')" -ForegroundColor Red return } else { try { if ($PSCmdlet.ShouldProcess("MailerSetting", "SetMailerSetting")) { Set-IgugaMailerSetting -Settings $MailerSetting -SettingsFilePath $SettingsFilePath -WhatIf:$WhatIfPreference Write-IgugaReportContent -Text $($Script:LocalizedData.SetSettingSuccess -f 'MailerSetting') -ForegroundColor Green -OutputFilePath $OutputFilePath -Silent:$Silent } } catch { Write-IgugaColorOutput "[-] $($_.Exception)" -ForegroundColor Red } } } elseif ($Mode -eq "ShowMailerSetting") { try { $settings = Get-IgugaMailerSetting -SettingsFilePath $SettingsFilePath Write-IgugaColorOutput "" Write-IgugaColorOutput "$($Script:LocalizedData.ShowMailerSettingSmtpServer -f $settings.SMTPServer)" Write-IgugaColorOutput "$($Script:LocalizedData.ShowMailerSettingPort -f $settings.Port)" if ($settings.Credential) { Write-IgugaColorOutput "$($Script:LocalizedData.ShowMailerSettingUsername -f $settings.Credential.Username)" Write-IgugaColorOutput "$($Script:LocalizedData.ShowMailerSettingPassword -f '****************')" } Write-IgugaColorOutput "$($Script:LocalizedData.ShowMailerSettingEncryption -f $settings.Encryption)" Write-IgugaColorOutput "$($Script:LocalizedData.ShowMailerSettingFilePath -f $SettingsFilePath)" Write-IgugaColorOutput "" } catch { if ($_.FullyQualifiedErrorId -eq 'PathNotFound') { Write-IgugaColorOutput "[-] $($Script:LocalizedData.ErrorUtilitySettingsFileDoesNotExistsMode -f $Mode, 'SetMailerSetting')" -ForegroundColor Red return } else { Write-IgugaColorOutput "[-] $($_.Exception)" -ForegroundColor Red return } } } elseif ($Mode -eq "RemoveMailerSetting") { try { if ($PSCmdlet.ShouldProcess("MailerSetting", "RemoveMailerSetting")) { Remove-IgugaMailerSetting -SettingsFilePath $SettingsFilePath -WhatIf:$WhatIfPreference Write-IgugaReportContent -Text $($Script:LocalizedData.RemoveSettingSuccess -f 'MailerSetting') -ForegroundColor Green -OutputFilePath $OutputFilePath -Silent:$Silent } } catch { if ($_.FullyQualifiedErrorId -eq 'PathNotFound') { Write-IgugaColorOutput "[-] $($Script:LocalizedData.ErrorUtilitySettingsFileDoesNotExistsMode -f $Mode, 'SetMailerSetting')" -ForegroundColor Red return } else { Write-IgugaColorOutput "[-] $($_.Exception)" -ForegroundColor Red return } } } Write-IgugaReporSummary -Mode $Mode -OutputFilePath $OutputFilePath -Algorithm $Algorithm -Path $Path -Footer -Verbose:($PSBoundParameters['Verbose'] -eq $true) if (-not($SendEmailNotification -eq "None")) { $SendNotification = $false if (($SendEmailNotification -eq "Success") -and ($Script:TotalOfItems -eq $Script:ReportItemsValid)) { $SendNotification = $true } elseif (($SendEmailNotification -eq "NotSuccess") -and ($Script:TotalOfItems -ne $Script:ReportItemsValid)) { $SendNotification = $true } elseif ($SendEmailNotification -eq "Always") { $SendNotification = $true } if (($Mode -eq 'Validate') -and $SendNotification) { $MailerSetting = Get-IgugaMailerSetting -SettingsFilePath $SettingsFilePath $TextBody = "$($Script:LocalizedData.ValidationEmailNotificationGreetings)`n" $TextBody += "`n" $TextBody += "$($Script:LocalizedData.ValidationEmailNotificationInstructions)`n" $TextBody += "$($Script:LocalizedData.ValidationEmailNotificationTotalItems -f $Script:TotalOfItems)`n" $TextBody += "$($Script:LocalizedData.ValidationEmailNotificationTotalPassed -f $Script:ReportItemsValid)`n" $TextBody += "$($Script:LocalizedData.ValidationEmailNotificationTotalFailed -f $Script:ReportItemsInvalid)`n" $TextBody += "$($Script:LocalizedData.ValidationEmailNotificationTotalFileNotFound -f $Script:ReportItemsFileNotFound)`n" $TextBody += "`n" $TextBody += "$($Script:LocalizedData.ValidationEmailNotificationMoreInfo)`n" $TextBody += "`n" $TextBody += "---`n" $TextBody += "$($Script:LocalizedData.ValidationEmailNotificationSignature -f $MyInvocation.MyCommand.Module.Name)`n" $Parameters = @{ MailerSetting = $MailerSetting From = $From ToList = $ToList CcList = $CcList BccList = $BccList Subject = "$($Script:LocalizedData.ValidationEmailNotificationSubject -f $MyInvocation.MyCommand.Module.Name)" TextBody = $TextBody AttachmentList = @($OutputFilePath) } Send-IgugaMailMessage @Parameters Write-IgugaColorOutput "[+] $($Script:LocalizedData.EmailNotificationSentWithSuccess)" } if (-not($OutputFilePathDefinedByUser) -and (Test-Path -LiteralPath $OutputFilePath -PathType Leaf)) { Remove-Item $OutputFilePath } } if (-not($Silent.IsPresent)) { Write-IgugaColorOutput "[+] $($Script:LocalizedData.OpCompleted)" if (-not($PSBoundParameters.ContainsKey("Verbose"))) { Write-IgugaColorOutput "[+] $($Script:LocalizedData.VerboseMoreInfo)" } } } |