Psmd.Bootstrap.psm1

$script:ModuleRoot = $PSScriptRoot

function New-PsmdBootstrapScript {
    <#
    .SYNOPSIS
        Take all contents of a folder and embed them into a bootstrap scriptfile.
     
    .DESCRIPTION
        Take all contents of a folder and embed them into a bootstrap scriptfile.
        The targeted folder must contain a run.ps1 file for executing the bootstrap logic (unless you change that using the -StartScript parameter).
 
        When executing the resulting file, it will:
        - Create a temp folder
        - Write all contents of the source folder into that temp folder
        - Execute the start script within that temp folder (in a child process, unless calling the resulting file with '-NoChildProcess')
        - Remove the temp folder
     
    .PARAMETER Path
        The source folder containing the content to wrap up.
        Must contain a file named run.ps1, may contain subfolders.
     
    .PARAMETER OutPath
        The path where to write the bootstrap scriptfile to.
        Can be either a folder or the path to the ps1 file itself.
        If a folder is specified, it will create a "bootstrap.ps1" file in that folder.
 
    .PARAMETER StartScript
        The script file in the root folder that should be run when executing the bootstrap-script resulting from this command.
        Defaults to "run.ps1"
     
    .EXAMPLE
        PS C:\> New-PsmdBootstrapScript -Path . -OutPath C:\temp
         
        Takes all items in the current folder, wraps them into a bootstrap script and writes that single file to C:\temp\bootstrap.ps1
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [PsfValidateScript('PSFramework.Validate.FSPath.Folder', ErrorString = 'PSFramework.Validate.FSPath.Folder')]
        [string]
        $Path,

        [Parameter(Mandatory = $true)]
        [PsfValidateScript('PSFramework.Validate.FSPath.FileOrParent', ErrorString = 'PSFramework.Validate.FSPath.FileOrParent')]
        [string]
        $OutPath,

        [PsfValidatePattern('\.ps1$', ErrorMessage = 'The Start Script must be a ps1 file!')]
        [string]
        $StartScript = 'run.ps1'
    )
    process {
        $runFile = Join-Path -Path $Path -ChildPath $StartScript
        if (-not (Test-Path -Path $runFile)) {
            Stop-PSFFunction -Message "Invalid package! No $StartScript found in source folder $Path." -Target $Path -EnableException $true -Cmdlet $PSCmdlet -Category InvalidData
        }

        #region Generate Bootstrap Payload
        $tempFile = New-PSFTempFile -Name bootstrapzip -Extension zip -ModuleName Psmd.Bootstrap
        $tempDir = New-PSFTempDirectory -Name bootstrapdir -ModuleName Psmd.Bootstrap
        Copy-Item -Path (Join-Path -Path $Path -ChildPath '*') -Destination $tempDir

        # Write config file for bootstrap script
        @{ RunFile = $StartScript } | Export-Clixml -Path "$tempDir\__Psmd_Bootstrap.clixml"

        Compress-Archive -Path "$tempDir\*" -DestinationPath $tempFile -Force
        $bytes = [System.IO.File]::ReadAllBytes($tempFile)
        $encoded = [convert]::ToBase64String($bytes)
        $bytes = $null

        $bootstrapCode = [System.IO.File]::ReadAllText("$script:ModuleRoot\content\bootstrap.ps1")
        $bootstrapCode = $bootstrapCode -replace '%data%', $encoded
        $encoded = $null
        Remove-PSFTempItem -Name bootstrapzip -ModuleName Psmd.Bootstrap
        Remove-PSFTempItem -Name bootstrapdir -ModuleName Psmd.Bootstrap
        #endregion Generate Bootstrap Payload

        #region Export bootstrapped file
        $outFile = Resolve-PSFPath -Path $OutPath -Provider FileSystem -SingleItem -NewChild
        if (Test-Path -Path $OutPath) {
            $item = Get-Item -Path $OutPath
            if ($item.PSIsContainer) {
                $outFile = Join-Path -Path $outFile -ChildPath 'bootstrap.ps1'
            }
        }
        $filename = Split-Path -Path $outFile -Leaf
        $bootstrapCode = $bootstrapCode -replace '%scriptname%', $filename

        $encoding = [System.Text.UTF8Encoding]::new($true)
        [System.IO.File]::WriteAllText($outFile, $bootstrapCode, $encoding)
        #endregion Export bootstrapped file
    }
}