Public/Invoke-EmailOnError.ps1

<#
    .SYNOPSIS
    Runs a script block and sends an email if an error occurs.

    .DESCRIPTION
    Used to wrap code that needs to report on configuration or authentication errors. I mean we are forced to change passwords. ;-)

    .INPUTS
    None. You cannot pipe objects to Invoke-EmailOnError.

    .OUTPUTS
    None

    .PARAMETER Script
    A script block to execute with a catch to send email if exception is thrown.

    .PARAMETER Subject
    The subject of the email.

    .EXAMPLE
    PS> Invoke-EmailOnError -Script { Invoke-DoWork } -Subject "Error while executing Invoke-DoWork"

    .LINK
    Set-FileEmailConfig

    .NOTES
    Assumes email config is initialized using Set-FileEmailConfig
#>

function Invoke-EmailOnError {

    [CmdletBinding()]
    [OutputType([System.Void])]
    param(
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [ScriptBlock]
        $Script,

        [Parameter(Mandatory = $true, Position = 1)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Subject
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
    }

    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }

    process {
        Write-Debug "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)"
        try {
            $perf = Measure-Command { Invoke-Command -ScriptBlock $Script }
            Write-Information "$(Get-Date -f 'hh:mm:ss') Duration = $($perf.TotalSeconds) seconds"
        }
        catch {
            Write-Verbose "ERROR Encountered processsing script block: $($_)"
            Write-Verbose "Attempting to email"
            $firstError = $_
            try {
                Send-Email -Subject $Subject -Message "MESSAGE: $($_.ErrorDetails.Message) STACK: $($_.ScriptStackTrace)"
            }
            catch {
                Write-Information "$(Get-Date -f 'hh:mm:ss') SENDING EMAIL FAILED: $($_.Exception.Message)"
            }
            finally {
                throw $firstError
            }
        }
    }
}