Modules/Helper.psm1

function Convert-HtmlMessage {
    <#
    .SYNOPSIS
    Converts an HTML message to plain text or Markdown format, optionally making it JSON-safe and/or single line.
 
    .DESCRIPTION
    This function processes an input HTML message and converts it to either plain text or Markdown output by replacing common HTML tags with appropriate equivalents.
    It supports making the output JSON-safe by escaping special characters, and can optionally output the result as a single line by removing line breaks.
 
    .PARAMETER Message
    The input HTML message string to convert.
 
    .PARAMETER Output
    Specifies the output format. Valid values are 'Text' (default) for plain text output, or 'Markdown' for Markdown-formatted output.
 
    .PARAMETER JsonSafe
    If set, converts the output to a JSON-safe string by escaping characters and compressing the output using ConvertTo-Json.
 
    .EXAMPLE
    Convert-HtmlMessage -Message "<p><b>Hello</b><br>World</p>" -Output Text
 
    Outputs:
    Hello
 
    World
 
    .EXAMPLE
    Convert-HtmlMessage -Message "<p><b>Hello</b><br>World</p>" -Output Markdown
 
    Outputs:
    **Hello**
 
    World
 
    .EXAMPLE
    Convert-HtmlMessage -Message "<p>Hello &emsp;World</p>" -JsonSafe
 
    Outputs a JSON-safe escaped string of the input HTML.
 
    .NOTES
    - The SingleLine switch parameter is defined but not yet implemented in the function.
    - Verbose output can be enabled to see detailed processing steps by using the -Verbose common parameter.
 
    .LINK
    https://gitea.netillimar.net:5443/netillimar/powershell-custom-modules
    #>


    [CmdletBinding()]
    param (
        $Message,
        [ValidateSet("Text", "Markdown")]$Output = "Text",
        [switch]$JsonSafe
    )

    $Message = ($Message | Out-String)

    Write-Verbose -Message "Input Message"
    Write-Verbose -Message $Message

    if ($JsonSafe) {
        $OutputMessage = $Message | ConvertTo-Json -Compress
        Write-Verbose -Message "Convert HTML message to JSON safe"
        Write-Verbose -Message $OutputMessage

        return $OutputMessage
    }

    Write-Verbose -Message "Output $($Output):"

    $OutputMessage = $Message

    switch ($Output) {
        "Text" {
            $Replacements = @{
                '<p>' = ""
                '</p>' = "`n`n"
                '<br>' = "`n"
                '<b>' = ""
                '</b>' = ""
                '&emsp;' = " "
                '</span>' = ""
                '(?i)<span style="color:.*?;">' = ""
            }
        }

        "Markdown" {
            $Replacements = @{
                '<p>' = ""
                '</p>' = "`n`n"
                '<br>' = "`n"
                '<b>' = '**'
                '</b>' = '**'
                '&emsp;' = " "
                '</span>' = ""
                '(?i)<span style="color:.*?;">' = ""
            }
        }
    }

    foreach ($key in $Replacements.Keys) {
        $OutputMessage = $OutputMessage -replace $key, $Replacements[$key]
    }

    Write-Verbose -Message $OutputMessage

    return $OutputMessage
}

function Format-Param {
    [CmdletBinding()]
    param (
        $BoundParameters
    )

    if (!$BoundParameters) {
        Write-Verbose -Message "No parameters were passed"
        $FormatedParams = "Parameters:`nNo parameters were passed"

        return $FormatedParams
    }

    $ForbidenOnes = @("SessionId", "Password", "authentication-token", "Authorization")
    $MaximumSupported = 31839
    $FormatedParams = @()
    $SimplifiedParams = @()
    $FormatedParams += "Parameters:`n`n"

    foreach ($BoundParameter in $BoundParameters.Keys) {
        $RawValue = $BoundParameters[$BoundParameter]
        Write-Verbose -Message "Formating parameter $($BoundParameter):`n$(($RawValue | Out-String).TrimEnd())"

        if (!$RawValue) {
            $ParameterValue = $null
            $TypeName = ""
        } else {
            $TypeName = $RawValue.GetType().Name

            switch ($TypeName) {
                "SwitchParameter" {
                    $ParameterValue = [bool]$RawValue.IsPresent
                }
            
                Default {
                    $ParameterValue = $RawValue
                }
            }
        }

        $ValueAsString = ($ParameterValue | Out-String).TrimEnd()

        if ($BoundParameter -in $ForbidenOnes) { 
            $ValueAsString = "...sanitized..."
        }

        if ($ValueAsString.Length -gt 100) {
            $SimplifiedParams += "$($BoundParameter):`n$(($ValueAsString[0..100] + "..."))`n`n"
        } else {
            $SimplifiedParams += "$($BoundParameter):`n$(($ValueAsString).TrimEnd())`n`n"
        }

        $FormatedParams += "$($BoundParameter):`n$(($ValueAsString).TrimEnd())`n`n"
    }

    $FormatedParams = $FormatedParams -join ""

    if ($FormatedParams.Length -gt $MaximumSupported) {
        $FormatedParams = $SimplifiedParams -join ""
    }

    Write-Verbose -Message $FormatedParams

    return $FormatedParams
}

