Modules/businessdev.ALbuild.OnPrem/Private/Import-BcManagementShell.ps1
|
function Import-BcManagementShell { <# .SYNOPSIS Loads the Business Central administration shell (Publish-NAVApp / Sync-NAVApp / Install-NAVApp / Get-NAVAppInfo / ...) into the current session. .DESCRIPTION The on-prem cmdlets are provided by the BC server's management assemblies, which are NOT on PSModulePath and are therefore not auto-loaded. Without this, an on-prem publish fails with "The term 'Publish-NAVApp' is not recognized". Mirrors the AL.build V1 ReleaseOnPrem behaviour: if the shell is already present it is reused; otherwise the management assemblies are located under the BC install tree and imported (modern 'Microsoft.BusinessCentral.*' first, then the legacy 'Microsoft.Dynamics.Nav.*' names for older versions). Progress is logged in detail (every search root, every assembly imported and from where) so a failure on a customer agent is diagnosable from the pipeline log alone. .PARAMETER SentinelCommand The command whose presence proves the shell is loaded. Default 'Publish-NAVApp' (the cmdlet the on-prem publish actually needs). .PARAMETER SearchRoot Glob root(s) under which to search for the management assemblies. .OUTPUTS None. Throws a clear, actionable error listing the searched locations if the shell cannot be loaded. #> [CmdletBinding()] param( [string] $SentinelCommand = 'Publish-NAVApp', [string[]] $SearchRoot = @( 'C:\Program Files\Microsoft Dynamics*\*\Service\', 'C:\Program Files (x86)\Microsoft Dynamics*\*\Service\' ) ) if (Get-Command -Name $SentinelCommand -ErrorAction SilentlyContinue) { Write-ALbuildLog "BC management shell already loaded ('$SentinelCommand' available); reusing it." return } Write-ALbuildLog "BC management shell not loaded ('$SentinelCommand' missing); locating the management assemblies..." # Modern (BC15+) assemblies first, then the legacy NAV names for older on-prem versions. Each set # provides the server (…Management) + app (…Apps.Management) cmdlets we call. $moduleSets = @( @('Microsoft.BusinessCentral.Management.dll', 'Microsoft.BusinessCentral.Apps.Management.dll'), @('Microsoft.Dynamics.Nav.Management.dll', 'Microsoft.Dynamics.Nav.Apps.Management.dll') ) $searched = [System.Collections.Generic.List[string]]::new() $importedAny = $false foreach ($set in $moduleSets) { foreach ($dll in $set) { foreach ($root in $SearchRoot) { # String-concatenate (roots end in a separator) rather than Join-Path: Join-Path # resolves the 'C:' qualifier and throws "drive 'C' does not exist" on non-Windows # agents (the module is loaded/tested on the Linux CI leg, though it only runs for real # on a Windows BC server). $searched.Add($root + $dll) $found = @() # NOTE: do NOT add -File here. With a wildcard '...\*\Service\' path + -Recurse, -File makes # Get-ChildItem return nothing (PowerShell quirk), so the assemblies are never found - which # is exactly why V1/the reference installer omit it. Filter out directories in the loop instead. try { $found = @(Get-ChildItem -Path $root -Filter $dll -Recurse -ErrorAction SilentlyContinue | Where-Object { -not $_.PSIsContainer }) } catch { $found = @() } # a Windows-only root throws 'drive not found' off Windows; treat as no match foreach ($f in $found) { Write-ALbuildLog " importing '$($f.Name)' from '$($f.Directory.FullName)'." try { Import-Module -Name $f.FullName -Force -Global -DisableNameChecking -ErrorAction Stop $importedAny = $true } catch { Write-ALbuildLog -Level Warning " failed to import '$($f.FullName)': $($_.Exception.Message)." } } } } # Stop at the first assembly set that yields the cmdlet we need. if (Get-Command -Name $SentinelCommand -ErrorAction SilentlyContinue) { break } } if (-not (Get-Command -Name $SentinelCommand -ErrorAction SilentlyContinue)) { $hint = if ($importedAny) { "Assemblies were found and imported but '$SentinelCommand' is still unavailable - the installed BC version may use different module names." } else { 'No BC management assemblies were found under the search roots - the BC server (or its management tools) does not appear to be installed on this agent.' } throw ("Could not load the Business Central management shell. $hint" + [Environment]::NewLine + "Searched: $(($searched | Select-Object -Unique) -join '; ')") } Write-ALbuildLog -Level Success "BC management shell loaded ('$SentinelCommand' now available)." } |