EnhancedLoggingAO.psm1

#Region '.\Private\AppendCSVLog.ps1' -1

#Unique Tracking ID: 737397f0-c74e-4087-9b99-279b520b7448, Timestamp: 2024-03-20 12:25:26
function AppendCSVLog {
    param (
        [string]$Message,
        [string]$CSVFilePath_1001
           
    )
    
    $csvData = [PSCustomObject]@{
        TimeStamp    = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
        ComputerName = $env:COMPUTERNAME
        Message      = $Message
    }
    
    $csvData | Export-Csv -Path $CSVFilePath_1001 -Append -NoTypeInformation -Force
}
#EndRegion '.\Private\AppendCSVLog.ps1' 17
#Region '.\Private\CreateEventSourceAndLog.ps1' -1

#Unique Tracking ID: 4362313d-3c19-4d0c-933d-99438a6da297, Timestamp: 2024-03-20 12:25:26

function CreateEventSourceAndLog {
    param (
        [string]$LogName,
        [string]$EventSource
    )
    
    
    # Validate parameters
    if (-not $LogName) {
        Write-Warning "LogName is required."
        return
    }
    if (-not $EventSource) {
        Write-Warning "Source is required."
        return
    }
    
    # Function to create event log and source
    function CreateEventLogSource($logName, $EventSource) {
        try {
            if ($PSVersionTable.PSVersion.Major -lt 6) {
                New-EventLog -LogName $logName -Source $EventSource
            }
            else {
                [System.Diagnostics.EventLog]::CreateEventSource($EventSource, $logName)
            }
            Write-Host "Event source '$EventSource' created in log '$logName'" -ForegroundColor Green
        }
        catch {
            Write-Warning "Error creating the event log. Make sure you run PowerShell as an Administrator."
        }
    }
    
    # Check if the event log exists
    if (-not (Get-WinEvent -ListLog $LogName -ErrorAction SilentlyContinue)) {
        # CreateEventLogSource $LogName $EventSource
    }
    # Check if the event source exists
    elseif (-not ([System.Diagnostics.EventLog]::SourceExists($EventSource))) {
        # Unregister the source if it's registered with a different log
        $existingLogName = (Get-WinEvent -ListLog * | Where-Object { $_.LogName -contains $EventSource }).LogName
        if ($existingLogName -ne $LogName) {
            Remove-EventLog -Source $EventSource -ErrorAction SilentlyContinue
        }
        # CreateEventLogSource $LogName $EventSource
    }
    else {
        Write-Host "Event source '$EventSource' already exists in log '$LogName'" -ForegroundColor Yellow
    }
}
    
# $LogName = (Get-Date -Format "HHmmss") + "_$LoggingDeploymentName"
# $EventSource = (Get-Date -Format "HHmmss") + "_$LoggingDeploymentName"
    
# Call the Create-EventSourceAndLog function
# CreateEventSourceAndLog -LogName $LogName -EventSource $EventSource
    
# Call the Write-CustomEventLog function with custom parameters and level
# Write-CustomEventLog -LogName $LogName -EventSource $EventSource -EventMessage "Outlook Signature Restore completed with warnings." -EventID 1001 -Level 'WARNING'
#EndRegion '.\Private\CreateEventSourceAndLog.ps1' 62
#Region '.\Private\Export-EventLog.ps1' -1

#Unique Tracking ID: c00ecaca-dd4b-4c7c-b80e-566b2f627e32, Timestamp: 2024-03-20 12:25:26
function Export-EventLog {
    param (
        [Parameter(Mandatory = $true)]
        [string]$LogName,
        [Parameter(Mandatory = $true)]
        [string]$ExportPath
    )
    
    try {
        wevtutil epl $LogName $ExportPath
    
        if (Test-Path $ExportPath) {
            Write-EnhancedLog -Message "Event log '$LogName' exported to '$ExportPath'" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
        }
        else {
            Write-EnhancedLog -Message "Event log '$LogName' not exported: File does not exist at '$ExportPath'" -Level "WARNING" -ForegroundColor ([ConsoleColor]::Yellow)
        }
    }
    catch {
        Write-EnhancedLog -Message "Error exporting event log '$LogName': $($_.Exception.Message)" -Level "ERROR" -ForegroundColor ([ConsoleColor]::Red)
    }
}
    
