Public/Logging/Write-CustomError.ps1

function Write-CustomError {

    <#
        .SYNOPSIS
            Mimics Write-Error but with optional logging to the Windows Event Log.

        .DESCRIPTION
            This function writes error messages to the console and, if instructed, to the specified Windows Event Log.
            It supports both predefined and custom event logging, allowing flexibility in logging approaches.

        .PARAMETER CreateWindowsEvent
            Switch to indicate if a Windows Event Log entry should be created instead of just outputting a verbose message.

        .PARAMETER Message
            The message to be written, either to the console (as verbose) or the Windows Event Log.

        .PARAMETER EventInfo
            Predefined event information of type [EventIDs], if using predefined events.

        .PARAMETER EventId
            Custom event ID if logging a custom event.

        .PARAMETER EventName
            Name of the custom event being logged.

        .PARAMETER EventCategory
            Custom event category for the event.

        .EXAMPLE
            # Write a simple Error message
            Write-CustomError -Message "Starting process" -Verbose

        .EXAMPLE
            # Log a error message and also create a Windows Event Log entry with predefined event info
            Write-CustomError -CreateWindowsEvent -EventInfo ([EventIDs]::AuthenticationFailed) -Message "Unknown user."

        .EXAMPLE
            # Log a error message and also create a Windows Event Log entry with predefined event info
            $Splat = @{
                CreateWindowsEvent = $true
                EventInfo = ([EventIDs]::FailedGetGroupMembership)
                Message = 'Error while Fetching members of the group.'
            }
            Write-CustomError @Splat

        .EXAMPLE
            # Log a custom event with specific event details
            Write-CustomError -CreateWindowsEvent -EventId 20001 -EventName "Authentication Failure" -EventCategory Security
            -Message "User unknown." -Verbose

        .NOTES
            Ensure necessary event types (EventIDs, EventCategory, etc.) are defined on Class.Events.ps1 file
            located under Classes folder.
            This file is written in C# (CSharp) language and compiled in runtime when module is imported. This is
            due visibility and compatibility issues on modules when using just PowerShell code.
    #>


    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Default')]
    [OutputType([void])]

    param(

        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'If present a new event will be created in the corresponding Windows Event among Write-Verbose.',
            Position = 0)]
        [switch]
        $CreateWindowsEvent,

        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Message body of the event and/or Verbose message.',
            Position = 1,
            ParameterSetName = 'Default')]
        [Parameter(ParameterSetName = 'Custom')]
        [ValidateNotNullOrEmpty()]
        [string]
        $Message,

        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Default built-in Event Information to be used of type [EventIDs].',
            Position = 2,
            ParameterSetName = 'Default')]
        [EventIDInfo]
        $EventInfo,

        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Custom Event ID to be used of type [EventID].',
            Position = 2,
            ParameterSetName = 'Custom')]
        [ValidateScript({
                [Enum]::IsDefined([EventID], $_)
            })]
        [EventID]
        $EventId,

        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Custom Event Name to be used.',
            Position = 3,
            ParameterSetName = 'Custom')]
        [ValidateNotNullOrEmpty()]
        [string]
        $EventName,

        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Custom Category to be used of type [EventCategory].',
            Position = 4,
            ParameterSetName = 'Custom')]
        [ValidateScript({
                [Enum]::IsDefined([EventCategory], $_)
            })]
        [EventCategory]
        $EventCategory

    )

    Begin {

        $ErrorActionPreference = 'Stop'

        [hashtable]$Splat = [hashtable]::New([StringComparer]::OrdinalIgnoreCase)

    } #end Begin

    Process {
        if ($PSCmdlet.ShouldProcess("Writing verbose log: $Message")) {

            # Handle logging to Windows Event Log if requested
            If ($PSBoundParameters.ContainsKey('CreateWindowsEvent')) {

                # Use predefined event info if available, otherwise, use custom event details
                If ($PSBoundParameters.ContainsKey('EventInfo')) {

                    # Predefined (Built-In) event to be used.
                    # Those are defined on the Class.Events.ps1 file under Classes folder.
                    Write-CustomLog -EventInfo $PSBoundParameters['EventInfo'] -Message $PSBoundParameters['Message']

                } else {

                    # Custom event logging
                    $Splat = @{
                        CustomEventId  = $PSBoundParameters['EventID']
                        EventName      = $PSBoundParameters['EventName']
                        EventCategory  = $PSBoundParameters['EventCategory']
                        Message        = $PSBoundParameters['Message']
                        CustomSeverity = [EventSeverity]::Error
                        Verbose        = $PSBoundParameters['Verbose']
                    }
                    Write-CustomLog @Splat

                } #end Else-If

            } #end If CreateWindowsEvent

            # Call Write-Verbose with parsed message.
            Write-Error -Message $Message -Verbose:$PSBoundParameters['Verbose']
        }
    } #end Process

    End {

    } #end End
} #end Function