public/Start-PSTaskLogging.ps1


function Start-PSTaskLogging {
    <#
    .SYNOPSIS
    Initializes logging for a PSTask script.
 
    .DESCRIPTION
    The Start-PSTaskLogging function sets up logging for a script using PSTask. It creates the necessary log file and writes the initial header. If logging is already active, it increments a reference count instead of initializing a new log.
 
    .PARAMETER LogName
    The name of the log for which logging is being initialized. This parameter is mandatory.
 
    .PARAMETER LogPath
    An optional custom path for the log file. If not specified, the function will use the default log path from the script configuration or the current location.
 
    .PARAMETER LogPathOverride
    An optional full path (including filename) for the log file. When specified, this overrides PSTask's internal file naming logic and uses the exact path provided. Cannot be used together with LogPath.
 
    .PARAMETER CustomFields
    A hashtable of custom fields to be added to the log header. This allows for additional context or metadata to be included in the log.
 
    .EXAMPLE
    Start-PSTaskLogging -LogName "MyScript"
    # This initializes logging for "MyScript" using the default log path.
 
    .EXAMPLE
    Start-PSTaskLogging -LogName "MyScript" -LogPath "C:\Logs" -CustomFields @{Version="1.0"; Environment="Production"}
    # This initializes logging for "MyScript" in the specified path with custom fields for version and environment.
 
    .EXAMPLE
    Start-PSTaskLogging -LogName "MyScript" -LogPathOverride "C:\Logs\CustomLog.log"
    # This initializes logging for "MyScript" using the exact file path specified, bypassing the automatic filename generation.
 
    .NOTES
    The function uses script-scoped variables ($script:PSTaskLoggingState and $script:Config) to manage logging state and configuration. Ensure these are properly initialized before calling this function.
 
    .INPUTS
    None. You cannot pipe objects to Start-PSTaskLogging.
 
    .OUTPUTS
    None. This function does not generate any output.
    #>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$LogName,

        [Parameter(Mandatory=$false)]
        [string]$LogPath,

        [Parameter(Mandatory=$false)]
        [string]$LogPathOverride,
        
        [Parameter(Mandatory=$false)]
        [hashtable]$CustomFields
    )

    process {
        if ($script:PSTaskLoggingState.IsLogging) {
            $script:PSTaskLoggingState.ReferenceCount++
            Write-Verbose "Logging already active. Increased reference count to $($script:PSTaskLoggingState.ReferenceCount)"
            return
        }

        # Validate that LogPath and LogPathOverride are not both specified
        if ($LogPath -and $LogPathOverride) {
            throw "Cannot specify both LogPath and LogPathOverride parameters. Use LogPathOverride to specify the complete file path, or LogPath to specify only the directory."
        }

        # Use LogPathOverride if specified, otherwise use the existing logic
        if ($LogPathOverride) {
            $LogPath = $LogPathOverride
        }
        else {
            $newLogName = Get-PSTaskLogFileName -LogName $LogName

            if ((-not $LogPath) -and ($script:Config.Logging.DefaultLogPath)) {
                $LogPath = Join-Path $script:Config.Logging.DefaultLogPath $newLogName
            }
            elseif (-not $LogPath) {
                $LogPath = Join-Path (Get-Location).Path $newLogName
            }
            else {
                $LogPath = Join-Path $LogPath $newLogName
            }
        }

        $script:PSTaskLoggingState.IsLogging = $true
        $script:PSTaskLoggingState.LogPath = $LogPath
        $script:PSTaskLoggingState.ReferenceCount = 1

        # Collect system information
        $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
        $currentIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $user = $currentIdentity.Name
        $runAsUser = $currentIdentity.Name  # In most cases this is the same unless impersonating
        $machineName = $env:COMPUTERNAME
        $osVersion = [System.Environment]::OSVersion.VersionString
        $hostApp = $Host.Name
        if ($MyInvocation.PSCommandPath) {
            $hostApp = $MyInvocation.PSCommandPath
        } elseif ($Host.Name -eq "ConsoleHost") {
            $hostApp = (Get-Process -Id $PID).Path
        }
        $processId = $PID
        $psVersion = if ($PSVersionTable.PSVersion) { $PSVersionTable.PSVersion.ToString() } else { "N/A" }
        $edition = if ($PSVersionTable.PSEdition) { $PSVersionTable.PSEdition } else { "Desktop" }
        $psCompatibleVersions = if ($PSVersionTable.PSCompatibleVersions) { $PSVersionTable.PSCompatibleVersions -join ", " } else { "N/A" }
        $buildVersion = if ($PSVersionTable.BuildVersion) { $PSVersionTable.BuildVersion.ToString() } else { "N/A" }
        $clrVersion = if ($PSVersionTable.CLRVersion) { $PSVersionTable.CLRVersion.ToString() } else { "N/A" }
        $wsManStackVersion = if ($PSVersionTable.WSManStackVersion) { $PSVersionTable.WSManStackVersion.ToString() } else { "N/A" }
        $psRemotingProtocolVersion = if ($PSVersionTable.PSRemotingProtocolVersion) { $PSVersionTable.PSRemotingProtocolVersion.ToString() } else { "N/A" }
        $serializationVersion = if ($PSVersionTable.SerializationVersion) { $PSVersionTable.SerializationVersion.ToString() } else { "N/A" }

        # Format custom fields if provided
        $customFieldsString = ""
        if ($CustomFields) {
            $customFieldsString = ($CustomFields.GetEnumerator() | ForEach-Object { "$($_.Key): $($_.Value)`n" }) -join ""
        }

        $header = $script:Config.Logging.LogHeaderFormat -f $timestamp, $LogName, $user, $runAsUser, $machineName, $osVersion, $hostApp, $processId, $psVersion, $edition, $psCompatibleVersions, $buildVersion, $clrVersion, $wsManStackVersion, $psRemotingProtocolVersion, $serializationVersion, $customFieldsString
        $header | Out-File -FilePath $LogPath -Append
        Write-Verbose "Logging initialized. Log file: $($script:PSTaskLoggingState.LogPath)"
    }
}