# # Example usage
# $LogName = '$LoggingDeploymentNameLog'
# # $ExportPath = 'Path\to\your\exported\eventlog.evtx'
# $ExportPath = "C:\code\$LoggingDeploymentName\exports\Logs\$logname.evtx"
# Export-EventLog -LogName $LogName -ExportPath $ExportPath
#EndRegion '.\Private\Export-EventLog.ps1' 30
#Region '.\Private\Initialize-CSVDirectory.ps1' -1

function Initialize-CSVDirectory {
    param (
        [string]$deploymentName,
        [string]$computerName
    )

    $isWindowsOS = $false
    if ($PSVersionTable.PSVersion.Major -ge 6) {
        $isWindowsOS = $isWindowsOS -or ($PSVersionTable.Platform -eq 'Win32NT')
    } else {
        $isWindowsOS = $isWindowsOS -or ($env:OS -eq 'Windows_NT')
    }

    $baseScriptPath = if ($isWindowsOS) { "C:\code" } else { "/home/code" }
    $scriptPath_1001 = Join-Path -Path $baseScriptPath -ChildPath $deploymentName
    $CSVDir_1001 = Join-Path -Path $scriptPath_1001 -ChildPath "exports/CSV"
    $CSVFilePath_1001 = Join-Path -Path $CSVDir_1001 -ChildPath "$computerName"

    try {
        if (-not (Test-Path $CSVFilePath_1001)) {
            Write-Host "Did not find CSV directory at $CSVFilePath_1001" -ForegroundColor Yellow
            Write-Host "Creating CSV directory at $CSVFilePath_1001" -ForegroundColor Yellow
            New-Item -ItemType Directory -Path $CSVFilePath_1001 -Force -ErrorAction Stop | Out-Null
            Write-Host "Created CSV directory at $CSVFilePath_1001" -ForegroundColor Green
        }

        return @{
            CSVFilePath = $CSVFilePath_1001
        }
    } catch {
        Write-Host "An error occurred while initializing CSV directory: $_" -ForegroundColor Red
    }
}

# # Example usage of Initialize-CSVDirectory
# try {
# $csvInitResult = Initialize-CSVDirectory -deploymentName "$LoggingDeploymentName" -computerName $env:COMPUTERNAME
# Write-Host "CSV initialization successful. CSV directory path: $($csvInitResult.CSVFilePath)" -ForegroundColor Green
# } catch {
# Write-Host "CSV initialization failed: $_" -ForegroundColor Red
# }
#EndRegion '.\Private\Initialize-CSVDirectory.ps1' 42
#Region '.\Private\Write-EventLogMessage.ps1' -1

#Unique Tracking ID: 132a90f9-6ba2-49cd-878b-279deadb8e22, Timestamp: 2024-03-20 12:25:26

function Write-EventLogMessage {
    param (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$Message,
    
        [string]$LogName = "$LoggingDeploymentName",
        [string]$EventSource,
    
        [int]$EventID = 1000  # Default event ID
    )
    
    $ErrorActionPreference = 'SilentlyContinue'
    $hadError = $false
    
    try {
        if (-not $EventSource) {
            throw "EventSource is required."
        }
    
        if ($PSVersionTable.PSVersion.Major -lt 6) {
            # PowerShell version is less than 6, use Write-EventLog
            Write-EventLog -LogName $logName -Source $EventSource -EntryType Information -EventId $EventID -Message $Message
        }
        else {
            # PowerShell version is 6 or greater, use System.Diagnostics.EventLog
            $eventLog = New-Object System.Diagnostics.EventLog($logName)
            $eventLog.Source = $EventSource
            $eventLog.WriteEntry($Message, [System.Diagnostics.EventLogEntryType]::Information, $EventID)
        }
    
        # Write-Host "Event log entry created: $Message"
    }
    catch {
        Write-Host "Error creating event log entry: $_" 
        $hadError = $true
    }
    
    if (-not $hadError) {
        # Write-Host "Event log message writing completed successfully."
    }
}
    
#EndRegion '.\Private\Write-EventLogMessage.ps1' 46
#Region '.\Public\Add-Step.ps1' -1

