Get-ALOpsBCManagementDlls.ps1
|
function Get-ALOpsBCModuleManifestRoot() { param( [string] $ManifestPath ) # Returns the RootModule declared by a PowerShell module manifest, so the caller can tell a # pure-PowerShell module (BC 29 and later, RootModule = *.psm1) from a manifest that only wraps # a binary module (BC 28 Admin folder, RootModule = *.dll). Empty when it cannot be determined. $RootModule = "" try { $Manifest = Import-PowerShellDataFile -Path $ManifestPath -ErrorAction Stop $RootModule = "$($Manifest.RootModule)" if ([string]::IsNullOrEmpty($RootModule)){ $RootModule = "$($Manifest.ModuleToProcess)" } } catch { foreach ($Line in (Get-Content -Path $ManifestPath -ErrorAction SilentlyContinue)){ $Trimmed = "$($Line)".Trim() if ($Trimmed.StartsWith("RootModule") -or $Trimmed.StartsWith("ModuleToProcess")){ $Parts = $Trimmed.Split("=") if ($Parts.Count -gt 1){ $RootModule = $Parts[1].Trim().Trim("'").Trim('"') break } } } } return $RootModule } function Get-ALOpsBCManagementDlls() { param( [string] $SearchPath ) # Copy of the ALOps helper (ALOps repo, PSModules\ALOpsV2\Get-ALOpsBCManagementDlls.ps1); keep in sync. # Locate the Business Central / NAV management PowerShell modules (GitHub #998, #1016). # Tier 1: Microsoft.BusinessCentral.Management.dll outside the Admin folder (BC24+ preview layout). # Tier 2: Microsoft.Dynamics.Nav.Management.dll (BC14-BC28, .NET Framework build, loads in PS 5.1 and PS7). # Tier 3: the Service\Admin folder (BC29+). BC29 ships Microsoft's pure-PowerShell modules (.psd1 + .psm1, # REST based) next to a .NET 10 binary that can no longer be imported in either PowerShell edition. # The module manifest is therefore preferred; the .dll stays as fallback for a BC28 Admin layout. # The Apps module follows the tier of the management module so BC14-BC28 behaviour stays unchanged: # on BC24-BC28 the Admin folder also holds a PowerShell 7 only Apps module that must NOT be picked up. $Tier = 0 $ManagementDll = $null $AppsManagementDll = $null $IsModuleManifest = $false if (-not [string]::IsNullOrEmpty($SearchPath)){ $ManagementDll = Get-ChildItem -Path $SearchPath -Filter "Microsoft.BusinessCentral.Management.dll" -Recurse -ErrorAction SilentlyContinue | Where-Object { ($_.FullName -notmatch '[\\/]Admin[\\/]') -and (-not $_.FullName.Contains("LegacyDlls")) } | Select-Object -First 1 if ($null -ne $ManagementDll){ $Tier = 1 } else { $ManagementDll = Get-ChildItem -Path $SearchPath -Filter "Microsoft.Dynamics.Nav.Management.dll" -Recurse -ErrorAction SilentlyContinue | Where-Object { -not $_.FullName.Contains("LegacyDlls") } | Select-Object -First 1 if ($null -ne $ManagementDll){ $Tier = 2 } else { # Only treat the manifest as the target when it really is a script module: the BC 28 # Admin manifest wraps the binary and must keep the PowerShell 7 handling below. $ManifestCandidate = Get-ChildItem -Path $SearchPath -Filter "Microsoft.BusinessCentral.Management.psd1" -Recurse -ErrorAction SilentlyContinue | Where-Object { -not $_.FullName.Contains("LegacyDlls") } | Select-Object -First 1 if (($null -ne $ManifestCandidate) -and ((Get-ALOpsBCModuleManifestRoot -ManifestPath $ManifestCandidate.FullName) -notlike "*.dll")){ $ManagementDll = $ManifestCandidate $Tier = 3 $IsModuleManifest = $true } else { $ManagementDll = Get-ChildItem -Path $SearchPath -Filter "Microsoft.BusinessCentral.Management.dll" -Recurse -ErrorAction SilentlyContinue | Where-Object { -not $_.FullName.Contains("LegacyDlls") } | Select-Object -First 1 if ($null -ne $ManagementDll){ $Tier = 3 } } } } if ($Tier -eq 3){ if ($IsModuleManifest){ $AppsCandidate = $null $Candidate = Join-Path -Path $ManagementDll.DirectoryName -ChildPath "Microsoft.BusinessCentral.Apps.Management.psd1" if (Test-Path -Path $Candidate){ $AppsCandidate = Get-Item -Path $Candidate } else { $AppsCandidate = Get-ChildItem -Path $SearchPath -Filter "Microsoft.BusinessCentral.Apps.Management.psd1" -Recurse -ErrorAction SilentlyContinue | Where-Object { -not $_.FullName.Contains("LegacyDlls") } | Select-Object -First 1 } if (($null -ne $AppsCandidate) -and ((Get-ALOpsBCModuleManifestRoot -ManifestPath $AppsCandidate.FullName) -notlike "*.dll")){ $AppsManagementDll = $AppsCandidate } } if ($null -eq $AppsManagementDll){ $Candidate = Join-Path -Path $ManagementDll.DirectoryName -ChildPath "Microsoft.BusinessCentral.Apps.Management.dll" if (Test-Path -Path $Candidate){ $AppsManagementDll = Get-Item -Path $Candidate } else { $AppsManagementDll = Get-ChildItem -Path $SearchPath -Filter "Microsoft.BusinessCentral.Apps.Management.dll" -Recurse -ErrorAction SilentlyContinue | Where-Object { -not $_.FullName.Contains("LegacyDlls") } | Select-Object -First 1 } } } elseif ($Tier -gt 0){ $AppsManagementDll = Get-ChildItem -Path $SearchPath -Filter "Microsoft.BusinessCentral.Apps.Management.dll" -Recurse -ErrorAction SilentlyContinue | Where-Object { ($_.FullName -notmatch '[\\/]Admin[\\/]') -and (-not $_.FullName.Contains("LegacyDlls")) } | Select-Object -First 1 if ($null -eq $AppsManagementDll){ $AppsManagementDll = Get-ChildItem -Path $SearchPath -Filter "Microsoft.Dynamics.Nav.Apps.Management.dll" -Recurse -ErrorAction SilentlyContinue | Where-Object { -not $_.FullName.Contains("LegacyDlls") } | Select-Object -First 1 } } } $TierLabel = "" switch ($Tier) { 1 { $TierLabel = "tier 1, BusinessCentral" } 2 { $TierLabel = "tier 2, Dynamics.Nav" } 3 { if ($IsModuleManifest){ $TierLabel = "tier 3, Admin folder, PowerShell module manifest" } else { $TierLabel = "tier 3, Admin folder, PowerShell 7 module" } } } if ($Tier -eq 0){ Write-Host "*** BC Management DLL: not found under [$($SearchPath)]" } else { Write-Host "*** BC Management DLL [$($TierLabel)]: $($ManagementDll.FullName)" } # The BC29 module manifest is pure PowerShell and imports in Windows PowerShell 5.1 as well as in # PowerShell 7; only the binary fallback is PowerShell 7 only. $RequiresPowerShell7 = (($Tier -eq 3) -and (-not $IsModuleManifest)) if ($RequiresPowerShell7 -and ($PSVersionTable.PSEdition -ne "Core")){ Write-Warning "The Business Central management module [$($ManagementDll.FullName)] is a PowerShell 7 binary module. This session runs Windows PowerShell $($PSVersionTable.PSVersion). Run the command in PowerShell 7 or make sure PowerShell 7 is installed in the container." } return [PSCustomObject]@{ ManagementDll = $ManagementDll AppsManagementDll = $AppsManagementDll Tier = $Tier IsModuleManifest = $IsModuleManifest RequiresPowerShell7 = $RequiresPowerShell7 } } |