From bdbdf43a628f4b05df8d7d573ffe1c13d2cb64d6 Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Mon, 23 Jun 2025 20:15:23 -0700 Subject: [PATCH 01/12] First pass at implementing packed module support --- powershell-runtime/source/bootstrap | 16 ++++ .../modules/Private/Import-ModuleArchive.ps1 | 40 ++++++++++ .../modules/Private/Import-ModulePackage.ps1 | 49 ++++++++++++ .../modules/Private/Set-PSModulePath.ps1 | 9 +++ .../Private/Test-RuntimePackedModule.ps1 | 79 +++++++++++++++++++ 5 files changed, 193 insertions(+) create mode 100644 powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 create mode 100644 powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 create mode 100644 powershell-runtime/source/modules/Private/Test-RuntimePackedModule.ps1 diff --git a/powershell-runtime/source/bootstrap b/powershell-runtime/source/bootstrap index 81bcad7..15934cd 100755 --- a/powershell-runtime/source/bootstrap +++ b/powershell-runtime/source/bootstrap @@ -18,6 +18,22 @@ Import-Module '/opt/modules/pwsh-runtime.psd1' if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]Importing .NET class from .cs file to support script properties and method' } Add-Type -TypeDefinition ([System.IO.File]::ReadAllText('/opt/PowerShellLambdaContext.cs')) +# Unpack compressed modules, if present + +# Combined +If (Test-RuntimePackedModule -Combined) { + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') {Write-Host '[RUNTIME-bootstrap]Unpacking combined module archives'} + Import-ModuleArchive + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') {Write-Host '[RUNTIME-bootstrap]Finished unpacking archives'} + +} +# NuPkg +If (Test-RuntimePackedModule -NuPkg) { + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') {Write-Host '[RUNTIME-bootstrap]Unpacking module NuGet packages'} + Import-ModulePackage + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') {Write-Host '[RUNTIME-bootstrap]Finished unpacking NuGet packages'} +} + # Modify $env:PSModulePath to support Lambda paths if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') {Write-Host '[RUNTIME-bootstrap]Modify PSModulePath to support Lambda paths'} Set-PSModulePath diff --git a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 new file mode 100644 index 0000000..ed4347d --- /dev/null +++ b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 @@ -0,0 +1,40 @@ +function private:Import-ModuleArchive { + <# + .SYNOPSIS + Unpacks compressed PowerShell modules from .zip archives (modules.zip) + .DESCRIPTION + Unpacks compressed PowerShell modules from .zip archives (modules.zip) into a subdirectory of /tmp. + + This folder is later added to $env:PSModulePath, before user code runs, if module archives existed. + .NOTES + The contents of this archive should match the format of a folder in $Env:PSModulePath. More specifically: + * Module names should be top-level directories. + * One or more versions of the same module may be hosted in their own subdirectories, with respective version numbers. + * The module root (.psd1/.psm1 files, etc.) is contained within either the module-named or module-versioned directory. + + Module packages are imported from two locations, from lowest to highest precedence: + * /opt/ (Combined Lambda layer directory) + * $Env:LAMBDA_TASK_ROOT (Lambda Function Package deployment directory) + + If archives are detected at both locations, they will be extracted over the top of each-other. + #> + + $SearchPaths = @( + "/opt/modules.zip" + $(Join-Path $env:LAMBDA_TASK_ROOT -ChildPath "modules.zip") + ) + + If ($SearchPaths | ? { Test-Path $_ }) { + $UnpackDirectory = '/tmp/powershell-custom-runtime-unpacked-modules/combined/' + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]Creating unpack directory for combined module archives' } + New-Item -ItemType Directory -Path $UnpackDirectory -Force + $SearchPaths | ? { Test-Path $_ } | ForEach-Object { + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Unpacking $_ to $UnpackDirectory" } + Expand-Archive -LiteralPath $_ -DestinationPath $UnpackDirectory -Force + } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]Archive unpack complete' } + } + else { + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]No module archives detected; nothing to do.' } + } +} \ No newline at end of file diff --git a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 new file mode 100644 index 0000000..3aa26ef --- /dev/null +++ b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 @@ -0,0 +1,49 @@ +function private:Import-ModulePackage { + <# + .SYNOPSIS + Installs compressed PowerShell modules from NuGet packages (*.nupkg) + .DESCRIPTION + Installs compressed PowerShell modules from NuGet packages (*.nupkg) into a subdirectory of /tmp. + + This folder is later added to $env:PSModulePath, before user code runs, if module packages existed. + .NOTES + These packages should match the NuPkg format used by PSResourceGet or PowerShellGet. + + Packages can be exported either by: + * Downloading the .nupkg files directly from an upstream source (e.g. PowerShell Gallery) + * Using the -AsNuPkg parameter on Save-PSResource in the Microsoft.PowerShell.PSResourceGet module. + + Module packages are imported from two locations, from lowest to highest precedence: + * /opt/module-nupkgs/ (Combined Lambda layer directory) + * $Env:LAMBDA_TASK_ROOT/module-nupkgs/ (Lambda Function Package deployment directory) + #> + $SearchPaths = @{ + Layer = "/opt/module-nupkgs/*.nupkg" + Root = (Join-Path $env:LAMBDA_TASK_ROOT -ChildPath "module-nupkgs" -AdditionalChildPath "*.nupkg") + } + + If ($SearchPaths.Values | ? { Test-Path $_ }) { + $UnpackDirectory = '/tmp/powershell-custom-runtime-unpacked-modules/nupkgs/' + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]Creating unpack directory for individual module packages' } + New-Item -ItemType Directory -Path $UnpackDirectory -Force + $SearchPaths.GetEnumerator() | ? { Test-Path $_.Value } | ForEach-Object { + $PackageDirectory = Split-Path $_.Value -Parent + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Importing module packages from $PackageDirectory" } + $RepositoryName = "Lambda-Local-$($_.Key)" + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Registering local package repository $RepositoryName" } + Register-PSResourceRepository -Name $RepositoryName -Uri $PackageDirectory -Trusted -Priority 1 + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Enumerating packages in $PackageDirectory (PSResource repository $RepositoryName)" } + Find-PSResource -Name * -Repository $RepositoryName | ForEach-Object -Parallel { + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Saving package $($_.Name) version $($_.Version) (PSResource repository $($using:RepositoryName))" } + $_ | Save-PSResource -SkipDependencyCheck -Path $using:PackageDirectory -Quiet -AcceptLicense -Confirm:$false + } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Registering local package repository $RepositoryName" } + Unregister-PSResourceRepository -Name $RepositoryName -Confirm:$false + } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]Archive unpack complete' } + } + else { + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]No module archives detected; nothing to do.' } + } + +} \ No newline at end of file diff --git a/powershell-runtime/source/modules/Private/Set-PSModulePath.ps1 b/powershell-runtime/source/modules/Private/Set-PSModulePath.ps1 index d79b113..1c15c72 100644 --- a/powershell-runtime/source/modules/Private/Set-PSModulePath.ps1 +++ b/powershell-runtime/source/modules/Private/Set-PSModulePath.ps1 @@ -14,6 +14,7 @@ function private:Set-PSModulePath { 1: Modules supplied with pwsh 2: User supplied modules as part of Lambda Layers 3: User supplied modules as part of function package + 4: Compressed modules #> if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Set-PSModulePath]Start: Set-PSModulePath' } if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Set-PSModulePath]Setting PSModulePath environment variable' } @@ -22,5 +23,13 @@ function private:Set-PSModulePath { '/opt/modules', # User supplied modules as part of Lambda Layers [System.IO.Path]::Combine($env:LAMBDA_TASK_ROOT, 'modules') # User supplied modules as part of function package ) -join ':' + If (Test-RuntimePackedModule -Combined) { + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Set-PSModulePath]Combined module package detected, adding unpack directory to PSModulePath" } + $env:PSModulePath += (':' + '/tmp/powershell-custom-runtime-unpacked-modules/combined') # Modules unpacked via Import-ModuleArchive + } + If (Test-RuntimePackedModule -NuPkg) { + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Set-PSModulePath]Nupkg module package(s) detected, adding unpack directory to PSModulePath" } + $env:PSModulePath += (':' + '/tmp/powershell-custom-runtime-unpacked-modules/nupkg') # Modules unpacked via Import-ModulePackage + } if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Set-PSModulePath]PSModulePath environment variable set to: $($env:PSModulePath)" } } diff --git a/powershell-runtime/source/modules/Private/Test-RuntimePackedModule.ps1 b/powershell-runtime/source/modules/Private/Test-RuntimePackedModule.ps1 new file mode 100644 index 0000000..b2704ed --- /dev/null +++ b/powershell-runtime/source/modules/Private/Test-RuntimePackedModule.ps1 @@ -0,0 +1,79 @@ +function private:Test-RuntimePackedModule { + <# + .SYNOPSIS + Tests whether the current runtime environment contains compressed module packages (combined .zip or per-module .nupkg) + .DESCRIPTION + Tests whether the current runtime environment contains compressed module packages (combined .zip or per-module .nupkg) + .NOTES + Looks for module packages in two locations: + * /opt/ (Combined Lambda layer directory) + * $Env:LAMBDA_TASK_ROOT (Lambda Function package directory) + + Module packages can take two forms: + * A single, combined module archive, named "modules.zip". + The contents of this archive should match the format of a folder in $Env:PSModulePath. + (Module names as top-level directories, optional version subdirectory, corresponding module root) + * Individual module archives, as .nupkg files, inside a subdirectory named "module-nupkgs" + These files should match: + * The naming convention used by PSResourceGet. (e.g. ..nupkg) + * The Nupkg archive spec (module root at archive root, NuGet [Content_Types].xml/_rels, etc.) + + The following file locations should all be detected (assume $Env:LAMBDA_TASK_ROOT = /var/lambda/) + * /opt/modules.zip + * /var/lambda/modules.zip + * /opt/module-nupkgs/AWS.Tools.Common.4.1.833.nupkg + * /var/lambda/module-nupkgs/AWS.Tools.Common.4.1.833.nupkg + .EXAMPLE + Test-MyTestFunction -Verbose + Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines + #> + + [CmdletBinding()] + param( + # Looks for combined module archives (modules.zip). + [Parameter( + Mandatory, + ParameterSetName="Combined" + )] + [Switch] + $Combined, + + # Looks for individual module packages (*.nupkg). + [Parameter( + Mandatory, + ParameterSetName="NuPkg" + )] + [Switch] + $NuPkg + ) + + $BaseDirectories = @( + "/opt", + $Env:LAMBDA_TASK_ROOT + ) + + switch ($PSCmdlet.ParameterSetName) { + "Combined" { + + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Test-RuntimePackedModule]Searching for combined module archives" } + + $BaseDirectories | Join-Path -ChildPath "modules.zip" | Get-Item -ErrorAction SilentlyContinue | Set-Variable FoundItems + + } + "NuPkg" { + + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Test-RuntimePackedModule]Searching for individual module packages" } + + $BaseDirectories | Join-Path -ChildPath "module-nupkgs" -AdditionalChildPath "*.nupkg" | Get-Item -ErrorAction SilentlyContinue | Set-Variable FoundItems + + } + } + + If ($FoundItems) { + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Test-RuntimePackedModule]Found $($FoundItems | Measure-Object | % Count) match(es)" } + return $true + } else { + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Test-RuntimePackedModule]No matches found" } + return $false + } +} \ No newline at end of file From 98a8765357cb94698b4534be47a0e931e82bd641 Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Fri, 18 Jul 2025 11:41:26 -0700 Subject: [PATCH 02/12] Adjust log preamble for Import-Module* --- .../modules/Private/Import-ModuleArchive.ps1 | 8 ++++---- .../modules/Private/Import-ModulePackage.ps1 | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 index ed4347d..e6c8790 100644 --- a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 @@ -26,15 +26,15 @@ function private:Import-ModuleArchive { If ($SearchPaths | ? { Test-Path $_ }) { $UnpackDirectory = '/tmp/powershell-custom-runtime-unpacked-modules/combined/' - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]Creating unpack directory for combined module archives' } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]Creating unpack directory for combined module archives' } New-Item -ItemType Directory -Path $UnpackDirectory -Force $SearchPaths | ? { Test-Path $_ } | ForEach-Object { - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Unpacking $_ to $UnpackDirectory" } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModuleArchive]Unpacking $_ to $UnpackDirectory" } Expand-Archive -LiteralPath $_ -DestinationPath $UnpackDirectory -Force } - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]Archive unpack complete' } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]Archive unpack complete' } } else { - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]No module archives detected; nothing to do.' } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]No module archives detected; nothing to do.' } } } \ No newline at end of file diff --git a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 index 3aa26ef..9b77637 100644 --- a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 @@ -24,26 +24,26 @@ function private:Import-ModulePackage { If ($SearchPaths.Values | ? { Test-Path $_ }) { $UnpackDirectory = '/tmp/powershell-custom-runtime-unpacked-modules/nupkgs/' - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]Creating unpack directory for individual module packages' } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModulePackage]Creating unpack directory for individual module packages' } New-Item -ItemType Directory -Path $UnpackDirectory -Force $SearchPaths.GetEnumerator() | ? { Test-Path $_.Value } | ForEach-Object { $PackageDirectory = Split-Path $_.Value -Parent - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Importing module packages from $PackageDirectory" } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Importing module packages from $PackageDirectory" } $RepositoryName = "Lambda-Local-$($_.Key)" - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Registering local package repository $RepositoryName" } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Registering local package repository $RepositoryName" } Register-PSResourceRepository -Name $RepositoryName -Uri $PackageDirectory -Trusted -Priority 1 - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Enumerating packages in $PackageDirectory (PSResource repository $RepositoryName)" } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Enumerating packages in $PackageDirectory (PSResource repository $RepositoryName)" } Find-PSResource -Name * -Repository $RepositoryName | ForEach-Object -Parallel { - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Saving package $($_.Name) version $($_.Version) (PSResource repository $($using:RepositoryName))" } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Saving package $($_.Name) version $($_.Version) (PSResource repository $($using:RepositoryName))" } $_ | Save-PSResource -SkipDependencyCheck -Path $using:PackageDirectory -Quiet -AcceptLicense -Confirm:$false } - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-bootstrap]Registering local package repository $RepositoryName" } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Registering local package repository $RepositoryName" } Unregister-PSResourceRepository -Name $RepositoryName -Confirm:$false } - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]Archive unpack complete' } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModulePackage]Archive unpack complete' } } else { - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap]No module archives detected; nothing to do.' } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModulePackage]No module archives detected; nothing to do.' } } } \ No newline at end of file From 9963b94f4b24f13b97d96fd67e04a509c4db9e5f Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Fri, 18 Jul 2025 14:45:33 -0700 Subject: [PATCH 03/12] Remove alias --- .../source/modules/Private/Import-ModuleArchive.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 index e6c8790..e2b8b6e 100644 --- a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 @@ -24,7 +24,7 @@ function private:Import-ModuleArchive { $(Join-Path $env:LAMBDA_TASK_ROOT -ChildPath "modules.zip") ) - If ($SearchPaths | ? { Test-Path $_ }) { + If ($SearchPaths | Where-Object { Test-Path $_ }) { $UnpackDirectory = '/tmp/powershell-custom-runtime-unpacked-modules/combined/' if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]Creating unpack directory for combined module archives' } New-Item -ItemType Directory -Path $UnpackDirectory -Force From 917c9adcafbbe26df6bdcbb66626ef5e69f4cfc0 Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Fri, 18 Jul 2025 15:52:29 -0700 Subject: [PATCH 04/12] Sequester output of New-Item --- .../source/modules/Private/Import-ModuleArchive.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 index e2b8b6e..8b5585d 100644 --- a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 @@ -27,7 +27,7 @@ function private:Import-ModuleArchive { If ($SearchPaths | Where-Object { Test-Path $_ }) { $UnpackDirectory = '/tmp/powershell-custom-runtime-unpacked-modules/combined/' if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]Creating unpack directory for combined module archives' } - New-Item -ItemType Directory -Path $UnpackDirectory -Force + $null = New-Item -ItemType Directory -Path $UnpackDirectory -Force $SearchPaths | ? { Test-Path $_ } | ForEach-Object { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModuleArchive]Unpacking $_ to $UnpackDirectory" } Expand-Archive -LiteralPath $_ -DestinationPath $UnpackDirectory -Force From db51cda7d1e3db8b22d9b287e75ef1e615158f6f Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Fri, 18 Jul 2025 16:22:26 -0700 Subject: [PATCH 05/12] Memoize un/packed compressed module paths within module base, refactor `Set-PSModulePath` to use it --- .../modules/Private/Set-PSModulePath.ps1 | 20 ++++++++++++------- .../source/modules/pwsh-runtime.psm1 | 17 ++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/powershell-runtime/source/modules/Private/Set-PSModulePath.ps1 b/powershell-runtime/source/modules/Private/Set-PSModulePath.ps1 index 1c15c72..a2aed48 100644 --- a/powershell-runtime/source/modules/Private/Set-PSModulePath.ps1 +++ b/powershell-runtime/source/modules/Private/Set-PSModulePath.ps1 @@ -23,13 +23,19 @@ function private:Set-PSModulePath { '/opt/modules', # User supplied modules as part of Lambda Layers [System.IO.Path]::Combine($env:LAMBDA_TASK_ROOT, 'modules') # User supplied modules as part of function package ) -join ':' - If (Test-RuntimePackedModule -Combined) { - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Set-PSModulePath]Combined module package detected, adding unpack directory to PSModulePath" } - $env:PSModulePath += (':' + '/tmp/powershell-custom-runtime-unpacked-modules/combined') # Modules unpacked via Import-ModuleArchive - } - If (Test-RuntimePackedModule -NuPkg) { - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Set-PSModulePath]Nupkg module package(s) detected, adding unpack directory to PSModulePath" } - $env:PSModulePath += (':' + '/tmp/powershell-custom-runtime-unpacked-modules/nupkg') # Modules unpacked via Import-ModulePackage + + # Iterate over both packed module directories (.Combined for modules.zip, .NuPkg for nupkgs) and... add their unpack dirs to PSModulePath if present + $Script:ModulePaths.Packed.GetEnumerator() | ForEach-Object { + + # If the unpack directory exists... + If (Test-Path -LiteralPath $_.Value -ErrorAction SilentlyContinue) { + + # Add it to PSModulePath. + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Set-PSModulePath]$($_.Key) module package detected, adding unpack directory to PSModulePath" } + $env:PSModulePath += (':' + $_.Value) + + } } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Set-PSModulePath]PSModulePath environment variable set to: $($env:PSModulePath)" } } diff --git a/powershell-runtime/source/modules/pwsh-runtime.psm1 b/powershell-runtime/source/modules/pwsh-runtime.psm1 index a40b6ca..5af92b3 100644 --- a/powershell-runtime/source/modules/pwsh-runtime.psm1 +++ b/powershell-runtime/source/modules/pwsh-runtime.psm1 @@ -3,6 +3,23 @@ Set-PSDebug -Strict +$Script:ModulePaths = @{ + Packed = @{ + Combined = @( + "/opt/modules.zip" + "$Env:LAMBDA_TASK_ROOT/modules.zip" + ) + NuPkg = @( + "/opt/module-nupkgs/*.nupkg" + "$Env:LAMBDA_TASK_ROOT/module-nupkgs/*.nupkg" + ) + } + Unpacked = @{ + Combined = '/tmp/powershell-custom-runtime-unpacked-modules/combined' + NuPkg = '/tmp/powershell-custom-runtime-unpacked-modules/nupkg' + } +} + ##### All code below this comment is excluded from the build process # All Private modules merged into this file during build process to speed up module loading. From d2fb0e91653b4ede0363a66bc2d214b73d38e50c Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Fri, 18 Jul 2025 16:24:51 -0700 Subject: [PATCH 06/12] Use script-scope unpack dirs in Import-Module* --- .../source/modules/Private/Import-ModuleArchive.ps1 | 3 +-- .../source/modules/Private/Import-ModulePackage.ps1 | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 index 8b5585d..d6cf93b 100644 --- a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 @@ -25,9 +25,8 @@ function private:Import-ModuleArchive { ) If ($SearchPaths | Where-Object { Test-Path $_ }) { - $UnpackDirectory = '/tmp/powershell-custom-runtime-unpacked-modules/combined/' if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]Creating unpack directory for combined module archives' } - $null = New-Item -ItemType Directory -Path $UnpackDirectory -Force + $null = New-Item -ItemType Directory -Path $Script:ModulePaths.Unpacked.Combined -Force $SearchPaths | ? { Test-Path $_ } | ForEach-Object { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModuleArchive]Unpacking $_ to $UnpackDirectory" } Expand-Archive -LiteralPath $_ -DestinationPath $UnpackDirectory -Force diff --git a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 index 9b77637..4c77a4c 100644 --- a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 @@ -23,9 +23,8 @@ function private:Import-ModulePackage { } If ($SearchPaths.Values | ? { Test-Path $_ }) { - $UnpackDirectory = '/tmp/powershell-custom-runtime-unpacked-modules/nupkgs/' if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModulePackage]Creating unpack directory for individual module packages' } - New-Item -ItemType Directory -Path $UnpackDirectory -Force + New-Item -ItemType Directory -Path $Script:ModulePaths.Unpacked.NuPkg -Force $SearchPaths.GetEnumerator() | ? { Test-Path $_.Value } | ForEach-Object { $PackageDirectory = Split-Path $_.Value -Parent if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Importing module packages from $PackageDirectory" } From 9d6ce81deb20e0b58d426f408c2146d1d52b434a Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Fri, 18 Jul 2025 16:42:41 -0700 Subject: [PATCH 07/12] Use module-scoped packed module paths in Import-ModuleArchive --- .../source/modules/Private/Import-ModuleArchive.ps1 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 index d6cf93b..0e4fbff 100644 --- a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 @@ -19,10 +19,7 @@ function private:Import-ModuleArchive { If archives are detected at both locations, they will be extracted over the top of each-other. #> - $SearchPaths = @( - "/opt/modules.zip" - $(Join-Path $env:LAMBDA_TASK_ROOT -ChildPath "modules.zip") - ) + $SearchPaths = $Script:ModulePaths.Packed.Combined If ($SearchPaths | Where-Object { Test-Path $_ }) { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]Creating unpack directory for combined module archives' } From dd6283586ec9c60e0b9b85c34707a1a7cd5989a5 Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Fri, 18 Jul 2025 16:48:08 -0700 Subject: [PATCH 08/12] Use `[directory]::CreateDirectory()` instead of `New-Item` --- .../source/modules/Private/Import-ModuleArchive.ps1 | 2 +- .../source/modules/Private/Import-ModulePackage.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 index 0e4fbff..60a1019 100644 --- a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 @@ -23,7 +23,7 @@ function private:Import-ModuleArchive { If ($SearchPaths | Where-Object { Test-Path $_ }) { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]Creating unpack directory for combined module archives' } - $null = New-Item -ItemType Directory -Path $Script:ModulePaths.Unpacked.Combined -Force + $null = [System.IO.Directory]::CreateDirectory($Script:ModulePaths.Unpacked.Combined) $SearchPaths | ? { Test-Path $_ } | ForEach-Object { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModuleArchive]Unpacking $_ to $UnpackDirectory" } Expand-Archive -LiteralPath $_ -DestinationPath $UnpackDirectory -Force diff --git a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 index 4c77a4c..49dbadd 100644 --- a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 @@ -24,7 +24,7 @@ function private:Import-ModulePackage { If ($SearchPaths.Values | ? { Test-Path $_ }) { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModulePackage]Creating unpack directory for individual module packages' } - New-Item -ItemType Directory -Path $Script:ModulePaths.Unpacked.NuPkg -Force + [System.IO.Directory]::CreateDirectory($Script:ModulePaths.Unpacked.NuPkg) $SearchPaths.GetEnumerator() | ? { Test-Path $_.Value } | ForEach-Object { $PackageDirectory = Split-Path $_.Value -Parent if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Importing module packages from $PackageDirectory" } From d0c3297c092b3e37c5365473e7ade26f60d8ce07 Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Fri, 18 Jul 2025 17:00:32 -0700 Subject: [PATCH 09/12] Use hashtable for defining packed module directories --- .../modules/Private/Import-ModuleArchive.ps1 | 6 +++--- .../modules/Private/Import-ModulePackage.ps1 | 5 +---- .../source/modules/pwsh-runtime.psm1 | 16 ++++++++-------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 index 60a1019..e19d24e 100644 --- a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 @@ -19,12 +19,12 @@ function private:Import-ModuleArchive { If archives are detected at both locations, they will be extracted over the top of each-other. #> - $SearchPaths = $Script:ModulePaths.Packed.Combined + $SearchPaths = $Script:ModulePaths.Packed.Combined.Values - If ($SearchPaths | Where-Object { Test-Path $_ }) { + If ($SearchPaths| Where-Object { Test-Path $_ }) { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]Creating unpack directory for combined module archives' } $null = [System.IO.Directory]::CreateDirectory($Script:ModulePaths.Unpacked.Combined) - $SearchPaths | ? { Test-Path $_ } | ForEach-Object { + $SearchPaths | Where-Object { Test-Path $_ } | ForEach-Object { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModuleArchive]Unpacking $_ to $UnpackDirectory" } Expand-Archive -LiteralPath $_ -DestinationPath $UnpackDirectory -Force } diff --git a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 index 49dbadd..956380f 100644 --- a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 @@ -17,10 +17,7 @@ function private:Import-ModulePackage { * /opt/module-nupkgs/ (Combined Lambda layer directory) * $Env:LAMBDA_TASK_ROOT/module-nupkgs/ (Lambda Function Package deployment directory) #> - $SearchPaths = @{ - Layer = "/opt/module-nupkgs/*.nupkg" - Root = (Join-Path $env:LAMBDA_TASK_ROOT -ChildPath "module-nupkgs" -AdditionalChildPath "*.nupkg") - } + $SearchPaths = $Script:ModulePaths.Packed.NuPkg If ($SearchPaths.Values | ? { Test-Path $_ }) { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModulePackage]Creating unpack directory for individual module packages' } diff --git a/powershell-runtime/source/modules/pwsh-runtime.psm1 b/powershell-runtime/source/modules/pwsh-runtime.psm1 index 5af92b3..40268e4 100644 --- a/powershell-runtime/source/modules/pwsh-runtime.psm1 +++ b/powershell-runtime/source/modules/pwsh-runtime.psm1 @@ -5,14 +5,14 @@ Set-PSDebug -Strict $Script:ModulePaths = @{ Packed = @{ - Combined = @( - "/opt/modules.zip" - "$Env:LAMBDA_TASK_ROOT/modules.zip" - ) - NuPkg = @( - "/opt/module-nupkgs/*.nupkg" - "$Env:LAMBDA_TASK_ROOT/module-nupkgs/*.nupkg" - ) + Combined = @{ + Layer = "/opt/modules.zip" + Root = "$Env:LAMBDA_TASK_ROOT/modules.zip" + } + NuPkg = @{ + Layer = "/opt/module-nupkgs/*.nupkg" + Root = "$Env:LAMBDA_TASK_ROOT/module-nupkgs/*.nupkg" + } } Unpacked = @{ Combined = '/tmp/powershell-custom-runtime-unpacked-modules/combined' From a16477976c942640297b554e5434933969a11c4f Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Fri, 18 Jul 2025 17:01:07 -0700 Subject: [PATCH 10/12] More alias removal --- .../source/modules/Private/Import-ModulePackage.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 index 956380f..5ab9813 100644 --- a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 @@ -19,10 +19,10 @@ function private:Import-ModulePackage { #> $SearchPaths = $Script:ModulePaths.Packed.NuPkg - If ($SearchPaths.Values | ? { Test-Path $_ }) { + If ($SearchPaths.Values | Where-Object { Test-Path $_ }) { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModulePackage]Creating unpack directory for individual module packages' } [System.IO.Directory]::CreateDirectory($Script:ModulePaths.Unpacked.NuPkg) - $SearchPaths.GetEnumerator() | ? { Test-Path $_.Value } | ForEach-Object { + $SearchPaths.GetEnumerator() | Where-Object { Test-Path $_.Value } | ForEach-Object { $PackageDirectory = Split-Path $_.Value -Parent if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Importing module packages from $PackageDirectory" } $RepositoryName = "Lambda-Local-$($_.Key)" From 28116269ee7177dce1ab2df4ef7487651af29b3a Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Fri, 18 Jul 2025 17:44:54 -0700 Subject: [PATCH 11/12] Rename `Test-RuntimePackedModule` to `Find-RuntimePackedModule` --- ...est-RuntimePackedModule.ps1 => Find-RuntimePackedModule.ps1} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename powershell-runtime/source/modules/Private/{Test-RuntimePackedModule.ps1 => Find-RuntimePackedModule.ps1} (98%) diff --git a/powershell-runtime/source/modules/Private/Test-RuntimePackedModule.ps1 b/powershell-runtime/source/modules/Private/Find-RuntimePackedModule.ps1 similarity index 98% rename from powershell-runtime/source/modules/Private/Test-RuntimePackedModule.ps1 rename to powershell-runtime/source/modules/Private/Find-RuntimePackedModule.ps1 index b2704ed..6d4db7c 100644 --- a/powershell-runtime/source/modules/Private/Test-RuntimePackedModule.ps1 +++ b/powershell-runtime/source/modules/Private/Find-RuntimePackedModule.ps1 @@ -1,4 +1,4 @@ -function private:Test-RuntimePackedModule { +function private:Find-RuntimePackedModule { <# .SYNOPSIS Tests whether the current runtime environment contains compressed module packages (combined .zip or per-module .nupkg) From 3f80377c74bceae9623c5033b991a45a37f11f83 Mon Sep 17 00:00:00 2001 From: Sean Williams <72675818+sean-r-williams@users.noreply.github.com> Date: Fri, 18 Jul 2025 18:27:05 -0700 Subject: [PATCH 12/12] Refactor Import-Module* and Find-RuntimePackedModule to avoid re-enumeration of files/directories --- powershell-runtime/source/bootstrap | 13 ++-- .../Private/Find-RuntimePackedModule.ps1 | 64 ++++++------------- .../modules/Private/Import-ModuleArchive.ps1 | 24 ++++--- .../modules/Private/Import-ModulePackage.ps1 | 40 ++++++++---- 4 files changed, 72 insertions(+), 69 deletions(-) diff --git a/powershell-runtime/source/bootstrap b/powershell-runtime/source/bootstrap index 15934cd..a6b2f0d 100755 --- a/powershell-runtime/source/bootstrap +++ b/powershell-runtime/source/bootstrap @@ -19,21 +19,20 @@ if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-bootstrap Add-Type -TypeDefinition ([System.IO.File]::ReadAllText('/opt/PowerShellLambdaContext.cs')) # Unpack compressed modules, if present +$ResolvedModules = Find-RuntimePackedModule -# Combined -If (Test-RuntimePackedModule -Combined) { +If ($ResolvedModules.Combined) { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') {Write-Host '[RUNTIME-bootstrap]Unpacking combined module archives'} - Import-ModuleArchive + Import-ModuleArchive -ArchivePath $ResolvedModules.Combined if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') {Write-Host '[RUNTIME-bootstrap]Finished unpacking archives'} - } -# NuPkg -If (Test-RuntimePackedModule -NuPkg) { +If ($ResolvedModules.NuPkg) { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') {Write-Host '[RUNTIME-bootstrap]Unpacking module NuGet packages'} - Import-ModulePackage + Import-ModulePackage -PackagePath $ResolvedModules.NuPkg if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') {Write-Host '[RUNTIME-bootstrap]Finished unpacking NuGet packages'} } + # Modify $env:PSModulePath to support Lambda paths if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') {Write-Host '[RUNTIME-bootstrap]Modify PSModulePath to support Lambda paths'} Set-PSModulePath diff --git a/powershell-runtime/source/modules/Private/Find-RuntimePackedModule.ps1 b/powershell-runtime/source/modules/Private/Find-RuntimePackedModule.ps1 index 6d4db7c..8889cd3 100644 --- a/powershell-runtime/source/modules/Private/Find-RuntimePackedModule.ps1 +++ b/powershell-runtime/source/modules/Private/Find-RuntimePackedModule.ps1 @@ -1,9 +1,9 @@ function private:Find-RuntimePackedModule { <# .SYNOPSIS - Tests whether the current runtime environment contains compressed module packages (combined .zip or per-module .nupkg) + Searches runtime environment filesystem for compressed module packages (combined .zip or per-module .nupkg) .DESCRIPTION - Tests whether the current runtime environment contains compressed module packages (combined .zip or per-module .nupkg) + Searches the current runtime environment's filesystem for compressed module packages (combined .zip or per-module .nupkg). Any resolved paths are returned in a dictionary. If nothing is found, no object is returned. .NOTES Looks for module packages in two locations: * /opt/ (Combined Lambda layer directory) @@ -24,56 +24,34 @@ function private:Find-RuntimePackedModule { * /opt/module-nupkgs/AWS.Tools.Common.4.1.833.nupkg * /var/lambda/module-nupkgs/AWS.Tools.Common.4.1.833.nupkg .EXAMPLE - Test-MyTestFunction -Verbose - Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines + PS> Find-RuntimePackedModule + Name Value + ---- ----- + Combined {/opt/modules.zip} + NuPkg {/var/lambda/module-nupkgs/AWS.Tools.Common.4.1.833.nupkg, /var/lambda/module-nupkgs/AWS.Tools.S3.4.1.833.nupkg} #> [CmdletBinding()] param( - # Looks for combined module archives (modules.zip). - [Parameter( - Mandatory, - ParameterSetName="Combined" - )] - [Switch] - $Combined, - - # Looks for individual module packages (*.nupkg). - [Parameter( - Mandatory, - ParameterSetName="NuPkg" - )] - [Switch] - $NuPkg - ) - - $BaseDirectories = @( - "/opt", - $Env:LAMBDA_TASK_ROOT ) - switch ($PSCmdlet.ParameterSetName) { - "Combined" { - - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Test-RuntimePackedModule]Searching for combined module archives" } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Test-RuntimePackedModule]Searching for packed modules" } - $BaseDirectories | Join-Path -ChildPath "modules.zip" | Get-Item -ErrorAction SilentlyContinue | Set-Variable FoundItems - - } - "NuPkg" { - - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Test-RuntimePackedModule]Searching for individual module packages" } + $ResolvedModules = @{ + Combined = $( + $Script:ModulePaths.Packed.Combined.Values | Get-Item -ErrorAction SilentlyContinue + ) + NuPkg = $( + $Script:ModulePaths.Packed.NuPkg.Values | Get-Item -ErrorAction SilentlyContinue + ) + } - $BaseDirectories | Join-Path -ChildPath "module-nupkgs" -AdditionalChildPath "*.nupkg" | Get-Item -ErrorAction SilentlyContinue | Set-Variable FoundItems - } - } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Test-RuntimePackedModule]Found $($ResolvedModules.Combined | Measure-Object | ForEach-Object Count) combined module archive(s)" } + if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Test-RuntimePackedModule]Found $($ResolvedModules.NuPkg | Measure-Object | ForEach-Object Count) individual module package(s)" } - If ($FoundItems) { - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Test-RuntimePackedModule]Found $($FoundItems | Measure-Object | % Count) match(es)" } - return $true - } else { - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Test-RuntimePackedModule]No matches found" } - return $false + # Only return a value if we found either combined or NuPkg module packages + If ($ResolvedModules.Combined -or $ResolvedModules.NuPkg) { + return $ResolvedModules } } \ No newline at end of file diff --git a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 index e19d24e..4b18a8f 100644 --- a/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModuleArchive.ps1 @@ -18,19 +18,27 @@ function private:Import-ModuleArchive { If archives are detected at both locations, they will be extracted over the top of each-other. #> + [CmdletBinding()] + param( + [ValidatePattern(".zip$")] + [ValidateNotNullOrEmpty()] + [Parameter( + Mandatory, + Position = 0 + )] + [System.IO.FileInfo[]]$ArchivePath + ) - $SearchPaths = $Script:ModulePaths.Packed.Combined.Values - - If ($SearchPaths| Where-Object { Test-Path $_ }) { + Begin { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]Creating unpack directory for combined module archives' } - $null = [System.IO.Directory]::CreateDirectory($Script:ModulePaths.Unpacked.Combined) - $SearchPaths | Where-Object { Test-Path $_ } | ForEach-Object { + $UnpackDirectory = [System.IO.Directory]::CreateDirectory($Script:ModulePaths.Unpacked.Combined) + } + + Process { + $ArchivePath | ForEach-Object { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModuleArchive]Unpacking $_ to $UnpackDirectory" } Expand-Archive -LiteralPath $_ -DestinationPath $UnpackDirectory -Force } if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]Archive unpack complete' } } - else { - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModuleArchive]No module archives detected; nothing to do.' } - } } \ No newline at end of file diff --git a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 index 5ab9813..f136351 100644 --- a/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 +++ b/powershell-runtime/source/modules/Private/Import-ModulePackage.ps1 @@ -17,29 +17,47 @@ function private:Import-ModulePackage { * /opt/module-nupkgs/ (Combined Lambda layer directory) * $Env:LAMBDA_TASK_ROOT/module-nupkgs/ (Lambda Function Package deployment directory) #> - $SearchPaths = $Script:ModulePaths.Packed.NuPkg + [CmdletBinding()] + param( + [ValidatePattern(".nupkg$")] + [ValidateNotNullOrEmpty()] + [Parameter( + Mandatory, + Position = 0 + )] + [System.IO.FileInfo[]]$PackagePath + ) - If ($SearchPaths.Values | Where-Object { Test-Path $_ }) { + Begin { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModulePackage]Creating unpack directory for individual module packages' } - [System.IO.Directory]::CreateDirectory($Script:ModulePaths.Unpacked.NuPkg) - $SearchPaths.GetEnumerator() | Where-Object { Test-Path $_.Value } | ForEach-Object { - $PackageDirectory = Split-Path $_.Value -Parent + $UnpackDirectory = [System.IO.Directory]::CreateDirectory($Script:ModulePaths.Unpacked.NuPkg) + } + + Process { + $PackagePath | Group-Object -Property Directory | ForEach-Object { + + # The group key should be the directory for the folder containing the nupkgs. + $PackageDirectory = $_.Name if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Importing module packages from $PackageDirectory" } - $RepositoryName = "Lambda-Local-$($_.Key)" + + # We split-path that directory to strip off "module-nupkgs". + $RepositoryName = "Lambda-Local-$($_.Group | Split-Path -Parent)" + + # Attach a PSResourceGet repository to the directory holding the packages. if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Registering local package repository $RepositoryName" } Register-PSResourceRepository -Name $RepositoryName -Uri $PackageDirectory -Trusted -Priority 1 + + # Then, enumerate all the packages in that repository (again, just a directory) and "save" (install/unpack them) into /tmp. if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Enumerating packages in $PackageDirectory (PSResource repository $RepositoryName)" } Find-PSResource -Name * -Repository $RepositoryName | ForEach-Object -Parallel { if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Saving package $($_.Name) version $($_.Version) (PSResource repository $($using:RepositoryName))" } - $_ | Save-PSResource -SkipDependencyCheck -Path $using:PackageDirectory -Quiet -AcceptLicense -Confirm:$false + $_ | Save-PSResource -SkipDependencyCheck -Path $using:UnpackDirectory -Quiet -AcceptLicense -Confirm:$false } + + # Clean up the local repository config. This doesn't uninstall anything (just edits some XML files in PSResourceGet) if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host "[RUNTIME-Import-ModulePackage]Registering local package repository $RepositoryName" } Unregister-PSResourceRepository -Name $RepositoryName -Confirm:$false } if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModulePackage]Archive unpack complete' } } - else { - if ($env:POWERSHELL_RUNTIME_VERBOSE -eq 'TRUE') { Write-Host '[RUNTIME-Import-ModulePackage]No module archives detected; nothing to do.' } - } - } \ No newline at end of file