function Add-Step {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$Description,

        [Parameter(Mandatory = $true)]
        [ScriptBlock]$Action
    )

    Begin {
        Write-EnhancedLog -Message "Starting Add-Step function" -Level "INFO"
        Log-Params -Params @{
            Description = $Description
            Action = $Action.ToString()
        }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Adding step: $Description" -Level "INFO"
            $global:steps.Add([PSCustomObject]@{ Description = $Description; Action = $Action })
        } catch {
            Write-EnhancedLog -Message "An error occurred while adding step: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Add-Step function" -Level "INFO"
    }
}

# Example usage
# Add-Step -Description "Sample step description" -Action { Write-Output "Sample action" }
#EndRegion '.\Public\Add-Step.ps1' 36
#Region '.\Public\Export-Data.ps1' -1

function Export-Data {
    <#
.SYNOPSIS
Exports data to various formats including CSV, JSON, XML, HTML, PlainText, Excel, PDF, Markdown, and YAML.
 
.DESCRIPTION
The Export-Data function exports provided data to multiple file formats based on switches provided. It supports CSV, JSON, XML, GridView (for display only), HTML, PlainText, Excel, PDF, Markdown, and YAML formats. This function is designed to work with any PSObject.
 
.PARAMETER Data
The data to be exported. This parameter accepts input of type PSObject.
 
.PARAMETER BaseOutputPath
The base path for output files without file extension. This path is used to generate filenames for each export format.
 
.PARAMETER IncludeCSV
Switch to include CSV format in the export.
 
.PARAMETER IncludeJSON
Switch to include JSON format in the export.
 
.PARAMETER IncludeXML
Switch to include XML format in the export.
 
.PARAMETER IncludeGridView
Switch to display the data in a GridView.
 
.PARAMETER IncludeHTML
Switch to include HTML format in the export.
 
.PARAMETER IncludePlainText
Switch to include PlainText format in the export.
 
.PARAMETER IncludePDF
Switch to include PDF format in the export. Requires intermediate HTML to PDF conversion.
 
.PARAMETER IncludeExcel
Switch to include Excel format in the export.
 
.PARAMETER IncludeMarkdown
Switch to include Markdown format in the export. Custom or use a module if available.
 
.PARAMETER IncludeYAML
Switch to include YAML format in the export. Requires 'powershell-yaml' module.
 
.EXAMPLE
PS> $data = Get-Process | Select-Object -First 10
PS> Export-Data -Data $data -BaseOutputPath "C:\exports\mydata" -IncludeCSV -IncludeJSON
 
This example exports the first 10 processes to CSV and JSON formats.
#>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [psobject]$Data,

        [Parameter(Mandatory = $true)]
        [string]$BaseOutputPath,

        [switch]$IncludeCSV,
        [switch]$IncludeJSON,
        [switch]$IncludeXML,
        [switch]$IncludeGridView,
        [switch]$IncludeHTML,
        [switch]$IncludePlainText,
        [switch]$IncludePDF, # Requires intermediate HTML to PDF conversion
        [switch]$IncludeExcel,
        [switch]$IncludeMarkdown, # Custom or use a module if available
        [switch]$IncludeYAML  # Requires 'powershell-yaml' module
    )

    Begin {




        # $modules = @('ImportExcel', 'powershell-yaml' , 'PSWriteHTML')
        # Install-MissingModules -RequiredModules $modules -Verbose


        # Setup the base path without extension
        Write-Host "BaseOutputPath before change: '$BaseOutputPath'"
        $basePathWithoutExtension = [System.IO.Path]::ChangeExtension($BaseOutputPath, $null)

        # Remove extension manually if it exists
        $basePathWithoutExtension = if ($BaseOutputPath -match '\.') {
            $BaseOutputPath.Substring(0, $BaseOutputPath.LastIndexOf('.'))
        }
        else {
            $BaseOutputPath
        }

        # Ensure no trailing periods
        $basePathWithoutExtension = $basePathWithoutExtension.TrimEnd('.')
    }

    Process {
        try {
            if ($IncludeCSV) {
                $csvPath = "$basePathWithoutExtension.csv"
                $Data | Export-Csv -Path $csvPath -NoTypeInformation
            }

            if ($IncludeJSON) {
                $jsonPath = "$basePathWithoutExtension.json"
                $Data | ConvertTo-Json -Depth 10 | Set-Content -Path $jsonPath
            }

            if ($IncludeXML) {
                $xmlPath = "$basePathWithoutExtension.xml"
                $Data | Export-Clixml -Path $xmlPath
            }

            if ($IncludeGridView) {
                $Data | Out-GridView -Title "Data Preview"
            }

            if ($IncludeHTML) {
                # Assumes $Data is the dataset you want to export to HTML
                # and $basePathWithoutExtension is prepared earlier in your script
                
                $htmlPath = "$basePathWithoutExtension.html"
                
                # Convert $Data to HTML using PSWriteHTML
                New-HTML -Title "Data Export Report" -FilePath $htmlPath -ShowHTML {
                    New-HTMLSection -HeaderText "Data Export Details" -Content {
                        New-HTMLTable -DataTable $Data -ScrollX -HideFooter
                    }
                }
            
                Write-Host "HTML report generated: '$htmlPath'"
            }
            

            if ($IncludePlainText) {
                $txtPath = "$basePathWithoutExtension.txt"
                $Data | Out-String | Set-Content -Path $txtPath
            }

            if ($IncludeExcel) {
                $excelPath = "$basePathWithoutExtension.xlsx"
                $Data | Export-Excel -Path $excelPath
            }

            # Assuming $Data holds the objects you want to serialize to YAML
            if ($IncludeYAML) {
                $yamlPath = "$basePathWithoutExtension.yaml"
    
                # Check if the powershell-yaml module is loaded
                if (Get-Module -ListAvailable -Name powershell-yaml) {
                    Import-Module powershell-yaml

                    # Process $Data to handle potentially problematic properties
                    $processedData = $Data | ForEach-Object {
                        $originalObject = $_
                        $properties = $_ | Get-Member -MemberType Properties
                        $clonedObject = New-Object -TypeName PSObject

                        foreach ($prop in $properties) {
                            try {
                                $clonedObject | Add-Member -MemberType NoteProperty -Name $prop.Name -Value $originalObject.$($prop.Name) -ErrorAction Stop
                            }
                            catch {
                                # Optionally handle or log the error. Skipping problematic property.
                                $clonedObject | Add-Member -MemberType NoteProperty -Name $prop.Name -Value "Error serializing property" -ErrorAction SilentlyContinue
                            }
                        }

                        return $clonedObject
                    }

                    # Convert the processed data to YAML and save it with UTF-16 LE encoding
                    $processedData | ConvertTo-Yaml | Set-Content -Path $yamlPath -Encoding Unicode
                    Write-Host "YAML export completed successfully: $yamlPath"
                }
                else {
                    Write-Warning "The 'powershell-yaml' module is not installed. YAML export skipped."
                }
            }

            if ($IncludeMarkdown) {
                # You'll need to implement or find a ConvertTo-Markdown function or use a suitable module
                $markdownPath = "$basePathWithoutExtension.md"
                $Data | ConvertTo-Markdown | Set-Content -Path $markdownPath
            }

            if ($IncludePDF) {
                # Convert HTML to PDF using external tool
                # This is a placeholder for the process. You will need to generate HTML first and then convert it.
                $pdfPath = "$basePathWithoutExtension.pdf"
                # Assuming you have a Convert-HtmlToPdf function or a similar mechanism
                $htmlPath = "$basePathWithoutExtension.html"
                $Data | ConvertTo-Html | Convert-HtmlToPdf -OutputPath $pdfPath
            }

        }
        catch {
            Write-Error "An error occurred during export: $_"
        }
    }

    End {
        Write-Verbose "Export-Data function execution completed."
    }
}
#EndRegion '.\Public\Export-Data.ps1' 206
#Region '.\Public\Get-TranscriptFilePath.ps1' -1

