Functions/Public/Write-Log.ps1

function Write-Log {
    <#
    .SYNOPSIS
        Writes structured log messages to a log file.

    .DESCRIPTION
        The Write-Log function writes timestamped log entries to a specified log file.
        Supports multiple log levels (INFO, WARNING, ERROR, DEBUG, VERBOSE) and
        automatically creates the log directory if it doesn't exist.

    .PARAMETER Message
        The message to write to the log file.

    .PARAMETER Level
        The severity level of the log entry.
        Valid values: INFO, WARNING, ERROR, DEBUG, VERBOSE
        Default is INFO.

    .PARAMETER LogFile
        The full path to the log file. If only a filename is provided,
        uses LogDirectory parameter or current directory.

    .PARAMETER LogDirectory
        The directory for log files. Used when LogFile is just a filename.
        Default is the current directory.

    .PARAMETER LogName
        Alternative to LogFile - creates a log file with this name (adds .log extension).
        Useful for simple logging scenarios.

    .PARAMETER PassThru
        If specified, also writes the message to the console with appropriate coloring.

    .PARAMETER Append
        If specified (default), appends to existing log file.
        Use -Append:$false to overwrite.

    .INPUTS
        System.String. You can pipe log messages to Write-Log.

    .OUTPUTS
        None by default. The log message string if -PassThru is specified.

    .EXAMPLE
        Write-Log -Message "Process started" -LogFile "C:\Logs\app.log"

        Writes an INFO level entry to the specified log file.

    .EXAMPLE
        Write-Log -Message "Connection failed" -Level ERROR -LogName "MyApp"

        Writes an ERROR entry to MyApp.log in current directory.

    .EXAMPLE
        Write-Log "User $username logged in" -LogFile $logPath -PassThru

        Logs the message and also displays it in the console.

    .EXAMPLE
        "Starting backup..." | Write-Log -Level INFO -LogFile $logPath

        Pipe a message to the log function.

    .NOTES
        Author: Sune Alexandersen Narud
        Version: 1.0.0
        Date: February 2026

        Log format: YYYY-MM-DD HH:mm:ss [LEVEL] Message
    #>


    [CmdletBinding(DefaultParameterSetName = 'LogFile')]
    param (
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$Message,

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

        [Parameter(ParameterSetName = 'LogFile')]
        [string]$LogFile,

        [Parameter(ParameterSetName = 'LogName')]
        [string]$LogName,

        [Parameter()]
        [string]$LogDirectory = (Get-Location).Path,

        [Parameter()]
        [switch]$PassThru,

        [Parameter()]
        [switch]$Append = $true
    )

    begin {
        # Determine the log file path
        if ($PSCmdlet.ParameterSetName -eq 'LogName') {
            $logPath = Join-Path $LogDirectory "$LogName.log"
        }
        elseif ($LogFile) {
            if ([System.IO.Path]::IsPathRooted($LogFile)) {
                $logPath = $LogFile
            }
            else {
                $logPath = Join-Path $LogDirectory $LogFile
            }
        }
        else {
            # Default log file name based on date
            $logPath = Join-Path $LogDirectory "log_$(Get-Date -Format 'yyyyMMdd').log"
        }

        # Ensure log directory exists
        $logDir = Split-Path -Parent $logPath
        if (-not (Test-Path -Path $logDir)) {
            New-Item -Path $logDir -ItemType Directory -Force | Out-Null
        }
    }

    process {
        # Format the log entry
        $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
        $logEntry = "$timestamp [$Level] $Message"

        # Write to file
        if ($Append) {
            $logEntry | Out-File -FilePath $logPath -Append -Encoding UTF8
        }
        else {
            $logEntry | Out-File -FilePath $logPath -Encoding UTF8
        }

        # Optionally output to console
        if ($PassThru) {
            $color = switch ($Level) {
                'ERROR'   { 'Red' }
                'WARNING' { 'Yellow' }
                'DEBUG'   { 'Gray' }
                'VERBOSE' { 'DarkGray' }
                default   { 'White' }
            }
            Write-Host $logEntry -ForegroundColor $color
            return $logEntry
        }
    }
}