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 ship as .NET-Framework assemblies (loadable only by Windows PowerShell) through BC28, and as .NET 8 assemblies (loadable only by PowerShell 7 / pwsh) from BC24 onwards. BC24-BC28 ship both, so we stay on 'powershell' - the long-proven path. BC29 removed the Windows PowerShell 5 compatibility module (Microsoft.Dynamics.Nav.Management.dll under ...\Service\Management; it disappeared between insider builds 29.0.52169.0 and 29.0.53000.0), leaving only the .NET 8 Microsoft.BusinessCentral.*.Management.dll under ...\Service\Admin - so from BC29 we must use 'pwsh', which the generic image ships (7.6 on PATH). Override with the ALBUILD_CONTAINER_POWERSHELL environment variable (e.g. to force 'pwsh' for testing the .NET path on a BC28 image). The legacy probe matches the two assembly names EXACTLY. A wildcard such as 'Microsoft.Dynamics.Nav.*Management.dll' also matches the unrelated Microsoft.Dynamics.Nav.Client.PowerBIManagement.dll, which BC29 still ships - that false positive kept BC29 on Windows PowerShell and made every container app operation fail with "Get-NAVAppInfo : The term ... is not recognized". .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. # -Include with the exact file names, NOT a wildcard -Filter: see the false-positive note above. $legacy = Invoke-BcDocker -DockerExecutable $DockerExecutable -Quiet -PassThru -Arguments @( 'exec', $Name, 'powershell', '-NoProfile', '-Command', "[bool]@(Get-ChildItem 'C:\Program Files\Microsoft Dynamics NAV' -Recurse -Include 'Microsoft.Dynamics.Nav.Management.dll','Microsoft.Dynamics.Nav.Apps.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 } |