function Get-TranscriptFilePath {
    [CmdletBinding()]
    param (
        [string]$TranscriptsPath = "C:\Logs\Transcript",
        [string]$JobName = "AAD Migration"
    )

    # Ensure the destination directory exists
    if (-not (Test-Path -Path $TranscriptsPath)) {
        New-Item -ItemType Directory -Path $TranscriptsPath -Force
        Write-EnhancedLog -Message "Created Transcripts directory at: $TranscriptsPath" -Level "INFO"
    }

    try {
        # Log the start of the function
        Write-EnhancedLog -Message "Starting Get-TranscriptFilePath function..." -Level "NOTICE"

        # Get the current username
        $username = if ($env:USERNAME) { $env:USERNAME } else { "UnknownUser" }
        Write-EnhancedLog -Message "Current username: $username" -Level "INFO"

        # Get the script name from $MyInvocation
        $scriptName = [System.IO.Path]::GetFileNameWithoutExtension($MyInvocation.ScriptName)
        if (-not $scriptName) {
            $scriptName = "UnknownScript"
        }
        Write-EnhancedLog -Message "Script name: $scriptName" -Level "INFO"

        # Check if running as SYSTEM using Test-RunningAsSystem
        $isSystem = Test-RunningAsSystem
        Write-EnhancedLog -Message "Is running as SYSTEM: $isSystem" -Level "INFO"

        # Get the current date for folder creation
        $currentDate = Get-Date -Format "yyyy-MM-dd"

        $hostname = $env:COMPUTERNAME
        $timestamp = Get-Date -Format "yyyy-MM-dd-HH-mm-ss"
        $logFolderPath = "$TranscriptsPath\$currentDate\$scriptName"

        # Ensure the log directory exists
        if (-not (Test-Path -Path $logFolderPath)) {
            New-Item -Path $logFolderPath -ItemType Directory -Force
            Write-EnhancedLog -Message "Created directory for log file: $logFolderPath" -Level "INFO"
        }

        # Generate log file path based on context
        if ($isSystem) {
            $logFilePath = "$logFolderPath\$hostname-$JobName-SYSTEM-$scriptName-transcript-$timestamp.log"
            Write-EnhancedLog -Message "Generated log file path for SYSTEM: $logFilePath" -Level "INFO"
        }
        else {
            $logFilePath = "$logFolderPath\$hostname-$JobName-$username-$scriptName-transcript-$timestamp.log"
            Write-EnhancedLog -Message "Generated log file path for non-SYSTEM: $logFilePath" -Level "INFO"
        }

        # Convert the logFilePath to a string explicitly
        $logFilePath = [string]$logFilePath

        Write-EnhancedLog -Message "Exiting Get-TranscriptFilePath function" -Level "NOTICE"
        return $logFilePath
    }
    catch {
        Write-EnhancedLog -Message "An error occurred in Get-TranscriptFilePath: $_" -Level "ERROR"
        Handle-Error -ErrorRecord $_
        throw $_  # Re-throw the error after logging it
    }
}
#EndRegion '.\Public\Get-TranscriptFilePath.ps1' 68
#Region '.\Public\Handle-Error.ps1' -1

