Public/Logging/Write-Log.ps1

<#
.SYNOPSIS
    Writes a timestamped log entry to the console and an optional log file.
 
.DESCRIPTION
    Reads the log file path from $Global:LogFile set in the calling script; when set, every log
    line is also appended there (creating the containing directory if needed). Use -Section to
    write a visual section header to organize log output into readable blocks.
 
    Console output is gated by $Global:LogToConsole: it must be set to $true for console output
    to appear at all. Leaving it unset (the default, $null) or setting it to $false both suppress
    console output, same as passing -NoConsole - despite what "if not set" might suggest, an
    unset $Global:LogToConsole does NOT default to writing to the console.
 
    If neither $Global:LogFile nor $Global:LogToConsole is set, Write-Log produces no output.
 
.PARAMETER Message
    The message to log.
 
.PARAMETER Level
    Log severity level: INFO, WARNING, ERROR, DEBUG, or SUCCESS. Defaults to INFO. Controls the
    console color and the level tag in the line. Ignored when -Section is specified.
 
.PARAMETER Section
    Renders the message as a visual section header with divider lines instead of a timestamped
    entry.
 
.PARAMETER NoConsole
    Suppresses console output; writes to the log file only. Console output is already suppressed
    by default unless $Global:LogToConsole has been explicitly set to $true - see DESCRIPTION.
 
.EXAMPLE
    $Global:LogFile = "C:\Logs\MyScript_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
    $Global:LogToConsole = $true
 
    Write-Log 'Script started'
    Write-Log 'Phase 1: Connect' -Section
    Write-Log 'Connected to server' -Level SUCCESS
    Write-Log 'Retrying in 5s' -Level WARNING
    Write-Log 'Connection refused' -Level ERROR
 
    Writes each entry to both the console and the log file.
 
.EXAMPLE
    Write-Log 'Raw response body saved' -Level DEBUG -NoConsole
 
    Writes the entry to $Global:LogFile only, even when $Global:LogToConsole is $true.
 
.OUTPUTS
    None
#>

function Write-Log {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [string] $Message,

        [Parameter()]
        [ValidateSet('INFO', 'WARNING', 'ERROR', 'DEBUG', 'SUCCESS')]
        [string] $Level = 'INFO',

        [Parameter()]
        [switch] $Section,

        [Parameter()]
        [switch] $NoConsole
    )

    process {
        [string] $logFile = $Global:LogFile
        [bool]   $consoleOutput = $Global:LogToConsole

        if ($null -ne $consoleOutput -and $consoleOutput -eq $false) {
            $NoConsole = $true
        }

        if ($Section) {
            $divider = '-' * 80
            $lines = @('', $divider, " $Message", $divider, '')
            $color = 'White'
        } else {
            $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
            $tag = $Level.PadRight(7)
            $lines = @("$timestamp | $tag | $Message")
            $color = switch ($Level) {
                'INFO' {
                    'Cyan'
                }
                'WARNING' {
                    'Yellow'
                }
                'ERROR' {
                    'Red'
                }
                'DEBUG' {
                    'DarkGray'
                }
                'SUCCESS' {
                    'Green'
                }
            }
        }

        if (-not $NoConsole) {
            foreach ($line in $lines) {
                Write-Host $line -ForegroundColor $color
            }
        }

        if ($logFile) {
            $logDir = Split-Path -Path $logFile -Parent

            if ($logDir -and -not (Test-Path -Path $logDir)) {
                $null = New-Item -ItemType Directory -Path $logDir -Force
            }

            Add-Content -Path $logFile -Value $lines -Encoding UTF8
        }
    }
}