function Write-CustomLog {
    <#
    .SYNOPSIS
    Writes a custom event to the Windows Event Viewer.
 
    .DESCRIPTION
    This function writes a log entry to the Windows Event Viewer using a specified source, log name, and entry type.
    If the source does not exist, the function attempts to create it (requires administrative privileges).
    The message can be plain text or HTML, which will be converted to text before logging.
 
    .PARAMETER Message
    The content of the log entry. Can be plain text or HTML.
 
    .PARAMETER Source
    The source of the event log entry. Defaults to the global variable $Script:Source if not specified.
 
    .PARAMETER LogName
    The name of the event log to write to. Currently supports only the "Application" log.
 
    .PARAMETER EntryType
    The type of log entry. Valid values are "Information", "Warning", and "Error".
 
    .PARAMETER EventId
    The event ID to associate with the log entry. Defaults to 0.
 
    .EXAMPLE
    Write-CustomLog -Message "Service started successfully." -Source "MyApp" -EntryType "Information" -EventId 1001
 
    .EXAMPLE
    Write-CustomLog -Message "<b>Error:</b> Something failed!" -Source "MyApp" -EntryType "Error" -Verbose
 
    .NOTES
    Requires administrative privileges to create new event sources or write to the event log.
 
    .LINK
    https://gitea.netillimar.net:5443/netillimar/powershell-custom-modules
    #>


    [CmdletBinding()]
    param (
        $Message,
        $MessageHtml,
        $Source = $Script:Source,
        [ValidateSet("Application")]$LogName = "Application",
        [ValidateSet("Error", "Information", "Warning")]$EntryType = "Information",
        $EventId = 0
    )

    try {
        Test-Path "$env:SystemRoot\System32\config\system" -ErrorAction Stop | Out-Null
        $IsAdmin = $true
        Write-Verbose -Message "Admin Powershell session"
    } catch {
        $IsAdmin = $false
        Write-Verbose -Message "Not an admin Powershell session"
    }

    if ($IsAdmin) {
        if ($MessageHtml) {
            Write-Verbose -Message "Calling function Convert-HtmlMessage in case message is HTML"
            $MessageText = Convert-HtmlMessage -Message $MessageHtml -Output Text -Verbose:$Verbose
        } else {
            $MessageText = $Message | Out-String
        }

        if (!([System.Diagnostics.EventLog]::SourceExists($Source))) {
            Write-Verbose -Message "Specified source doesn't exist"

            try {
                New-EventLog -LogName $LogName -Source $Source
                $CreateSource = $true
                Write-Verbose -Message "Source $Source successfully created"
                
            } catch {
                $CreateSource = $false
                Write-Verbose -Message "Unable to create source $Source. Error: $($_.Exception.Message)"
            }
        }

        if (([System.Diagnostics.EventLog]::SourceExists($Source)) -or $CreateSource) {
            Write-Verbose -Message "Specified source exists"

            if ($($Script:RunCorrelationKey)) {
                $MessageText = "Execution Key: $($Script:RunCorrelationKey)`n`n$($MessageText)"
            }

            try {
                Write-EventLog -LogName $LogName -Source $Source -EntryType $EntryType -EventId $EventId -Message $MessageText -Verbose:$Verbose
                Write-Verbose -Message "Log successfully written`nLog name: $LogName`nSource: $Source`nEntryType: $EntryType`n"
                Write-Verbose -Message "Message:`n$($MessageText)"
            } catch {
                Write-Verbose -Message "Unable to write log message. Error: $($_.Exception.Message)"
            }
        } else {
            Write-Verbose -Message "Specified source doesn't exist"
        }
    } else {
        Write-Verbose -Message "The current session is not running as admin"
    }
}