function Handle-Error {
    param (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.ErrorRecord]$ErrorRecord
    )

    try {
        if ($PSVersionTable.PSVersion.Major -ge 7) {
            $fullErrorDetails = Get-Error -InputObject $ErrorRecord | Out-String
        } else {
            $fullErrorDetails = $ErrorRecord.Exception | Format-List * -Force | Out-String
        }

        Write-EnhancedLog -Message "Exception Message: $($ErrorRecord.Exception.Message)" -Level "ERROR"
        Write-EnhancedLog -Message "Full Exception: $fullErrorDetails" -Level "ERROR"
    } catch {
        # Fallback error handling in case of an unexpected error in the try block
        Write-EnhancedLog -Message "An error occurred while handling another error. Original Exception: $($ErrorRecord.Exception.Message)" -Level "CRITICAL"
        Write-EnhancedLog -Message "Handler Exception: $($_.Exception.Message)" -Level "CRITICAL"
        Write-EnhancedLog -Message "Handler Full Exception: $($_ | Out-String)" -Level "CRITICAL"
    }
}

# # Example usage of Handle-Error
# try {
# # Intentionally cause an error for demonstration purposes
# throw "This is a test error"
# } catch {
# Handle-Error -ErrorRecord $_
# }



#EndRegion '.\Public\Handle-Error.ps1' 34
#Region '.\Public\Handle-PSFLogging.ps1' -1

