EnhancedSchedTaskAO.psm1

#Region '.\Private\Download-PsExec.ps1' -1

function Download-PsExec {
    [CmdletBinding()]
    param(
        [string]$TargetFolder
    )

    Begin {
        # Ensure the target folder exists
        Ensure-TargetFolderExists -TargetFolder $TargetFolder
        Write-EnhancedLog -Message "Removing existing PsExec from target folder: $TargetFolder" -Level "INFO"

        Remove-ExistingPsExec -TargetFolder $TargetFolder
    }

    Process {
        try {
            

            # Define the URL for PsExec download
            $url = "https://download.sysinternals.com/files/PSTools.zip"
            # Full path for the downloaded file
            $zipPath = Join-Path -Path $TargetFolder -ChildPath "PSTools.zip"

            # Download the PSTools.zip file containing PsExec
            Write-EnhancedLog -Message "Downloading PSTools.zip from: $url to: $zipPath" -Level "INFO"
            Invoke-WebRequest -Uri $url -OutFile $zipPath

            # Extract PsExec64.exe from the zip file
            Write-EnhancedLog -Message "Extracting PSTools.zip to: $TargetFolder\PStools" -Level "INFO"
            Expand-Archive -Path $zipPath -DestinationPath "$TargetFolder\PStools" -Force

            # Specific extraction of PsExec64.exe
            $extractedFolderPath = Join-Path -Path $TargetFolder -ChildPath "PSTools"
            $PsExec64Path = Join-Path -Path $extractedFolderPath -ChildPath "PsExec64.exe"
            $finalPath = Join-Path -Path $TargetFolder -ChildPath "PsExec64.exe"

            # Move PsExec64.exe to the desired location
            if (Test-Path -Path $PsExec64Path) {
                Write-EnhancedLog -Message "Moving PsExec64.exe from: $PsExec64Path to: $finalPath" -Level "INFO"
                Move-Item -Path $PsExec64Path -Destination $finalPath

                # Remove the downloaded zip file and extracted folder
                Write-EnhancedLog -Message "Removing downloaded zip file and extracted folder" -Level "INFO"
                Remove-Item -Path $zipPath -Force
                Remove-Item -Path $extractedFolderPath -Recurse -Force

                Write-EnhancedLog -Message "PsExec64.exe has been successfully downloaded and moved to: $finalPath" -Level "INFO"
            } else {
                Write-EnhancedLog -Message "PsExec64.exe not found in the extracted files." -Level "ERROR"
            }
        } catch {
            # Handle any errors during the process
            Write-EnhancedLog -Message "An error occurred during the download or extraction process: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }
}
#EndRegion '.\Private\Download-PsExec.ps1' 58
#Region '.\Private\Ensure-TargetFolderExists.ps1' -1

function Ensure-TargetFolderExists {
    param (
        [string]$TargetFolder
    )
    
    try {
        if (-Not (Test-Path -Path $TargetFolder)) {
            Write-EnhancedLog -Message "Target folder does not exist. Creating folder: $TargetFolder" -Level "INFO" -ForegroundColor ([ConsoleColor]::Cyan)
            New-Item -Path $TargetFolder -ItemType Directory -Force
            Write-EnhancedLog -Message "Target folder created: $TargetFolder" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
        } else {
            Write-EnhancedLog -Message "Target folder already exists: $TargetFolder" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
        }
    } catch {
        Write-EnhancedLog -Message "An error occurred while ensuring the target folder exists: $($_.Exception.Message)" -Level "ERROR" -ForegroundColor ([ConsoleColor]::Red)
        Handle-Error -ErrorRecord $_
    }
}
#EndRegion '.\Private\Ensure-TargetFolderExists.ps1' 19
#Region '.\Private\MyRegisterScheduledTask.ps1' -1


# function MyRegisterScheduledTask {


# <#
# .SYNOPSIS
# Registers a scheduled task with the system.

# .DESCRIPTION
# This function creates a new scheduled task with the specified parameters, including the name, description, VBScript path, and PowerShell script path. It sets up a basic daily trigger and runs the task as the SYSTEM account with the highest privileges. Enhanced logging is used for status messages and error handling to manage potential issues.

# .PARAMETER schtaskName
# The name of the scheduled task to register.

# .PARAMETER schtaskDescription
# A description for the scheduled task.

# .PARAMETER Path_vbs
# The path to the VBScript file used to run the PowerShell script.

# .PARAMETER Path_PSscript
# The path to the PowerShell script to execute.

# .EXAMPLE
# MyRegisterScheduledTask -schtaskName "MyTask" -schtaskDescription "Performs automated checks" -Path_vbs "C:\Scripts\run-hidden.vbs" -Path_PSscript "C:\Scripts\myScript.ps1"

# This example registers a new scheduled task named "MyTask" that executes "myScript.ps1" using "run-hidden.vbs".
# #>

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

# [Parameter(Mandatory = $true)]
# [string]$schtaskDescription,

# [Parameter(Mandatory = $true)]
# # [ValidateScript({Test-Path $_ -File})]
# [string]$Path_vbs,

# [Parameter(Mandatory = $true)]
# # [ValidateScript({Test-Path $_ -File})]
# [string]$Path_PSscript,

# [Parameter(Mandatory = $true)]
# # [ValidateScript({Test-Path $_ -File})]
# [string]$PackageExecutionContext
# )

# try {
# Write-EnhancedLog -Message "Registering scheduled task: $schtaskName" -Level "INFO" -ForegroundColor Magenta

# $startTime = (Get-Date).AddMinutes(1).ToString("HH:mm")

        
# # $action = New-ScheduledTaskAction -Execute "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Argument "`"$Path_vbs`" `"$Path_PSscript`""
# # $argList = "-NoExit -ExecutionPolicy Bypass -File"
# # $action = New-ScheduledTaskAction -Execute "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Argument "`"$argList`" `"$Path_PSscript`""



# # Define the path to the PowerShell script
# # $Path_PSscript = "C:\Path\To\Your\Script.ps1"

# # Define the arguments for the PowerShell executable
# # $argList = "-NoExit -ExecutionPolicy Bypass -File `"$Path_PSscript`""

# # # Create the scheduled task action
# # $action = New-ScheduledTaskAction -Execute "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Argument $argList








# # # Load the configuration from config.json
# # $configPath = Join-Path -Path $PSScriptRoot -ChildPath "config.json"
# # $config = Get-Content -Path $configPath -Raw | ConvertFrom-Json

# # # Define the principal for the task
# # $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
# # Write-EnhancedLog -Message "Principal for the task defined." -Level "INFO"

# # Define the action based on the provided options in the config.json
# if ($config.UsePSADT) {
# Write-EnhancedLog -Message "setting up Schedule Task action for Service UI and PSADT" -Level "INFO" -ForegroundColor Magenta

# # Define the path to the PowerShell Application Deployment Toolkit executable
# # $ToolkitExecutable = "$PSScriptRoot\Private\PSAppDeployToolkit\Toolkit\Deploy-Application.exe"
# $ToolkitExecutable = "$Path_PR\Private\PSAppDeployToolkit\Toolkit\Deploy-Application.exe"

# # Define the path to the ServiceUI executable
# # $ServiceUIExecutable = "$PSScriptRoot\Private\ServiceUI.exe"
# $ServiceUIExecutable = "$Path_PR\Private\ServiceUI.exe"

# # Define the deployment type
# $DeploymentType = "install"

# # Define the arguments for ServiceUI.exe
# $argList = "-process:explorer.exe `"$ToolkitExecutable`" -DeploymentType $DeploymentType"

# # Create the scheduled task action
# $action = New-ScheduledTaskAction -Execute $ServiceUIExecutable -Argument $argList
# }
# else {
# Write-EnhancedLog -Message "Setting up Scheduled Task action for wscript and VBS" -Level "INFO" -ForegroundColor Magenta

# # Define the arguments for wscript.exe
# $argList = "`"$Path_vbs`" `"$Path_PSscript`""

# # Create the scheduled task action for wscript and VBS
# $action = New-ScheduledTaskAction -Execute "C:\Windows\System32\wscript.exe" -Argument $argList
# }


# # Write-EnhancedLog -Message "Scheduled Task '$($config.TaskName)' created successfully." -Level "INFO"

        


















# #option 1 - NO PSADT but rather Wscript and VBS

# # $action = New-ScheduledTaskAction -Execute "C:\Windows\System32\wscript.exe" -Argument "`"$Path_vbs`" `"$Path_PSscript`""




# # #option 2 - ServiceUI calling PSADT in the SYSTEM context
# # Write-EnhancedLog -Message "setting up Schedule Task action for Service UI and PSADT" -Level "INFO" -ForegroundColor Magenta

# # # Define the path to the PowerShell Application Deployment Toolkit executable
# # # $ToolkitExecutable = "$PSScriptRoot\Private\PSAppDeployToolkit\Toolkit\Deploy-Application.exe"
# # $ToolkitExecutable = "$Path_PR\Private\PSAppDeployToolkit\Toolkit\Deploy-Application.exe"

# # # Define the path to the ServiceUI executable
# # # $ServiceUIExecutable = "$PSScriptRoot\Private\ServiceUI.exe"
# # $ServiceUIExecutable = "$Path_PR\Private\ServiceUI.exe"

# # # Define the deployment type
# # $DeploymentType = "install"

# # # Define the arguments for ServiceUI.exe
# # $argList = "-process:explorer.exe `"$ToolkitExecutable`" -DeploymentType $DeploymentType"

# # # Create the scheduled task action
# # $action = New-ScheduledTaskAction -Execute $ServiceUIExecutable -Argument $argList



# #option 1: Trigger - Daily Frequency

# # $trigger = New-ScheduledTaskTrigger -Daily -At $startTime

# #option 2: Trigger On logon of user defaultuser0 (OOBE)




# # Load the configuration from config.json
# # $configPath = Join-Path -Path $PSScriptRoot -ChildPath "config.json"
# # $config = Get-Content -Path $configPath -Raw | ConvertFrom-Json

# # Define the trigger based on the TriggerType
# if ($config.TriggerType -eq "Daily") {
# $trigger = New-ScheduledTaskTrigger -Daily -At $startTime
# Write-EnhancedLog -Message "Trigger set to Daily at $startTime" -Level "INFO"
# }
# elseif ($config.TriggerType -eq "Logon") {
# if (-not $config.LogonUserId) {
# throw "LogonUserId must be specified for Logon trigger type."
# }
# # $trigger = New-ScheduledTaskTrigger -AtLogOn -User $config.LogonUserId
# $trigger = New-ScheduledTaskTrigger -AtLogOn
# Write-EnhancedLog -Message "Trigger set to logon of user $($config.LogonUserId)" -Level "INFO"
# }
# else {
# throw "Invalid TriggerType specified in the configuration."
# }

# $principal = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest

# # $task = Register-ScheduledTask -TaskName $schtaskName -Action $action -Trigger $trigger -Principal $principal -Description $schtaskDescription -Force


  

# # Check if the task should run on demand (Zero triggers defined)
# if ($config.RunOnDemand -eq $true) {
# Write-EnhancedLog -Message "calling Register-ScheduledTask with RunOnDemand set to $($config.RunOnDemand)"
# # Task to run on demand; no trigger defined
# $task = Register-ScheduledTask -TaskName $schtaskName -Action $action -Principal $principal -Description $schtaskDescription -Force

# $task = Get-ScheduledTask -TaskName $schtaskName
# }
# else {
# # Define your trigger here
# Write-EnhancedLog -Message "calling Register-ScheduledTask with RunOnDemand set to $($config.RunOnDemand)"
# $task = Register-ScheduledTask -TaskName $schtaskName -Action $action -Trigger $trigger -Principal $principal -Description $schtaskDescription -Force
# # $DBG

# Write-EnhancedLog -Message "calling Register-ScheduledTask done"

# Write-EnhancedLog -Message "calling Get-ScheduledTask"
# $task = Get-ScheduledTask -TaskName $schtaskName
# Write-EnhancedLog -Message "calling Get-ScheduledTask done"
            
# $task.Triggers[0].Repetition.Interval = $RepetitionInterval
# $task | Set-ScheduledTask
# }



# # Updating the task to include repetition with a 5-minute interval
        

# # Check the execution context specified in the config
# if ($PackageExecutionContext -eq "User") {
# # This code block will only execute if ExecutionContext is set to "User"

# # Connect to the Task Scheduler service
# $ShedService = New-Object -ComObject 'Schedule.Service'
# $ShedService.Connect()

# # Get the folder where the task is stored (root folder in this case)
# $taskFolder = $ShedService.GetFolder("\")
    
# # Get the existing task by name
# $Task = $taskFolder.GetTask("$schtaskName")

# # Update the task with a new definition
# $taskFolder.RegisterTaskDefinition("$schtaskName", $Task.Definition, 6, 'Users', $null, 4) # 6 is TASK_CREATE_OR_UPDATE
# }
# else {
# Write-Host "Execution context is not set to 'User', skipping this block."
# }



# Write-EnhancedLog -Message "Scheduled task $schtaskName registered successfully." -Level "INFO" -ForegroundColor Green
# }
# catch {
# Write-EnhancedLog -Message "An error occurred while registering the scheduled task: $_" -Level "ERROR" -ForegroundColor Red
# throw $_
# }
# }
#EndRegion '.\Private\MyRegisterScheduledTask.ps1' 265
#Region '.\Private\SetupNewTaskEnvironment.ps1' -1

# function SetupNewTaskEnvironment {
# <#
# .SYNOPSIS
# Sets up a new task environment for scheduled task execution.

# .DESCRIPTION
# This function prepares the environment for a new scheduled task. It creates a specified directory, determines the PowerShell script path based on the script mode, generates a VBScript to run the PowerShell script hidden, and finally registers the scheduled task with the provided parameters. It utilizes enhanced logging for feedback and error handling to manage potential issues.

# .PARAMETER Path_PR
# The path where the task's scripts and support files will be stored.

# .PARAMETER schtaskName
# The name of the scheduled task to be created.

# .PARAMETER schtaskDescription
# A description for the scheduled task.

# .PARAMETER ScriptMode
# Determines the script type to be executed ("Remediation" or "PackageName").

# .PARAMETER PackageExecutionContext
# The context in which the package should execute.

# .PARAMETER RepetitionInterval
# The interval at which the task should repeat.

# .PARAMETER Path_VBShiddenPS
# The path to the VBScript file that runs the PowerShell script hidden.

# .EXAMPLE
# SetupNewTaskEnvironment -Path_PR "C:\Tasks\MyTask" -schtaskName "MyScheduledTask" -schtaskDescription "This task does something important" -ScriptMode "Remediation" -PackageExecutionContext "User" -RepetitionInterval "PT1H" -Path_VBShiddenPS "C:\Tasks\MyTask\run-ps-hidden.vbs"

# This example sets up the environment for a scheduled task named "MyScheduledTask" with a specific description, intended for remediation purposes.
# #>

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

# [Parameter(Mandatory = $true)]
# [string]$schtaskName,

# [Parameter(Mandatory = $true)]
# [string]$schtaskDescription,

# [Parameter(Mandatory = $true)]
# [ValidateSet("Remediation", "PackageName")]
# [string]$ScriptMode,

# [Parameter(Mandatory = $true)]
# [string]$PackageExecutionContext,

# [Parameter(Mandatory = $true)]
# [string]$RepetitionInterval,

# [Parameter(Mandatory = $true)]
# [string]$Path_VBShiddenPS
# )

# begin {
# Write-EnhancedLog -Message 'Starting SetupNewTaskEnvironment function' -Level 'INFO'
# Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters
# }

# process {
# try {
# Write-EnhancedLog -Message "Setting up new task environment at $Path_PR." -Level "INFO" -ForegroundColor Cyan

# # Determine the PowerShell script path based on ScriptMode
# $Path_PSscript = switch ($ScriptMode) {
# "Remediation" { Join-Path $Path_PR "remediation.ps1" }
# "PackageName" { Join-Path $Path_PR "$PackageName.ps1" }
# Default { throw "Invalid ScriptMode: $ScriptMode. Expected 'Remediation' or 'PackageName'." }
# }

# $scheduledTaskParams = @{
# schtaskName = $schtaskName
# schtaskDescription = $schtaskDescription
# Path_vbs = $Path_VBShiddenPS
# Path_PSscript = $Path_PSscript
# PackageExecutionContext = $PackageExecutionContext
# RepetitionInterval = $RepetitionInterval
# }

# Log-Params -Params $scheduledTaskParams

# MyRegisterScheduledTask @scheduledTaskParams

# Write-EnhancedLog -Message "Scheduled task $schtaskName with description '$schtaskDescription' registered successfully." -Level "INFO"
# } catch {
# Write-EnhancedLog -Message "An error occurred during setup of new task environment: $_" -Level "ERROR"
# Handle-Error -ErrorRecord $_
# }
# }

# end {
# Write-EnhancedLog -Message 'SetupNewTaskEnvironment function completed' -Level 'INFO'
# }
# }
#EndRegion '.\Private\SetupNewTaskEnvironment.ps1' 101
#Region '.\Public\Check-ExistingTask.ps1' -1

function Check-ExistingTask {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$taskName
    )

    Begin {
        Write-EnhancedLog -Message "Starting Check-ExistingTask function" -Level "INFO"
        Log-Params -Params @{ taskName = $taskName }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Checking for existing scheduled task: $taskName" -Level "INFO" -ForegroundColor Magenta
            $tasks = Get-ScheduledTask -ErrorAction SilentlyContinue | Where-Object { $_.TaskName -eq $taskName }

            if ($tasks.Count -eq 0) {
                Write-EnhancedLog -Message "No existing task named $taskName found." -Level "INFO" -ForegroundColor Yellow
                return $false
            }

            Write-EnhancedLog -Message "Task named $taskName found." -Level "INFO" -ForegroundColor Green
            return $true
        } catch {
            Write-EnhancedLog -Message "An error occurred while checking for the scheduled task: $($_.Exception.Message)" -Level "ERROR" -ForegroundColor Red
            Handle-Error -ErrorRecord $_
            throw $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Check-ExistingTask function" -Level "INFO"
    }
}

# # Example usage:
# $taskExists = Check-ExistingTask -taskName "AADM Launch PSADT for Interactive Migration"
# Write-Output "Task exists: $taskExists"
#EndRegion '.\Public\Check-ExistingTask.ps1' 40
#Region '.\Public\CheckAndElevate.ps1' -1

function CheckAndElevate {
    <#
    .SYNOPSIS
    Elevates the script to run with administrative privileges if not already running as an administrator.
 
    .DESCRIPTION
    The CheckAndElevate function checks if the current PowerShell session is running with administrative privileges. If it is not, the function attempts to restart the script with elevated privileges using the 'RunAs' verb. This is useful for scripts that require administrative privileges to perform their tasks.
 
    .EXAMPLE
    CheckAndElevate
 
    Checks the current session for administrative privileges and elevates if necessary.
 
    .NOTES
    This function will cause the script to exit and restart if it is not already running with administrative privileges. Ensure that any state or data required after elevation is managed appropriately.
    #>


    [CmdletBinding()]
    param ()

    Begin {
        Write-EnhancedLog -Message "Starting CheckAndElevate function" -Level "INFO"
        try {
            $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
            $isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

            Write-EnhancedLog -Message "Checking for administrative privileges..." -Level "INFO"
        } catch {
            Write-EnhancedLog -Message "Error determining administrative status: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
            throw $_
        }
    }

    Process {
        if (-not $isAdmin) {
            try {
                Write-EnhancedLog -Message "The script is not running with administrative privileges. Attempting to elevate..." -Level "WARNING"
                
                $arguments = "-NoProfile -ExecutionPolicy Bypass -NoExit -File `"$PSCommandPath`" $args"
                Start-Process PowerShell -Verb RunAs -ArgumentList $arguments

                Write-EnhancedLog -Message "Script re-launched with administrative privileges. Exiting current session." -Level "INFO"
                exit
            } catch {
                Write-EnhancedLog -Message "Failed to elevate privileges: $($_.Exception.Message)" -Level "ERROR"
                Handle-Error -ErrorRecord $_
                throw $_
            }
        } else {
            Write-EnhancedLog -Message "Script is already running with administrative privileges." -Level "INFO"
        }
    }

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

# Example usage
# CheckAndElevate
#EndRegion '.\Public\CheckAndElevate.ps1' 62
#Region '.\Public\CheckAndExecuteTask.ps1' -1

function CheckAndExecuteTask {
    <#
    .SYNOPSIS
    Checks for an existing scheduled task and executes tasks based on conditions.
 
    .DESCRIPTION
    This function checks if a scheduled task with the specified name and version exists. If it does, it proceeds to execute detection and remediation scripts. If not, it sets up a new task environment and registers the task. It uses enhanced logging for status messages and error handling to manage potential issues.
 
    .PARAMETER schtaskName
    The name of the scheduled task to check and potentially execute.
 
    .PARAMETER Version
    The version of the task to check for. This is used to verify if the correct task version is already scheduled.
 
    .PARAMETER Path_PR
    The path to the directory containing the detection and remediation scripts, used if the task needs to be executed.
 
    .PARAMETER ScriptMode
    The mode in which the script should run.
 
    .PARAMETER PackageExecutionContext
    The context in which the package should execute.
 
    .PARAMETER schtaskDescription
    The description of the scheduled task.
 
    .EXAMPLE
    CheckAndExecuteTask -schtaskName "MyScheduledTask" -Version 1 -Path_PR "C:\Tasks\MyTask"
 
    This example checks for an existing scheduled task named "MyScheduledTask" of version 1. If it exists, it executes the associated tasks; otherwise, it sets up a new environment and registers the task.
    #>


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

        # [Parameter(Mandatory = $true)]
        # [int]$Version,

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

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

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

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


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

        [Parameter(Mandatory = $true)]
        [string]$Path_VBShiddenPS
    )

    begin {
        Write-EnhancedLog -Message 'Starting CheckAndExecuteTask function' -Level 'INFO'
        Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters
    }

    process {
        try {
            Write-EnhancedLog -Message "Checking for existing task: $schtaskName" -Level "INFO"

            $checkParams = @{
                taskName = $schtaskName
                # version = $Version
            }
            $taskExists = Check-ExistingTask @checkParams

            if ($taskExists) {
                Write-EnhancedLog -Message "Existing task found. Executing detection and remediation scripts." -Level "INFO"
                $executeParams = @{
                    Path_PR = $Path_PR
                }
                Execute-DetectionAndRemediation @executeParams
            }
            else {
                Write-EnhancedLog -Message "No existing task found. Setting up new task environment." -Level "INFO"
                $setupParams = @{
                    Path_PR                 = $Path_PR
                    schtaskName             = $schtaskName
                    schtaskDescription      = $schtaskDescription
                    ScriptMode              = $ScriptMode
                    PackageExecutionContext = $PackageExecutionContext
                    RepetitionInterval      = $RepetitionInterval
                    Path_VBShiddenPS        = $Path_VBShiddenPS
                }
                SetupNewTaskEnvironment @setupParams
            }
        }
        catch {
            Write-EnhancedLog -Message "An error occurred while checking and executing the task: $_" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    end {
        Write-EnhancedLog -Message 'CheckAndExecuteTask function completed' -Level 'INFO'
    }
}




# # Example usage of CheckAndExecuteTask function with splatting
# $params = @{
# schtaskName = "MyScheduledTask"
# Version = 1
# Path_PR = "C:\Tasks\MyTask"
# ScriptMode = "Normal"
# PackageExecutionContext = "User"
# schtaskDescription = "This is a scheduled task for MyTask"
# }

# # Call the CheckAndExecuteTask function using splatting
# CheckAndExecuteTask @params

#EndRegion '.\Public\CheckAndExecuteTask.ps1' 124
#Region '.\Public\Copy-FilesToPath.ps1' -1

function Copy-FilesToPath {
    <#
.SYNOPSIS
Copies all files and folders in the specified source directory to the specified destination path.
 
.DESCRIPTION
This function copies all files and folders located in the specified source directory to the specified destination path. It can be used to bundle necessary files and folders with the script for distribution or deployment.
 
.PARAMETER SourcePath
The source path from where the files and folders will be copied.
 
.PARAMETER DestinationPath
The destination path where the files and folders will be copied.
 
.EXAMPLE
Copy-FilesToPath -SourcePath "C:\Source" -DestinationPath "C:\Temp"
 
This example copies all files and folders in the "C:\Source" directory to the "C:\Temp" directory.
#>

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

        [Parameter(Mandatory = $true)]
        [string]$DestinationPath
    )

    Begin {
        Write-EnhancedLog -Message "Starting the copy process from the Source Path $SourcePath to $DestinationPath" -Level "INFO"
        Log-Params -Params @{
            SourcePath = $SourcePath
            DestinationPath = $DestinationPath
        }

        # Ensure the destination directory exists
        if (-not (Test-Path -Path $DestinationPath)) {
            New-Item -Path $DestinationPath -ItemType Directory | Out-Null
        }
    }

    Process {
        try {
            # Copy all items from the source directory to the destination, including subdirectories
            $copyParams = @{
                Path        = "$SourcePath\*"
                Destination = $DestinationPath
                Recurse     = $true
                Force       = $true
                ErrorAction = "Stop"
            }
            Copy-Item @copyParams

            Write-EnhancedLog -Message "All items copied successfully from the Source Path $SourcePath to $DestinationPath." -Level "INFO"
        } catch {
            Write-EnhancedLog -Message "Error occurred during the copy process: $_" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Copy process completed." -Level "INFO"
    }
}



# # Define parameters for the function
# $sourcePath = "C:\SourceDirectory"
# $destinationPath = "C:\DestinationDirectory"

# # Call the function with the defined parameters
# Copy-FilesToPath -SourcePath $sourcePath -DestinationPath $destinationPath
#EndRegion '.\Public\Copy-FilesToPath.ps1' 74
#Region '.\Public\Create-VBShiddenPS.ps1' -1



function Create-VBShiddenPS {

    <#
.SYNOPSIS
Creates a VBScript file to run a PowerShell script hidden from the user interface.
 
.DESCRIPTION
This function generates a VBScript (.vbs) file designed to execute a PowerShell script without displaying the PowerShell window. It's particularly useful for running background tasks or scripts that do not require user interaction. The path to the PowerShell script is taken as an argument, and the VBScript is created in a specified directory within the global path variable.
 
.EXAMPLE
$Path_VBShiddenPS = Create-VBShiddenPS
 
This example creates the VBScript file and returns its path.
#>



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

        [string]$DataFolder = "Data",

        [string]$FileName = "run-ps-hidden.vbs"
    )

    try {
        # Construct the full path for DataFolder and validate it manually
        $fullDataFolderPath = Join-Path -Path $Path_local -ChildPath $DataFolder
        if (-not (Test-Path -Path $fullDataFolderPath -PathType Container)) {
            throw "DataFolder does not exist or is not a directory: $fullDataFolderPath"
        }

        # Log message about creating VBScript
        Write-EnhancedLog -Message "Creating VBScript to hide PowerShell window..." -Level "INFO" -ForegroundColor Magenta

        $scriptBlock = @"
Dim shell,fso,file
 
Set shell=CreateObject("WScript.Shell")
Set fso=CreateObject("Scripting.FileSystemObject")
 
strPath=WScript.Arguments.Item(0)
 
If fso.FileExists(strPath) Then
    set file=fso.GetFile(strPath)
    strCMD="powershell -nologo -executionpolicy ByPass -command " & Chr(34) & "&{" & file.ShortPath & "}" & Chr(34)
    shell.Run strCMD,0
End If
"@


        # Combine paths to construct the full path for the VBScript
        $folderPath = $fullDataFolderPath
        $Path_VBShiddenPS = Join-Path -Path $folderPath -ChildPath $FileName

        # Write the script block to the VBScript file
        $scriptBlock | Out-File -FilePath (New-Item -Path $Path_VBShiddenPS -Force) -Force

        # Validate the VBScript file creation
        if (Test-Path -Path $Path_VBShiddenPS) {
            Write-EnhancedLog -Message "VBScript created successfully at $Path_VBShiddenPS" -Level "INFO" -ForegroundColor Green
        }
        else {
            throw "Failed to create VBScript at $Path_VBShiddenPS"
        }

        return $Path_VBShiddenPS
    }
    catch {
        Write-EnhancedLog -Message "An error occurred while creating VBScript: $_" -Level "ERROR" -ForegroundColor Red
        throw $_
    }
}
#EndRegion '.\Public\Create-VBShiddenPS.ps1' 76
#Region '.\Public\CreateAndExecuteScheduledTask.ps1' -1

function CreateAndExecuteScheduledTask {
    <#
    .SYNOPSIS
    Creates and executes a scheduled task based on the provided configuration.
 
    .DESCRIPTION
    This function initializes variables, ensures necessary paths exist, copies files, creates a VBScript for hidden execution, and manages the execution of detection and remediation scripts. If the task does not exist, it sets up a new task environment.
 
    .PARAMETER ConfigPath
    The path to the JSON configuration file.
 
    .PARAMETER FileName
    The name of the file to be used for the VBScript.
 
    .EXAMPLE
    CreateAndExecuteScheduledTask -ConfigPath "C:\Tasks\Config.json" -FileName "HiddenScript.vbs"
 
    This example creates and executes a scheduled task based on the provided configuration file and VBScript file name.
    #>


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

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

        [Parameter(Mandatory = $true)]
        [string]$Scriptroot

    )

    begin {
        Write-EnhancedLog -Message 'Starting CreateAndExecuteScheduledTask function' -Level 'INFO'
        Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters
    }

    process {
        try {
            # # Load configuration from JSON file
            # $config = Get-Content -Path $ConfigPath | ConvertFrom-Json

            # Load configuration from PSD1 file
            $config = Import-PowerShellDataFile -Path $ConfigPath

            # # Initialize variables directly from the config
            $PackageName = $config.PackageName
            $PackageUniqueGUID = $config.PackageUniqueGUID
            $Version = $config.Version
            $ScriptMode = $config.ScriptMode
            $PackageExecutionContext = $config.PackageExecutionContext
            $RepetitionInterval = $config.RepetitionInterval
            $DataFolder = $config.DataFolder

            

            # Determine local path based on execution context if not provided
            if (-not $Path_local) {
                if (Test-RunningAsSystem) {
                    $Path_local = "c:\_MEM"
                }
                else {
                    $Path_local = "$ENV:LOCALAPPDATA\_MEM"
                }
            }

            $Path_PR = "$Path_local\Data\$PackageName-$PackageUniqueGUID"
            $schtaskName = "$PackageName - $PackageUniqueGUID"
            $schtaskDescription = "Version $Version"

            # Ensure script paths exist
            if (-not (Test-Path -Path $Path_local)) {
                New-Item -Path $Path_local -ItemType Directory -Force | Out-Null
                Write-EnhancedLog -Message "Created directory: $Path_local" -Level "INFO"
            }

            if (-not (Test-Path -Path $Path_PR)) {
                New-Item -Path $Path_PR -ItemType Directory -Force | Out-Null
                Write-EnhancedLog -Message "Created directory: $Path_PR" -Level "INFO"
            }

            # Copy files to path
            $CopyFilesToPathParams = @{
                SourcePath      = $Scriptroot
                DestinationPath = $Path_PR
            }
            Copy-FilesToPath @CopyFilesToPathParams

            # Verify copy operation
            $VerifyCopyOperationParams = @{
                SourcePath      = $Scriptroot
                DestinationPath = $Path_PR
            }
            Verify-CopyOperation @VerifyCopyOperationParams

            # Ensure the script runs with administrative privileges
            if (-not (IsAdmin)) {
                Write-EnhancedLog -Message "Script requires administrative privileges." -Level "ERROR"
                exit
            }

            # Ensure the Data folder exists
            $DataFolderPath = Join-Path -Path $Path_local -ChildPath $DataFolder
            if (-not (Test-Path -Path $DataFolderPath -PathType Container)) {
                New-Item -ItemType Directory -Path $DataFolderPath -Force | Out-Null
                Write-EnhancedLog -Message "Data folder created at $DataFolderPath" -Level "INFO"
            }

            # Create the VBScript to run PowerShell script hidden
            try {
                $CreateVBShiddenPSParams = @{
                    Path_local = $Path_local
                    DataFolder = $DataFolder
                    FileName   = $FileName
                }
                $Path_VBShiddenPS = Create-VBShiddenPS @CreateVBShiddenPSParams

                # Validation of the VBScript file creation
                if (Test-Path -Path $Path_VBShiddenPS) {
                    Write-EnhancedLog -Message "Validation successful: VBScript file exists at $Path_VBShiddenPS" -Level "INFO"
                }
                else {
                    Write-EnhancedLog -Message "Validation failed: VBScript file does not exist at $Path_VBShiddenPS. Check script execution and permissions." -Level "WARNING"
                }
            }
            catch {
                Write-EnhancedLog -Message "An error occurred while creating VBScript: $_" -Level "ERROR"
            }

            # Check and execute task
            $checkTaskParams = @{
                taskName = $schtaskName
            }

            $taskExists = Check-ExistingTask @checkTaskParams

            if ($taskExists) {
                Write-EnhancedLog -Message "Existing task found. Executing detection and remediation scripts." -Level "INFO"
                
                $executeParams = @{
                    Path_PR = $Path_PR
                }
                

                # Register the scheduled task
                if ($config.ScheduleOnly -eq $true) {
                    Write-EnhancedLog -Message "Registering task with ScheduleOnly set to $($config.ScheduleOnly)" -Level "INFO"
                    # $task = Register-ScheduledTask -TaskName $schtaskName -Action $action -Trigger $trigger -Principal $principal -Description $schtaskDescription -Force
                }
                else {
                    Write-EnhancedLog -Message "Registering task with ScheduleOnly set to $($config.ScheduleOnly)" -Level "INFO"
                    Execute-DetectionAndRemediation @executeParams
                }


               
            }
            else {
                Write-EnhancedLog -Message "No existing task found. Setting up new task environment." -Level "INFO"

                # Setup new task environment
                $Path_PSscript = switch ($ScriptMode) {
                    "Remediation" { Join-Path $Path_PR "remediation.ps1" }
                    "PackageName" { Join-Path $Path_PR "$PackageName.ps1" }
                    Default { throw "Invalid ScriptMode: $ScriptMode. Expected 'Remediation' or 'PackageName'." }
                }

                $scheduledTaskParams = @{
                    schtaskName             = $schtaskName
                    schtaskDescription      = $schtaskDescription
                    Path_vbs                = $Path_VBShiddenPS
                    Path_PSscript           = $Path_PSscript
                    PackageExecutionContext = $PackageExecutionContext
                    RepetitionInterval      = $RepetitionInterval
                }

                MyRegisterScheduledTask @scheduledTaskParams

                Write-EnhancedLog -Message "Scheduled task $schtaskName with description '$schtaskDescription' registered successfully." -Level "INFO"
            }
        }
        catch {
            Write-EnhancedLog -Message "An error occurred: $_" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    end {
        Write-EnhancedLog -Message 'CreateAndExecuteScheduledTask function completed' -Level 'INFO'
    }
}

function MyRegisterScheduledTask {
    param (
        [Parameter(Mandatory = $true)]
        [string]$schtaskName,

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

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

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

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

        [Parameter(Mandatory = $true)]
        [string]$RepetitionInterval
    )

    try {
        Write-EnhancedLog -Message "Registering scheduled task: $schtaskName" -Level "INFO"

        $startTime = (Get-Date).AddMinutes(1).ToString("HH:mm")

        # Define the action based on the provided options in the config.json
        if ($config.UsePSADT) {
            Write-EnhancedLog -Message "Setting up Schedule Task action for Service UI and PSADT" -Level "INFO"

            # Define the path to the PowerShell Application Deployment Toolkit executable
            # $ToolkitExecutable = "$Path_PR\Private\PSAppDeployToolkit\Toolkit\Deploy-Application.exe"
            $ToolkitExecutable = "$Path_PR\Deploy-Application.exe"

            # Define the path to the ServiceUI executable
            # $ServiceUIExecutable = "$Path_PR\Private\ServiceUI.exe"
            $ServiceUIExecutable = "$Path_PR\ServiceUI.exe"

            # Define the deployment type
            $DeploymentType = "install"

            # Define the arguments for ServiceUI.exe
            $argList = "-process:explorer.exe `"$ToolkitExecutable`" -DeploymentType $DeploymentType"

            # Create the scheduled task action
            $action = New-ScheduledTaskAction -Execute $ServiceUIExecutable -Argument $argList
        }
        else {
            Write-EnhancedLog -Message "Setting up Scheduled Task action for wscript and VBS" -Level "INFO"

            # Define the arguments for wscript.exe
            $argList = "`"$Path_vbs`" `"$Path_PSscript`""

            # Create the scheduled task action for wscript and VBS
            $action = New-ScheduledTaskAction -Execute "C:\Windows\System32\wscript.exe" -Argument $argList
        }

        # Define the trigger based on the TriggerType
        if ($config.TriggerType -eq "Daily") {
            $trigger = New-ScheduledTaskTrigger -Daily -At $startTime
            Write-EnhancedLog -Message "Trigger set to Daily at $startTime" -Level "INFO"
        }
        elseif ($config.TriggerType -eq "Logon") {
            if (-not $config.LogonUserId) {
                throw "LogonUserId must be specified for Logon trigger type."
            }
            $trigger = New-ScheduledTaskTrigger -AtLogOn
            Write-EnhancedLog -Message "Trigger set to logon of user $($config.LogonUserId)" -Level "INFO"
        }
        elseif ($config.TriggerType -eq "AtStartup") {
            $trigger = New-ScheduledTaskTrigger AtStartup
            Write-EnhancedLog -Message "Trigger set at startup" -Level "INFO"
        }
        else {
            throw "Invalid TriggerType specified in the configuration."
        }

        $principal = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest

        # Register the scheduled task
        if ($config.RunOnDemand -eq $true) {
            Write-EnhancedLog -Message "Registering task with RunOnDemand set to $($config.RunOnDemand)" -Level "INFO"
            $task = Register-ScheduledTask -TaskName $schtaskName -Action $action -Principal $principal -Description $schtaskDescription -Force
        }
        else {
            Write-EnhancedLog -Message "Registering task with RunOnDemand set to $($config.RunOnDemand)" -Level "INFO"
            $task = Register-ScheduledTask -TaskName $schtaskName -Action $action -Trigger $trigger -Principal $principal -Description $schtaskDescription -Force
        }

        $task = Get-ScheduledTask -TaskName $schtaskName


        if ($config.Repeat -eq $true) {
            Write-EnhancedLog -Message "Registering task with Repeat set to $($config.Repeat)" -Level "INFO"
            $task.Triggers[0].Repetition.Interval = $RepetitionInterval
        }
        else {
            Write-EnhancedLog -Message "Registering task with Repeat set to $($config.Repeat)" -Level "INFO"
        }



        
        $task | Set-ScheduledTask

        if ($PackageExecutionContext -eq "User") {
            $ShedService = New-Object -ComObject 'Schedule.Service'
            $ShedService.Connect()
            $taskFolder = $ShedService.GetFolder("\")
            $Task = $taskFolder.GetTask("$schtaskName")
            $taskFolder.RegisterTaskDefinition("$schtaskName", $Task.Definition, 6, 'Users', $null, 4)
        }

        Write-EnhancedLog -Message "Scheduled task $schtaskName registered successfully." -Level "INFO"
    }
    catch {
        Write-EnhancedLog -Message "An error occurred while registering the scheduled task: $_" -Level "ERROR"
        throw $_
    }
}

# $configPath = Join-Path -Path $Scriptroot -ChildPath "config.json"
# $env:MYMODULE_CONFIG_PATH = $configPath

# # Define parameters for the function
# $taskParams = @{
# ConfigPath = $configPath
# FileName = "HiddenScript.vbs"
# }

# # Call the function with splatted parameters
# CreateAndExecuteScheduledTask @taskParams
#EndRegion '.\Public\CreateAndExecuteScheduledTask.ps1' 326
#Region '.\Public\Download-And-Install-ServiceUI.ps1' -1

function Download-And-Install-ServiceUI {
    [CmdletBinding()]
    param(
        [string]$TargetFolder,
        [string]$DownloadUrl,
        [string]$MsiFileName,
        [string]$InstalledServiceUIPath
    )

    begin {
        Write-EnhancedLog -Message "Starting Download-And-Install-ServiceUI function" -Level "INFO"
        Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters

        try {
            $removeParams = @{
                TargetFolder = $TargetFolder;
                FileName = "ServiceUI.exe"
            }
            Remove-ExistingServiceUI @removeParams
        }
        catch {
            Write-EnhancedLog -Message "Error during Remove-ExistingServiceUI: $_" -Level "ERROR"
            Handle-Error -ErrorRecord $_
            throw $_
        }
    }

    process {
        $msiPath = Join-Path -Path $([System.IO.Path]::GetTempPath()) -ChildPath $MsiFileName
        $finalPath = Join-Path -Path $TargetFolder -ChildPath "ServiceUI.exe"

        try {
            $downloadParams = @{
                Uri     = $DownloadUrl;
                OutFile = $msiPath
            }
            Write-EnhancedLog -Message "Downloading MDT MSI from: $DownloadUrl to: $msiPath" -Level "INFO"
            Invoke-WebRequest @downloadParams

            $installParams = @{
                FilePath     = "msiexec.exe";
                ArgumentList = "/i `"$msiPath`" /quiet /norestart";
                Wait         = $true
            }
            Write-EnhancedLog -Message "Installing MDT MSI from: $msiPath" -Level "INFO"
            Start-Process @installParams

            if (Test-Path -Path $InstalledServiceUIPath) {
                $sourceDir = "`"$(Split-Path -Parent $InstalledServiceUIPath)`""
                $destDir = "`"$TargetFolder`""
                $fileName = "ServiceUI.exe"
                $robocopyCommand = "robocopy.exe $sourceDir $destDir $fileName"
                Write-EnhancedLog -Message "Executing command: $robocopyCommand" -Level "INFO"
                Invoke-Expression $robocopyCommand

                Write-EnhancedLog -Message "ServiceUI.exe has been successfully copied to: $finalPath" -Level "INFO"
            }
            else {
                throw "ServiceUI.exe not found at: $InstalledServiceUIPath"
            }

            $removeMsiParams = @{
                Path  = $msiPath;
                Force = $true
            }
            Write-EnhancedLog -Message "Removing downloaded MSI file: $msiPath" -Level "INFO"
            Remove-Item @removeMsiParams
        }
        catch {
            Write-EnhancedLog -Message "An error occurred: $_" -Level "ERROR"
            Handle-Error -ErrorRecord $_
            throw $_
        }
    }

    end {
        Write-EnhancedLog -Message "Download-And-Install-ServiceUI function execution completed." -Level "INFO"
    }
}

# # Example usage of Download-And-Install-ServiceUI function with splatting
# $params = @{
# TargetFolder = "C:\Path\To\Your\Desired\Folder";
# DownloadUrl = "https://download.microsoft.com/download/3/3/9/339BE62D-B4B8-4956-B58D-73C4685FC492/MicrosoftDeploymentToolkit_x64.msi";
# MsiFileName = "MicrosoftDeploymentToolkit_x64.msi";
# InstalledServiceUIPath = "C:\Program Files\Microsoft Deployment Toolkit\Templates\Distribution\Tools\x64\ServiceUI.exe"
# }
# Download-And-Install-ServiceUI @params
#EndRegion '.\Public\Download-And-Install-ServiceUI.ps1' 89
#Region '.\Public\Download-InstallServiceUI-Archive.ps1' -1

# function Download-InstallServiceUI {
# [CmdletBinding()]
# param(
# [Parameter(Mandatory = $true)]
# # [string]$TargetFolder = "$PSScriptRoot\private",
# [string]$TargetFolder,

# [Parameter(Mandatory = $true)]
# [string]$URL
# )

# Begin {
# Write-EnhancedLog -Message "Starting Download-InstallServiceUI function" -Level "INFO"
# Log-Params -Params @{
# TargetFolder = $TargetFolder
# URL = $URL
# }

# try {
# Remove-ExistingServiceUI -TargetFolder $TargetFolder
# } catch {
# Write-EnhancedLog -Message "Error during Remove-ExistingServiceUI: $($_.Exception.Message)" -Level "ERROR"
# Handle-Error -ErrorRecord $_
# }
# }

# Process {
# # Path for the downloaded MSI file
# $msiPath = Join-Path -Path $([System.IO.Path]::GetTempPath()) -ChildPath "MicrosoftDeploymentToolkit_x64.msi"
# $logPath = Join-Path -Path $([System.IO.Path]::GetTempPath()) -ChildPath "MDT_Install.log"
        
# try {
# # Download the MDT MSI file
# Write-EnhancedLog -Message "Downloading MDT MSI from: $URL to: $msiPath" -Level "INFO"
# Invoke-WebRequest -Uri $URL -OutFile $msiPath

# # Install the MSI silently with logging
# Write-EnhancedLog -Message "Installing MDT MSI from: $msiPath" -Level "INFO"
# CheckAndElevate
# Start-Process -FilePath "msiexec.exe" -ArgumentList "/i `"$msiPath`" /quiet /norestart /l*v `"$logPath`"" -Wait

# # Path to the installed ServiceUI.exe
# $installedServiceUIPath = "C:\Program Files\Microsoft Deployment Toolkit\Templates\Distribution\Tools\x64\ServiceUI.exe"
# $finalPath = Join-Path -Path $TargetFolder -ChildPath "ServiceUI.exe"

# # Ensure the destination directory exists
# if (-not (Test-Path -Path $TargetFolder)) {
# Write-EnhancedLog -Message "Creating target folder: $TargetFolder" -Level "INFO"
# New-Item -ItemType Directory -Path $TargetFolder -Force
# }

# # Move ServiceUI.exe to the desired location
# if (Test-Path -Path $installedServiceUIPath) {
# Write-EnhancedLog -Message "Copying ServiceUI.exe from: $installedServiceUIPath to: $finalPath" -Level "INFO"
# Copy-Item -Path $installedServiceUIPath -Destination $finalPath -Force

# if (Test-Path -Path $finalPath) {
# Write-EnhancedLog -Message "ServiceUI.exe has been successfully copied to: $finalPath" -Level "INFO"
# } else {
# throw "ServiceUI.exe not successfully copied to: $finalPath"
# }
# } else {
# throw "ServiceUI.exe not found at: $installedServiceUIPath"
# }

# # Remove the downloaded MSI file
# Remove-Item -Path $msiPath -Force
# } catch {
# Write-EnhancedLog -Message "An error occurred: $($_.Exception.Message)" -Level "ERROR"
# Handle-Error -ErrorRecord $_
# }
# }

# End {
# Write-EnhancedLog -Message "Exiting Download-InstallServiceUI function" -Level "INFO"
# }
# }

# # Example usage
# # Download-InstallServiceUI -TargetFolder 'C:\YourPath\private' -URL 'https://download.microsoft.com/download/3/3/9/339BE62D-B4B8-4956-B58D-73C4685FC492/MicrosoftDeploymentToolkit_x64.msi'
#EndRegion '.\Public\Download-InstallServiceUI-Archive.ps1' 81
#Region '.\Public\Download-PSAppDeployToolkit.ps1' -1

function Download-PSAppDeployToolkit {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$GithubRepository,

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

        [Parameter(Mandatory = $true)]
        [string]$ScriptDirectory
    )

    begin {
        Write-EnhancedLog -Message "Starting Download-PSAppDeployToolkit function" -Level "INFO"
        Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters

        try {
            # Set the URI to get the latest release information from the GitHub repository
            $psadtReleaseUri = "https://api.github.com/repos/$GithubRepository/releases/latest"
            Write-EnhancedLog -Message "GitHub release URI: $psadtReleaseUri" -Level "INFO"
        }
        catch {
            Write-EnhancedLog -Message "Error in begin block: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
            throw $_
        }
    }

    process {
        try {
            # Fetch the latest release information from GitHub
            Write-EnhancedLog -Message "Fetching the latest release information from GitHub" -Level "INFO"
            $psadtDownloadUri = (Invoke-RestMethod -Method GET -Uri $psadtReleaseUri).assets |
                Where-Object { $_.name -like $FilenamePatternMatch } |
                Select-Object -ExpandProperty browser_download_url

            if (-not $psadtDownloadUri) {
                throw "No matching file found for pattern: $FilenamePatternMatch"
            }
            Write-EnhancedLog -Message "Found matching download URL: $psadtDownloadUri" -Level "INFO"

            # Set the path for the temporary download location
            $zipTempDownloadPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath (Split-Path -Path $psadtDownloadUri -Leaf)
            Write-EnhancedLog -Message "Temporary download path: $zipTempDownloadPath" -Level "INFO"

            # Download the file to the temporary location
            Write-EnhancedLog -Message "Downloading file from $psadtDownloadUri to $zipTempDownloadPath" -Level "INFO"
            Invoke-WebRequest -Uri $psadtDownloadUri -OutFile $zipTempDownloadPath

            # Unblock the downloaded file if necessary
            Write-EnhancedLog -Message "Unblocking file at $zipTempDownloadPath" -Level "INFO"
            Unblock-File -Path $zipTempDownloadPath

            # Set the temporary extraction path
            $tempExtractionPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "PSAppDeployToolkit"
            if (-not (Test-Path $tempExtractionPath)) {
                New-Item -Path $tempExtractionPath -ItemType Directory | Out-Null
            }

            # Extract the contents of the zip file to the temporary extraction path
            Write-EnhancedLog -Message "Extracting file from $zipTempDownloadPath to $tempExtractionPath" -Level "INFO"
            Expand-Archive -Path $zipTempDownloadPath -DestinationPath $tempExtractionPath -Force

            # Use robocopy to copy all files from the temporary extraction folder to the ScriptDirectory, excluding deploy-application.ps1
            Write-EnhancedLog -Message "Copying files from $tempExtractionPath to $ScriptDirectory" -Level "INFO"
            $robocopyArgs = @(
                $tempExtractionPath,
                $ScriptDirectory,
                "/E", # Copies subdirectories, including empty ones.
                "/XF", "deploy-application.ps1"
            )
            $robocopyCommand = "robocopy.exe $($robocopyArgs -join ' ')"
            Write-EnhancedLog -Message "Executing command: $robocopyCommand" -Level "INFO"
            Invoke-Expression $robocopyCommand

            # Copy Deploy-Application.exe from Toolkit to ScriptDirectory
            Write-EnhancedLog -Message "Copying Deploy-Application.exe from Toolkit to $ScriptDirectory" -Level "INFO"
            $deployAppSource = Join-Path -Path $tempExtractionPath -ChildPath "Toolkit"
            $deployAppArgs = @(
                $deployAppSource,
                $ScriptDirectory,
                "Deploy-Application.exe",
                "/COPY:DAT",
                "/R:1",
                "/W:1"
            )
            $deployAppCommand = "robocopy.exe $($deployAppArgs -join ' ')"
            Write-EnhancedLog -Message "Executing command: $deployAppCommand" -Level "INFO"
            Invoke-Expression $deployAppCommand

            Write-EnhancedLog -Message "Files copied successfully to $ScriptDirectory" -Level "INFO"

            # Clean up temporary files
            Write-EnhancedLog -Message "Removing temporary download file: $zipTempDownloadPath" -Level "INFO"
            Remove-Item -Path $zipTempDownloadPath -Force

            Write-EnhancedLog -Message "Removing temporary extraction folder: $tempExtractionPath" -Level "INFO"
            Remove-Item -Path $tempExtractionPath -Recurse -Force
        }
        catch {
            Write-EnhancedLog -Message "Error in process block: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
            throw $_
        }
    }

    end {
        try {
            Write-EnhancedLog -Message "File extracted and copied successfully to $ScriptDirectory" -Level "INFO"
        }
        catch {
            Write-EnhancedLog -Message "Error in end block: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }

        Write-EnhancedLog -Message "Exiting Download-PSAppDeployToolkit function" -Level "INFO"
    }
}

# # Example usage
# $params = @{
# GithubRepository = 'PSAppDeployToolkit/PSAppDeployToolkit';
# FilenamePatternMatch = '*.zip';
# ScriptDirectory = 'C:\YourScriptDirectory'
# }
# Download-PSAppDeployToolkit @params
#EndRegion '.\Public\Download-PSAppDeployToolkit.ps1' 128
#Region '.\Public\Ensure-RunningAsSystem.ps1' -1

function Ensure-RunningAsSystem {
    param (
        [Parameter(Mandatory = $true)]
        [string]$PsExec64Path,
        [Parameter(Mandatory = $true)]
        [string]$ScriptPath,
        [Parameter(Mandatory = $true)]
        [string]$TargetFolder
    )

     Write-EnhancedLog -Message "Calling Test-RunningAsSystem" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
    
    if (-not (Test-RunningAsSystem)) {
        # Check if the target folder exists, and create it if it does not
        if (-not (Test-Path -Path $TargetFolder)) {
            New-Item -Path $TargetFolder -ItemType Directory | Out-Null
        }

        $PsExec64Path = Join-Path -Path $TargetFolder -ChildPath "PsExec64.exe"
        
         Write-EnhancedLog -Message "Current session is not running as SYSTEM. Attempting to invoke as SYSTEM..." -Level "INFO" -ForegroundColor ([ConsoleColor]::Yellow)

        Invoke-AsSystem -PsExec64Path $PsExec64Path -ScriptPath $ScriptPath -TargetFolder $TargetFolder
    }
    else {
         Write-EnhancedLog -Message "Session is already running as SYSTEM." -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
    }
}

# # Example usage
# $privateFolderPath = Join-Path -Path $PSScriptRoot -ChildPath "private"
# $PsExec64Path = Join-Path -Path $privateFolderPath -ChildPath "PsExec64.exe"
# $ScriptToRunAsSystem = $MyInvocation.MyCommand.Path

# Ensure-RunningAsSystem -PsExec64Path $PsExec64Path -ScriptPath $ScriptToRunAsSystem -TargetFolder $privateFolderPath
#EndRegion '.\Public\Ensure-RunningAsSystem.ps1' 36
#Region '.\Public\Ensure-ScriptPathsExist.ps1' -1



function Ensure-ScriptPathsExist {


    <#
.SYNOPSIS
Ensures that all necessary script paths exist, creating them if they do not.
 
.DESCRIPTION
This function checks for the existence of essential script paths and creates them if they are not found. It is designed to be called after initializing script variables to ensure the environment is correctly prepared for the script's operations.
 
.PARAMETER Path_local
The local path where the script's data will be stored. This path varies based on the execution context (system vs. user).
 
.PARAMETER Path_PR
The specific path for storing package-related files, constructed based on the package name and unique GUID.
 
.EXAMPLE
Ensure-ScriptPathsExist -Path_local $global:Path_local -Path_PR $global:Path_PR
 
This example ensures that the paths stored in the global variables $Path_local and $Path_PR exist, creating them if necessary.
#>

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

        [Parameter(Mandatory = $true)]
        [string]$Path_PR
    )

    try {
        # Ensure Path_local exists
        if (-not (Test-Path -Path $Path_local)) {
            New-Item -Path $Path_local -ItemType Directory -Force | Out-Null
            Write-EnhancedLog -Message "Created directory: $Path_local" -Level "INFO" -ForegroundColor ([System.ConsoleColor]::Green)
        }

        # Ensure Path_PR exists
        if (-not (Test-Path -Path $Path_PR)) {
            New-Item -Path $Path_PR -ItemType Directory -Force | Out-Null
            Write-EnhancedLog -Message "Created directory: $Path_PR" -Level "INFO" -ForegroundColor ([System.ConsoleColor]::Green)
        }
    }
    catch {
        Write-EnhancedLog -Message "An error occurred while ensuring script paths exist: $_" -Level "ERROR" -ForegroundColor ([System.ConsoleColor]::Red)
    }
}
#EndRegion '.\Public\Ensure-ScriptPathsExist.ps1' 50
#Region '.\Public\Execute-DetectionAndRemediation.ps1' -1


function Execute-DetectionAndRemediation {

    <#
.SYNOPSIS
Executes detection and remediation scripts located in a specified directory.
 
.DESCRIPTION
This function navigates to the specified directory and executes the detection script. If the detection script exits with a non-zero exit code, indicating a positive detection, the remediation script is then executed. The function uses enhanced logging for status messages and error handling to manage any issues that arise during execution.
 
.PARAMETER Path_PR
The path to the directory containing the detection and remediation scripts.
 
.EXAMPLE
Execute-DetectionAndRemediation -Path_PR "C:\Scripts\MyTask"
This example executes the detection and remediation scripts located in "C:\Scripts\MyTask".
#>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        # [ValidateScript({Test-Path $_ -PathType 'Container'})]
        [string]$Path_PR
    )

    try {
        Write-EnhancedLog -Message "Executing detection and remediation scripts in $Path_PR..." -Level "INFO" -ForegroundColor Magenta
        Set-Location -Path $Path_PR

        # Execution of the detection script
        & .\detection.ps1
        if ($LASTEXITCODE -ne 0) {
            Write-EnhancedLog -Message "Detection positive, remediation starts now." -Level "INFO" -ForegroundColor Green
            & .\remediation.ps1
        }
        else {
            Write-EnhancedLog -Message "Detection negative, no further action needed." -Level "INFO" -ForegroundColor Yellow
        }
    }
    catch {
        Write-EnhancedLog -Message "An error occurred during detection and remediation execution: $_" -Level "ERROR" -ForegroundColor Red
        throw $_
    }
}

#EndRegion '.\Public\Execute-DetectionAndRemediation.ps1' 46
#Region '.\Public\Initialize-ScriptVariables.ps1' -1


function Initialize-ScriptVariables {


    <#
.SYNOPSIS
Initializes global script variables and defines the path for storing related files.
 
.DESCRIPTION
This function initializes global script variables such as PackageName, PackageUniqueGUID, Version, and ScriptMode. Additionally, it constructs the path where related files will be stored based on the provided parameters.
 
.PARAMETER PackageName
The name of the package being processed.
 
.PARAMETER PackageUniqueGUID
The unique identifier for the package being processed.
 
.PARAMETER Version
The version of the package being processed.
 
.PARAMETER ScriptMode
The mode in which the script is being executed (e.g., "Remediation", "PackageName").
 
.EXAMPLE
Initialize-ScriptVariables -PackageName "MyPackage" -PackageUniqueGUID "1234-5678" -Version 1 -ScriptMode "Remediation"
 
This example initializes the script variables with the specified values.
 
#>


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

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

        [Parameter(Mandatory = $true)]
        [int]$Version,

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

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


        [Parameter(Mandatory = $true)]
        [string]$RepetitionInterval
    )

    # Assuming Set-LocalPathBasedOnContext and Test-RunningAsSystem are defined elsewhere
    # $global:Path_local = Set-LocalPathBasedOnContext

    # Default logic for $Path_local if not set by Set-LocalPathBasedOnContext
    if (-not $Path_local) {
        if (Test-RunningAsSystem) {
            # $Path_local = "$ENV:ProgramFiles\_MEM"
            $Path_local = "c:\_MEM"
        }
        else {
            $Path_local = "$ENV:LOCALAPPDATA\_MEM"
        }
    }

    $Path_PR = "$Path_local\Data\$PackageName-$PackageUniqueGUID"
    $schtaskName = "$PackageName - $PackageUniqueGUID"
    $schtaskDescription = "Version $Version"

    try {
        # Assuming Write-EnhancedLog is defined elsewhere
        Write-EnhancedLog -Message "Initializing script variables..." -Level "INFO" -ForegroundColor ([System.ConsoleColor]::Green)

        # Returning a hashtable of all the important variables
        return @{
            PackageName             = $PackageName
            PackageUniqueGUID       = $PackageUniqueGUID
            Version                 = $Version
            ScriptMode              = $ScriptMode
            Path_local              = $Path_local
            Path_PR                 = $Path_PR
            schtaskName             = $schtaskName
            schtaskDescription      = $schtaskDescription
            PackageExecutionContext = $PackageExecutionContext
            RepetitionInterval     = $RepetitionInterval
        }
    }
    catch {
        Write-Error "An error occurred while initializing script variables: $_"
    }
}
#EndRegion '.\Public\Initialize-ScriptVariables.ps1' 93
#Region '.\Public\Invoke-AsSystem.ps1' -1

function Invoke-AsSystem {
    <#
.SYNOPSIS
Executes a PowerShell script under the SYSTEM context, similar to Intune's execution context.
 
.DESCRIPTION
The Invoke-AsSystem function executes a PowerShell script using PsExec64.exe to run under the SYSTEM context. This method is useful for scenarios requiring elevated privileges beyond the current user's capabilities.
 
.PARAMETER PsExec64Path
Specifies the full path to PsExec64.exe. If not provided, it assumes PsExec64.exe is in the same directory as the script.
 
.EXAMPLE
Invoke-AsSystem -PsExec64Path "C:\Tools\PsExec64.exe"
 
Executes PowerShell as SYSTEM using PsExec64.exe located at "C:\Tools\PsExec64.exe".
 
.NOTES
Ensure PsExec64.exe is available and the script has the necessary permissions to execute it.
 
.LINK
https://docs.microsoft.com/en-us/sysinternals/downloads/psexec
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$PsExec64Path,
        [string]$ScriptPathAsSYSTEM,  # Path to the PowerShell script you want to run as SYSTEM
        [string]$TargetFolder  # Path to the PowerShell script you want to run as SYSTEM
    )

    begin {
        CheckAndElevate
        # Define the arguments for PsExec64.exe to run PowerShell as SYSTEM with the script
        $argList = "-accepteula -i -s -d powershell.exe -NoExit -ExecutionPolicy Bypass -File `"$ScriptPathAsSYSTEM`""
        Write-EnhancedLog -Message "Preparing to execute PowerShell as SYSTEM using PsExec64 with the script: $ScriptPathAsSYSTEM" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)

        Log-Params -Params @{PsExec64Path = $PsExec64Path}

        # Download-PsExec -targetFolder $PsExec64Path
        Download-PsExec -targetFolder $TargetFolder
    }

    process {
        try {
            # Ensure PsExec64Path exists
            if (-not (Test-Path -Path $PsExec64Path)) {
                $errorMessage = "PsExec64.exe not found at path: $PsExec64Path"
                Write-EnhancedLog -Message $errorMessage -Level "ERROR" -ForegroundColor ([ConsoleColor]::Red)
                throw $errorMessage
            }

            # Run PsExec64.exe with the defined arguments to execute the script as SYSTEM
            $executingMessage = "Executing PsExec64.exe to start PowerShell as SYSTEM running script: $ScriptPathAsSYSTEM"
            Write-EnhancedLog -Message $executingMessage -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
            Start-Process -FilePath "$PsExec64Path" -ArgumentList $argList -Wait -NoNewWindow
            
            Write-EnhancedLog -Message "SYSTEM session started. Closing elevated session..." -Level "INFO" -ForegroundColor ([ConsoleColor]::Green)
            exit

        }
        catch {
            Write-EnhancedLog -Message "An error occurred: $_" -Level "ERROR" -ForegroundColor ([ConsoleColor]::Red)
        }
    }
}
#EndRegion '.\Public\Invoke-AsSystem.ps1' 66
#Region '.\Public\Remove-ExistingPsExec.ps1' -1


function Remove-ExistingPsExec {
    [CmdletBinding()]
    param(
        # [string]$TargetFolder = "$PSScriptRoot\private"
        [string]$TargetFolder
    )

    # Full path for PsExec64.exe
    $PsExec64Path = Join-Path -Path $TargetFolder -ChildPath "PsExec64.exe"

    try {
        # Check if PsExec64.exe exists
        if (Test-Path -Path $PsExec64Path) {
            Write-EnhancedLog -Message "Removing existing PsExec64.exe from: $TargetFolder"
            # Remove PsExec64.exe
            Remove-Item -Path $PsExec64Path -Force
            Write-EnhancedLog -Message "PsExec64.exe has been removed from: $TargetFolder"
        }
        else {
            Write-EnhancedLog -Message "No PsExec64.exe file found in: $TargetFolder"
        }
    }
    catch {
        # Handle any errors during the removal
        Write-Error "An error occurred while trying to remove PsExec64.exe: $_"
    }
}

#EndRegion '.\Public\Remove-ExistingPsExec.ps1' 30
#Region '.\Public\Remove-ExistingServiceUI.ps1' -1

function Remove-ExistingServiceUI {
    [CmdletBinding()]
    param(
        [string]$TargetFolder,
        [string]$FileName
    )

    begin {
        Write-EnhancedLog -Message "Starting Remove-ExistingServiceUI function" -Level "INFO"
        Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters
    }

    process {
        # Full path for ServiceUI.exe
        $serviceUIPathParams = @{
            Path = $TargetFolder
            ChildPath = $FileName
        }
        $ServiceUIPath = Join-Path @serviceUIPathParams

        try {
            # Check if ServiceUI.exe exists
            $testPathParams = @{
                Path = $ServiceUIPath
            }
            if (Test-Path @testPathParams) {
                Write-EnhancedLog -Message "Removing existing ServiceUI.exe from: $TargetFolder" -Level "INFO"

                # Remove ServiceUI.exe
                $removeItemParams = @{
                    Path = $ServiceUIPath
                    Force = $true
                }
                Remove-Item @removeItemParams

                Write-Output "ServiceUI.exe has been removed from: $TargetFolder"
            }
            else {
                Write-EnhancedLog -Message "No ServiceUI.exe file found in: $TargetFolder" -Level "INFO"
            }
        }
        catch {
            # Handle any errors during the removal
            Write-Error "An error occurred while trying to remove ServiceUI.exe: $_"
            Write-EnhancedLog -Message "An error occurred while trying to remove ServiceUI.exe: $_" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    end {
        Write-EnhancedLog -Message "Remove-ExistingServiceUI function execution completed." -Level "INFO"
    }
}

# # Example usage of Remove-ExistingServiceUI function with splatting
# $params = @{
# TargetFolder = "C:\Path\To\Your\Desired\Folder",
# FileName = "ServiceUI.exe"
# }
# Remove-ExistingServiceUI @params
#EndRegion '.\Public\Remove-ExistingServiceUI.ps1' 61
#Region '.\Public\Remove-ScheduledTaskFilesWithLogging.ps1' -1

function Remove-ScheduledTaskFilesWithLogging {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$Path
    )

    Begin {
        Write-EnhancedLog -Message "Starting Remove-ScheduledTaskFilesWithLogging function" -Level "INFO"
        Log-Params -Params @{
            Path = $Path
        }
    }

    Process {
        try {
            # Validate before removal
            $existsBefore = Validate-PathExistsWithLogging -Path $Path

            if ($existsBefore) {
                Write-EnhancedLog -Message "Calling Remove-Item for path: $Path" -Level "INFO"
                Remove-Item -Path $Path -Recurse -Force
                Write-EnhancedLog -Message "Remove-Item done for path: $Path" -Level "INFO"
            } else {
                Write-EnhancedLog -Message "Path $Path does not exist. No action taken." -Level "WARNING"
            }

            # Validate after removal
            $existsAfter = Validate-PathExistsWithLogging -Path $Path

            # $DBG

            if ($existsAfter) {
                Write-EnhancedLog -Message "Path $Path still exists after attempting to remove. Manual intervention may be required." -Level "ERROR"
            } else {
                Write-EnhancedLog -Message "Path $Path successfully removed." -Level "INFO"
            }
        } catch {
            Write-EnhancedLog -Message "Error during Remove-Item for path: $Path. Error: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Remove-ScheduledTaskFilesWithLogging function" -Level "INFO"
    }
}


# Remove-ScheduledTaskFilesWithLogging -Path "C:\Path\To\ScheduledTaskFiles"
#EndRegion '.\Public\Remove-ScheduledTaskFilesWithLogging.ps1' 51
#Region '.\Public\Set-LocalPathBasedOnContext.ps1' -1

function Set-LocalPathBasedOnContext {
    Write-EnhancedLog -Message "Checking running context..." -Level "INFO" -ForegroundColor ([System.ConsoleColor]::Cyan)
    if (Test-RunningAsSystem) {
        Write-EnhancedLog -Message "Running as system, setting path to Program Files" -Level "INFO" -ForegroundColor ([System.ConsoleColor]::Yellow)
        # return "$ENV:Programfiles\_MEM"
        return "C:\_MEM"
    }
    else {
        Write-EnhancedLog -Message "Running as user, setting path to Local AppData" -Level "INFO" -ForegroundColor ([System.ConsoleColor]::Yellow)
        return "$ENV:LOCALAPPDATA\_MEM"
    }
}
#EndRegion '.\Public\Set-LocalPathBasedOnContext.ps1' 13
#Region '.\Public\Start-ServiceUIWithAppDeploy.ps1' -1

function Start-ServiceUIWithAppDeploy {
    [CmdletBinding()]
    param (
        [string]$PSADTExecutable = "$PSScriptRoot\Private\PSAppDeployToolkit\Toolkit\Deploy-Application.exe",
        [string]$ServiceUIExecutable = "$PSScriptRoot\Private\ServiceUI.exe",
        [string]$DeploymentType = "Install",
        [string]$DeployMode = "Interactive"
    )

    try {
        # Verify if the ServiceUI executable exists
        if (-not (Test-Path -Path $ServiceUIExecutable)) {
            throw "ServiceUI executable not found at path: $ServiceUIExecutable"
        }

        # Verify if the PSAppDeployToolkit executable exists
        if (-not (Test-Path -Path $PSADTExecutable)) {
            throw "PSAppDeployToolkit executable not found at path: $PSADTExecutable"
        }

        # Log the start of the process
        Write-EnhancedLog -Message "Starting ServiceUI.exe with Deploy-Application.exe" -Level "INFO"

        # Define the arguments to pass to ServiceUI.exe
        $arguments = "-process:explorer.exe `"$PSADTExecutable`" -DeploymentType $DeploymentType -Deploymode $Deploymode"

        # Start the ServiceUI.exe process with the specified arguments
        Start-Process -FilePath $ServiceUIExecutable -ArgumentList $arguments -Wait -WindowStyle Hidden

        # Log successful completion
        Write-EnhancedLog -Message "ServiceUI.exe started successfully with Deploy-Application.exe" -Level "INFO"
    }
    catch {
        # Handle any errors during the process
        Write-Error "An error occurred: $_"
        Write-EnhancedLog -Message "An error occurred: $_" -Level "ERROR"
    }
}
#EndRegion '.\Public\Start-ServiceUIWithAppDeploy.ps1' 39
#Region '.\Public\Test-RunningAsSystem.ps1' -1

function Test-RunningAsSystem {
    $systemSid = New-Object System.Security.Principal.SecurityIdentifier "S-1-5-18"
    $currentSid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User

    return $currentSid -eq $systemSid
}
#EndRegion '.\Public\Test-RunningAsSystem.ps1' 7
#Region '.\Public\Unregister-ScheduledTaskWithLogging.ps1' -1

function Unregister-ScheduledTaskWithLogging {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$TaskName
    )

    Begin {
        Write-EnhancedLog -Message "Starting Unregister-ScheduledTaskWithLogging function" -Level "INFO"
        Log-Params -Params @{ TaskName = $TaskName }
    }

    Process {
        try {
            Write-EnhancedLog -Message "Checking if task '$TaskName' exists before attempting to unregister." -Level "INFO"
            $taskExistsBefore = Check-ExistingTask -taskName $TaskName
            
            if ($taskExistsBefore) {
                Write-EnhancedLog -Message "Task '$TaskName' found. Proceeding to unregister." -Level "INFO"
                Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false
                Write-EnhancedLog -Message "Unregister-ScheduledTask done for task: $TaskName" -Level "INFO"
            } else {
                Write-EnhancedLog -Message "Task '$TaskName' not found. No action taken." -Level "INFO"
            }

            Write-EnhancedLog -Message "Checking if task '$TaskName' exists after attempting to unregister." -Level "INFO"
            $taskExistsAfter = Check-ExistingTask -taskName $TaskName
            
            if ($taskExistsAfter) {
                Write-EnhancedLog -Message "Task '$TaskName' still exists after attempting to unregister. Manual intervention may be required." -Level "ERROR"
            } else {
                Write-EnhancedLog -Message "Task '$TaskName' successfully unregistered." -Level "INFO"
            }
        } catch {
            Write-EnhancedLog -Message "Error during Unregister-ScheduledTask for task: $TaskName. Error: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Unregister-ScheduledTaskWithLogging function" -Level "INFO"
    }
}


# Unregister-ScheduledTaskWithLogging -TaskName "YourScheduledTaskName"

#EndRegion '.\Public\Unregister-ScheduledTaskWithLogging.ps1' 48
#Region '.\Public\Validate-PathExistsWithLogging.ps1' -1

function Validate-PathExistsWithLogging {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$Path
    )

    Begin {
        Write-EnhancedLog -Message "Starting Validate-PathExistsWithLogging function" -Level "INFO"
        Log-Params -Params @{
            Path = $Path
        }
    }

    Process {
        try {
            $exists = Test-Path -Path $Path

            if ($exists) {
                Write-EnhancedLog -Message "Path exists: $Path" -Level "INFO"
            }
            else {
                Write-EnhancedLog -Message "Path does not exist: $Path" -Level "WARNING"
            }

            return $exists
        }
        catch {
            Write-EnhancedLog -Message "Error during path validation: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    End {
        Write-EnhancedLog -Message "Exiting Validate-PathExistsWithLogging function" -Level "INFO"
    }
}


# $pathExists = Validate-PathExistsWithLogging -Path "C:\Path\To\Check"

#EndRegion '.\Public\Validate-PathExistsWithLogging.ps1' 42
#Region '.\Public\Verify-CopyOperation.ps1' -1

function Verify-CopyOperation {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$SourcePath,

        [Parameter(Mandatory = $true)]
        [string]$DestinationPath
    )

    begin {
        Write-EnhancedLog -Message "Verifying copy operation..." -Level "INFO"
        Log-Params -Params @{
            SourcePath = $SourcePath
            DestinationPath = $DestinationPath
        }

        $sourceItems = Get-ChildItem -Path $SourcePath -Recurse
        $destinationItems = Get-ChildItem -Path $DestinationPath -Recurse

        # Use a generic list for better performance compared to using an array with +=
        $verificationResults = New-Object System.Collections.Generic.List[Object]
    }

    process {
        try {
            foreach ($item in $sourceItems) {
                $relativePath = $item.FullName.Substring($SourcePath.Length)
                $correspondingPath = Join-Path -Path $DestinationPath -ChildPath $relativePath

                if (-not (Test-Path -Path $correspondingPath)) {
                    $verificationResults.Add([PSCustomObject]@{
                            Status       = "Missing"
                            SourcePath   = $item.FullName
                            ExpectedPath = $correspondingPath
                        })
                }
            }

            foreach ($item in $destinationItems) {
                $relativePath = $item.FullName.Substring($DestinationPath.Length)
                $correspondingPath = Join-Path -Path $SourcePath -ChildPath $relativePath

                if (-not (Test-Path -Path $correspondingPath)) {
                    $verificationResults.Add([PSCustomObject]@{
                            Status     = "Extra"
                            SourcePath = $correspondingPath
                            ActualPath = $item.FullName
                        })
                }
            }
        }
        catch {
            Write-EnhancedLog -Message "Error during verification process: $($_.Exception.Message)" -Level "ERROR"
            Handle-Error -ErrorRecord $_
        }
    }

    end {
        if ($verificationResults.Count -gt 0) {
            Write-EnhancedLog -Message "Discrepancies found. See detailed log." -Level "WARNING"
            $verificationResults | Format-Table -AutoSize | Out-String | ForEach-Object { 
                Write-EnhancedLog -Message $_ -Level "INFO" 
            }

            #Uncomment when troubelshooting
            $verificationResults | Out-GridView
        }
        else {
            Write-EnhancedLog -Message "All items verified successfully. No discrepancies found." -Level "INFO"
        }

        Write-EnhancedLog -Message ("Total items in source: " + $sourceItems.Count) -Level "INFO"
        Write-EnhancedLog -Message ("Total items in destination: " + $destinationItems.Count) -Level "INFO"
    }
}


# # Define the source and destination paths
# $sourcePath = "C:\Source"
# $destinationPath = "C:\Destination"

# # Example usage of the Verify-CopyOperation function
# Verify-CopyOperation -SourcePath $sourcePath -DestinationPath $destinationPath

#EndRegion '.\Public\Verify-CopyOperation.ps1' 86