Modules/businessdev.ALbuild.Containers/Private/Get-BcContainerPowerShellExe.ps1
|
function Get-BcContainerPowerShellExe { <# .SYNOPSIS Resolves which in-container PowerShell host ('powershell' or 'pwsh') to run BC management commands under, for one container. Cached per container. .DESCRIPTION The BC management cmdlets are provided by .NET-Framework assemblies (loadable only by Windows PowerShell) up to ~BC27, and by .NET 8 assemblies (loadable only by PowerShell 7 / pwsh) from BC28. While a container still ships the legacy Microsoft.Dynamics.Nav.*.Management.dll we keep using 'powershell' - the long-proven path. Only when those are gone (a future .NET-only image) do we fall back to 'pwsh', which ships in modern BC containers and loads the .NET 8 Microsoft.BusinessCentral.*.Management.dll. Override with the ALBUILD_CONTAINER_POWERSHELL environment variable (e.g. to force 'pwsh' for testing the .NET path on a BC28 image). NOTE (provisional): the pwsh branch is forward-looking scaffolding. On BC28 the legacy assemblies still ship, so this returns 'powershell' and the pwsh path is not yet exercised in production. pwsh + Microsoft.BusinessCentral.*.Management.dll has been verified to work for the management cmdlets directly, but the full encoded-command round-trip under the container's PowerShell 7 needs validation against a real .NET-only BC image before this can be relied on - see the design notes. .PARAMETER Name Container name. .PARAMETER DockerExecutable The Docker executable to use (default 'docker'). .OUTPUTS System.String - 'powershell' or 'pwsh'. #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Name, [string] $DockerExecutable = 'docker' ) if (-not [string]::IsNullOrWhiteSpace($env:ALBUILD_CONTAINER_POWERSHELL)) { return $env:ALBUILD_CONTAINER_POWERSHELL } # StrictMode-safe lazy init (the script-scope var may not exist yet). if (-not (Test-Path 'variable:script:BcContainerHostCache')) { $script:BcContainerHostCache = @{} } if ($script:BcContainerHostCache.ContainsKey($Name)) { return $script:BcContainerHostCache[$Name] } $exe = 'powershell' try { # Probe (with Windows PowerShell, which is always present) whether the legacy .NET-Framework NAV # management DLLs still ship. If so, stay on 'powershell'. Otherwise, prefer 'pwsh' when present. $legacy = Invoke-BcDocker -DockerExecutable $DockerExecutable -Quiet -PassThru -Arguments @( 'exec', $Name, 'powershell', '-NoProfile', '-Command', "[bool]@(Get-ChildItem 'C:\Program Files\Microsoft Dynamics NAV' -Recurse -Filter 'Microsoft.Dynamics.Nav.*Management.dll' -ErrorAction SilentlyContinue).Count") $hasLegacy = $legacy.Success -and ("$($legacy.StdOut)".Trim() -eq 'True') if (-not $hasLegacy) { $pwsh = Invoke-BcDocker -DockerExecutable $DockerExecutable -Quiet -PassThru -SuccessExitCodes @(0, 1) -Arguments @( 'exec', $Name, 'cmd', '/c', 'where pwsh') if ($pwsh.ExitCode -eq 0 -and -not [string]::IsNullOrWhiteSpace($pwsh.StdOut)) { $exe = 'pwsh' } } } catch { $exe = 'powershell' } $script:BcContainerHostCache[$Name] = $exe return $exe } |