function Handle-PSFLogging {
    [CmdletBinding()]
    param (
        [string]$systemSourcePath = "C:\Windows\System32\config\systemprofile\AppData\Roaming\WindowsPowerShell\PSFramework\Logs\",
        [string]$PSFPath = "C:\Logs\PSF"
    )

    try {
        # Get the current username and script name
        $username = if ($env:USERNAME) { $env:USERNAME } else { "UnknownUser" }
        $scriptName = [System.IO.Path]::GetFileNameWithoutExtension($MyInvocation.ScriptName)
        if (-not $scriptName) {
            $scriptName = "UnknownScript"
        }

        # Get the current date for folder creation
        $currentDate = Get-Date -Format "yyyy-MM-dd"
        $logFolderPath = "$PSFPath\$currentDate\$scriptName"

        # Ensure the destination directory exists
        if (-not (Test-Path -Path $logFolderPath)) {
            New-Item -ItemType Directory -Path $logFolderPath -Force
            Write-EnhancedLog -Message "Created destination directory at $logFolderPath" -Level "INFO"
        }

        # Copy logs from the SYSTEM profile path
        if (Test-Path -Path $systemSourcePath) {
            try {
                Copy-Item -Path "$systemSourcePath*" -Destination $logFolderPath -Recurse -Force -ErrorAction Stop
                Write-EnhancedLog -Message "SYSTEM profile log files successfully copied to $logFolderPath" -Level "INFO"
            }
            catch {
                Write-EnhancedLog -Message "Failed to copy SYSTEM profile logs. Error: $_" -Level "ERROR"
            }
        }
        else {
            Write-EnhancedLog -Message "SYSTEM profile log path not found: $systemSourcePath" -Level "WARNING"
        }

        # Copy logs from the user's profile path
        $userSourcePath = "$env:USERPROFILE\AppData\Roaming\WindowsPowerShell\PSFramework\Logs\"
        if (Test-Path -Path $userSourcePath) {
            try {
                Copy-Item -Path "$userSourcePath*" -Destination $logFolderPath -Recurse -Force -ErrorAction Stop
                Write-EnhancedLog -Message "User profile log files successfully copied to $logFolderPath" -Level "INFO"
            }
            catch {
                Write-EnhancedLog -Message "Failed to copy user profile logs. Error: $_" -Level "ERROR"
            }
        }
        else {
            Write-EnhancedLog -Message "User profile log path not found: $userSourcePath" -Level "WARNING"
        }

        # Verify that the files have been copied
        if (Test-Path -Path $logFolderPath) {
            Write-EnhancedLog -Message "Logs successfully processed to $logFolderPath" -Level "INFO"
        }
        else {
            Write-EnhancedLog -Message "Failed to process log files." -Level "ERROR"
        }

        # Remove logs from the SYSTEM profile path
        if (Test-Path -Path $systemSourcePath) {
            try {
                Remove-Item -Path "$systemSourcePath*" -Recurse -Force -ErrorAction Stop
                Write-EnhancedLog -Message "Logs successfully removed from $systemSourcePath" -Level "INFO"
            }
            catch {
                Write-EnhancedLog -Message "Failed to remove logs. Error: $_" -Level "ERROR"
            }
        }
        else {
            Write-EnhancedLog -Message "Log path not found: $systemSourcePath" -Level "WARNING"
        }

        #Rename SYSTEM logs in PSF to append SYSTEM to easily identify these files as they were generated in the SYSTEM context and their levels are setup to Output instead of Info
        Rename-LogFilesWithUsername -LogDirectoryPath $logFolderPath

        # Remove logs from the user profile path
        # if (Test-Path -Path $userSourcePath) {
        # try {
        # Remove-Item -Path "$userSourcePath*" -Recurse -Force -ErrorAction Stop
        # Write-EnhancedLog -Message "Logs successfully removed from $userSourcePath" -Level "INFO"
        # }
        # catch {
        # Write-EnhancedLog -Message "Failed to remove logs. Error: $_" -Level "ERROR"
        # }
        # }
        # else {
        # Write-EnhancedLog -Message "Log path not found: $userSourcePath" -Level "WARNING"
        # }
    }
    catch {
        Write-EnhancedLog -Message "An error occurred in Handle-PSFLogging: $_" -Level "ERROR"
        Handle-Error -ErrorRecord $_
        throw $_  # Re-throw the error after logging it
    }
}


#usage

# $HandlePSFLoggingParams = @{
# systemSourcePath = "C:\Windows\System32\config\systemprofile\AppData\Roaming\WindowsPowerShell\PSFramework\Logs\"
# PSFPath = "C:\Logs\PSF"
# }

