Write-Error, $Error, and Users

Write-Error is useful, but the output is intimidating for new users.  You want them to see a nice message, but they get a wall of red text including a stack dump.

Here’s a way to output it as a warning, but populate $Error as well.

     function Out-Error
    {
        param (
            [String]$Message = "No error message.",
            [System.Management.Automation.ErrorCategory]$Category = 'NotSpecified',
            [System.Management.Automation.ActionPreference]$ErrorAction = $Script:ErrorAction
        );

        $message = "($((Get-Variable -Scope 1 -Name MyInvocation -ValueOnly).MyCommand.Name)) $message";
        Write-Warning -Message $message;
        Write-Error -ErrorAction SilentlyContinue -Message $message -Category $category;
    
        if ($ErrorAction -notmatch ‘Continue$’)
        {
            break function;
        }
    }

Here's the function in a basic script outline:

 param (
    [System.Management.Automation.ActionPreference]$ErrorAction = $(Get-Variable -Scope 1 -Name ErrorActionPreference -ValueOnly),
    [switch]$AppendError
);

Begin
{

    #region functions

    function Out-Error
    {
        param (
            [String]$Message = "No error message.",
            [System.Management.Automation.ErrorCategory]$Category = 'NotSpecified',
            [System.Management.Automation.ActionPreference]$ErrorAction = $Script:ErrorAction
        );

        $message = "($((Get-Variable -Scope 1 -Name MyInvocation -ValueOnly).MyCommand.Name)) $message";
        Write-Warning -Message $message;
        Write-Error -ErrorAction SilentlyContinue -Message $message -Category $category;
    
        if ($ErrorAction -notmatch ‘Continue$’)
        {
            break function;
        }
    }

    function Test-OutError
    {
        param (
            [string]$bar,
            [switch]$foo
        );

        # do stuff
        Out-Error -Message 'we failed to do stuff' -Category ObjectNotFound;

        # do more stuff
        Out-Error -Message "-Foo $foo we failed to do more stuff with -Bar '$bar'." -Category ObjectNotFound;
    }

    function Test-OutError2
    {
        param (
            [string]$bar,
            [switch]$foo
        );

        # do stuff
        Out-Error -Message 'we failed to do stuff' -Category ObjectNotFound -ErrorAction Stop;

        # do more stuff
        Out-Error -Message 'we failed to do more stuff' -Category ObjectNotFound;
    }

    #endregion
    #region initialization

    if (!$AppendError)
    {
        $Error.Clear();
    }

    #endregion
}

Process
{
    # do stuff
    Test-OutError -bar baz;
    Test-OutError2 -foo -bar baz;
}

End
{
    # do stuff on success

    # do stuff unconditionally
    :function foreach ($_ in 1)
    {
        $Error | Export-Clixml -Path "$home\Error.Clixml";
    }
}