Modules/businessdev.ALbuild.Containers/Private/ConvertTo-BcEncodedCommand.ps1
|
function ConvertTo-BcEncodedCommand { <# .SYNOPSIS Builds a Base64 -EncodedCommand payload for running a script block inside a container. .DESCRIPTION Internal, pure helper. Prepends a strict error preference, an import of the Business Central management module (the 'docker exec ... powershell -NoProfile' session does not load it, so NAV cmdlets such as Publish-NAVApp would otherwise be unrecognised) and optional variable assignments (passed as JSON to survive the process boundary), then UTF-16LE/Base64 encodes the result for 'powershell -EncodedCommand'. Pure (no I/O), so it is unit-testable. #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [scriptblock] $ScriptBlock, [hashtable] $Variables = @{}, # Return the assembled script text instead of the Base64 payload. The caller can then decide # whether to pass it via -EncodedCommand or - for scripts too long for the command line - via # a staged -File. [switch] $AsText ) # Make the BC management cmdlets (Get-NAVAppInfo, Publish-/Sync-/Install-NAVApp, Get-NAVServerInstance, # ...) available inside the container; the 'docker exec' session does not auto-load them. Both the # assembly NAME/location and the PowerShell edition that can load it vary by BC version: # Windows PowerShell (.NET Framework) -> Microsoft.Dynamics.Nav.*.Management.dll (BC <= ~27) # PowerShell 7 (.NET) -> Microsoft.BusinessCentral.*.Management.dll (BC 28+, .NET 8) # Pick the assemblies matching the running edition (a .NET 8 DLL won't load in Windows PowerShell and # vice versa), search recursively (location moved across versions), and import each until both the app # and server cmdlets resolve. Tolerant (no throw) so commands needing no NAV cmdlets still run. $importNavManagement = @' if (-not (Get-Command 'Get-NAVAppInfo' -ErrorAction SilentlyContinue) -or -not (Get-Command 'Get-NAVServerInstance' -ErrorAction SilentlyContinue)) { $__navDllNames = if ($PSVersionTable.PSEdition -eq 'Core') { @('Microsoft.BusinessCentral.Apps.Management.dll', 'Microsoft.BusinessCentral.Management.dll', 'Microsoft.Dynamics.Nav.Apps.Management.dll', 'Microsoft.Dynamics.Nav.Management.dll') } else { @('Microsoft.Dynamics.Nav.Apps.Management.dll', 'Microsoft.Dynamics.Nav.Management.dll') } foreach ($__navDll in $__navDllNames) { if ((Get-Command 'Get-NAVAppInfo' -ErrorAction SilentlyContinue) -and (Get-Command 'Get-NAVServerInstance' -ErrorAction SilentlyContinue)) { break } foreach ($__navFile in @(Get-ChildItem 'C:\Program Files\Microsoft Dynamics NAV' -Recurse -Filter $__navDll -ErrorAction SilentlyContinue)) { try { Import-Module $__navFile.FullName -DisableNameChecking -ErrorAction Stop } catch { } } } } '@ $sb = [System.Text.StringBuilder]::new() [void]$sb.AppendLine('$ErrorActionPreference = ''Stop''') [void]$sb.AppendLine($importNavManagement) foreach ($key in $Variables.Keys) { $json = ($Variables[$key] | ConvertTo-Json -Compress -Depth 20) $escaped = $json -replace "'", "''" [void]$sb.AppendLine("`$$key = '$escaped' | ConvertFrom-Json") } [void]$sb.AppendLine($ScriptBlock.ToString()) if ($AsText) { return $sb.ToString() } $bytes = [System.Text.Encoding]::Unicode.GetBytes($sb.ToString()) return [System.Convert]::ToBase64String($bytes) } |