# Handle-PSFLogging @HandlePSFLoggingParams
#EndRegion '.\Public\Handle-PSFLogging.ps1' 110
#Region '.\Public\Initialize-ScriptAndLogging.ps1' -1

$LoggingDeploymentName = $config.LoggingDeploymentName


function Initialize-ScriptAndLogging {
    $isWindowsOS = $false
    if ($PSVersionTable.PSVersion.Major -ge 6) {
        $isWindowsOS = $isWindowsOS -or ($PSVersionTable.Platform -eq 'Win32NT')
    } else {
        $isWindowsOS = $isWindowsOS -or ($env:OS -eq 'Windows_NT')
    }

    $deploymentName = "$LoggingDeploymentName" # Replace this with your actual deployment name
    $baseScriptPath = if ($isWindowsOS) { "C:\code" } else { "/home/code" }
    $scriptPath_1001 = Join-Path -Path $baseScriptPath -ChildPath $deploymentName
    $computerName = if ($isWindowsOS) { $env:COMPUTERNAME } else { (hostname) }

    try {
        if (-not (Test-Path -Path $scriptPath_1001)) {
            New-Item -ItemType Directory -Path $scriptPath_1001 -Force | Out-Null
            Write-Host "Created directory: $scriptPath_1001" -ForegroundColor Green
        }

        $Filename = "$LoggingDeploymentName"
        $logDir = Join-Path -Path $scriptPath_1001 -ChildPath "exports/Logs/$computerName"
        $logPath = Join-Path -Path $logDir -ChildPath "$(Get-Date -Format 'yyyy-MM-dd-HH-mm-ss')"

        if (-not (Test-Path $logPath)) {
            Write-Host "Did not find log directory at $logPath" -ForegroundColor Yellow
            Write-Host "Creating log directory at $logPath" -ForegroundColor Yellow
            New-Item -ItemType Directory -Path $logPath -Force -ErrorAction Stop | Out-Null
            Write-Host "Created log directory at $logPath" -ForegroundColor Green
        }

        $logFile = Join-Path -Path $logPath -ChildPath "$Filename-Transcript.log"
        Start-Transcript -Path $logFile -ErrorAction Stop | Out-Null

        return @{
            ScriptPath  = $scriptPath_1001
            Filename    = $Filename
            LogPath     = $logPath
            LogFile     = $logFile
        }
    } catch {
        Write-Host "An error occurred while initializing script and logging: $_" -ForegroundColor Red
    }
}

# Example usage of Initialize-ScriptAndLogging
# try {
# $initResult = Initialize-ScriptAndLogging
# Write-Host "Initialization successful. Log file path: $($initResult.LogFile)" -ForegroundColor Green
# } catch {
# Write-Host "Initialization failed: $_" -ForegroundColor Red
# }
#EndRegion '.\Public\Initialize-ScriptAndLogging.ps1' 55
#Region '.\Public\Log-And-Execute-Step.ps1' -1

function Log-And-Execute-Step {
    [CmdletBinding()]
    param ()

    Begin {
        Write-EnhancedLog -Message "Starting Log-And-Execute-Step function" -Level "INFO"
    }

    Process {
        try {
            $global:currentStep++
            $totalSteps = $global:steps.Count
            $step = $global:steps[$global:currentStep - 1]
            Write-EnhancedLog -Message "Step [$global:currentStep/$totalSteps]: $($step.Description)" -Level "INFO"
            
            & $step.Action
        } catch {
            Write-EnhancedLog -Message "Error in step: $($step.Description) - $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Log-And-Execute-Step function" -Level "INFO"
    }
}

# Example usage
# Log-And-Execute-Step
#EndRegion '.\Public\Log-And-Execute-Step.ps1' 30
#Region '.\Public\Log-Params.ps1' -1

function Log-Params {
    <#
    .SYNOPSIS
    Logs the provided parameters and their values.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [hashtable]$Params
    )

    Begin {
        # Write-EnhancedLog -Message "Starting Log-Params function" -Level "INFO"
    }

    Process {
        try {
            foreach ($key in $Params.Keys) {
                Write-EnhancedLog -Message "$key $($Params[$key])" -Level "INFO"
            }
        } catch {
            Write-EnhancedLog -Message "An error occurred while logging parameters: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        # Write-EnhancedLog -Message "Exiting Log-Params function" -Level "INFO"
    }
}
#EndRegion '.\Public\Log-Params.ps1' 31
#Region '.\Public\Rename-LogFilesWithUsername.ps1' -1

function Rename-LogFilesWithUsername {
    param (
        [string]$LogDirectoryPath = "C:\Logs\PSF"
    )

    Write-Host "Starting the renaming process for log files in directory: $LogDirectoryPath"

    # Get all log files in the specified directory
    $logFiles = Get-ChildItem -Path $LogDirectoryPath -Filter "*.log"

    if ($logFiles.Count -eq 0) {
        Write-Host "No log files found in the directory." -ForegroundColor Yellow
        return
    }

    Write-Host "Found $($logFiles.Count) log files to process."

    foreach ($logFile in $logFiles) {
        try {
            Write-Host "Processing file: $($logFile.FullName)"

            # Load the log file (assuming it can be imported as CSV for simplicity)
            $logEntries = Import-Csv -Path $logFile.FullName

            # Assume the first entry's username field for demonstration
            $username = $logEntries | Select-Object -First 1 | ForEach-Object { $_.Username }
            if (-not $username) {
                Write-Host "No username found in $($logFile.Name). Skipping file." -ForegroundColor Yellow
                continue
            }
            
            Write-Host "Username found in file: $username"

            # Sanitize the username by removing or replacing invalid characters
            $safeUsername = $username -replace '[\\/:*?"<>|]', '_'
            Write-Host "Sanitized username: $safeUsername"

            # Generate the new file name by appending the sanitized username
            $originalFileName = [System.IO.Path]::GetFileNameWithoutExtension($logFile.FullName)
            $fileExtension = [System.IO.Path]::GetExtension($logFile.FullName)
            $newFileName = "$originalFileName-$safeUsername$fileExtension"
            $newFilePath = [System.IO.Path]::Combine($logFile.DirectoryName, $newFileName)
            Write-Host "Attempting to rename to: $newFilePath"

            # Perform the rename operation
            Rename-Item -Path $logFile.FullName -NewName $newFileName -Force
            Write-Host "Successfully renamed $($logFile.FullName) to $newFileName" -ForegroundColor Green
        }
        catch {
            Write-Host "Failed to process $($logFile.FullName): $_" -ForegroundColor Red
            Write-Host "Possible cause: The file name or path may contain invalid characters or the file might be in use."
        }
    }

    Write-Host "Finished processing all log files."
}

# Run the function on the specified directory
# Rename-LogFilesWithUsername -LogDirectoryPath "C:\Logs\PSF"
#EndRegion '.\Public\Rename-LogFilesWithUsername.ps1' 60
#Region '.\Public\Write-EnhancedLog.ps1' -1

function Write-EnhancedLog {
    param (
        [string]$Message,
        [string]$Level = 'INFO'
    )

    # Get the PowerShell call stack to determine the actual calling function
    $callStack = Get-PSCallStack
    $callerFunction = if ($callStack.Count -ge 2) { $callStack[1].Command } else { '<Unknown>' }

    # Prepare the formatted message with the actual calling function information
    $formattedMessage = "[$Level] $Message"

    # Map custom levels to PSFramework levels
    $psfLevel = switch ($Level.ToUpper()) {
        'DEBUG'           { 'Debug' }
        'INFO'            { 'Host' }
        'NOTICE'          { 'Important' }
        'WARNING'         { 'Warning' }
        'ERROR'           { 'Error' }
        'CRITICAL'        { 'Critical' }
        'IMPORTANT'       { 'Important' }
        'OUTPUT'          { 'Output' }
        'SIGNIFICANT'     { 'Significant' }
        'VERYVERBOSE'     { 'VeryVerbose' }
        'VERBOSE'         { 'Verbose' }
        'SOMEWHATVERBOSE' { 'SomewhatVerbose' }
        'SYSTEM'          { 'System' }
        'INTERNALCOMMENT' { 'InternalComment' }
        default           { 'Host' }
    }

    # Log the message using PSFramework with the actual calling function name
    Write-PSFMessage -Level $psfLevel -Message $formattedMessage -FunctionName $callerFunction
}
#EndRegion '.\Public\Write-EnhancedLog.ps1' 36