Functions/ModuleManagement/Get-BcModule.ps1
function Get-BcModule { [CmdletBinding(DefaultParameterSetName='ServerInstance')] Param ( # Gets the modules compatible with the supplied serverinstance. [Parameter(ParameterSetName='ServerInstance', Mandatory = $true)] [string] $ServerInstance, # Gets the modules compatible with the supplied BcVersion. E.g. 'bc15' or 'bc13'. [Parameter(ParameterSetName='BcVersion', Mandatory = $true)] [string] $BcVersion, # Gets the modules compatible with the supplied BC Service installation path. [Parameter(ParameterSetName='BcInstallationPath', Mandatory = $true)] [string] $BcInstallationPath, # The target computers to retrieve the BC module paths from. [string] $Computer = $env:COMPUTERNAME, [switch] $ManagementModule, [switch] $AppManagementModule, [switch] $AppToolsModule, [switch] $ModelToolsModule ) Write-Verbose ('hostname: {0}, computer: {1}, PSVersion {2}' -f $env:COMPUTERNAME, $Computer, $PSVersionTable.PsVersion.Major) # If not a specific module is specified import all modules. if( $ManagementModule -eq $false -and $AppManagementModule -eq $false -and $AppToolsModule -eq $false -and $ModelToolsModule -eq $false) { $ManagementModule = $true $AppManagementModule = $true $AppToolsModule = $true $ModelToolsModule = $true } if($BcVersion){ if((Get-BcVersion -BcVersion $BcVersion) -eq $false){ "The supplied BC/NAV version '{0}' is not valid. Valid values are for example 'BC15', 'BC13', 'NAV2017'" -f $BcVersion | Write-Warning return } [hashtable] $BcVersion = Get-BcVersion -BcVersion $BcVersion } # Get BC version from Service if($ServerInstance){ $ServerInstanceConfig = Get-BCServerInstance -ServerInstance $ServerInstance -Computer $Computer -WarningAction SilentlyContinue if(-not $ServerInstanceConfig -or $ServerInstanceConfig.Version -eq '1.0.0.0'){ 'Could not look up the version number for Server Instance ''{0}''. Make sure the Server Instance exists and the installation is valid.' -f $ServerInstance | Write-Warning return } $BcVersionFolder = ([version] $ServerInstanceConfig.Version).Major * 10 #([version](Get-BCServerInstance -ServerInstance $ServerInstance).Version).Major * 10 [hashtable] $BcVersion = Get-BcVersion -VersionFolder $BcVersionFolder } # Get BC version from installation directory if($BcInstallationPath){ $regex = '.*\\(?<VersionFolder>\d{3})\\.*' $match = [regex]::Match($BcInstallationPath, $regex); if ($match.Success){ $versionFolder = ($match.Groups | Where-Object Name -eq 'VersionFolder').Value [hashtable] $BcVersion = Get-BcVersion -VersionFolder $versionFolder } } # Validate PowerShell version if ($BcVersion.VersionFolder -ge 240 -and $PSVersionTable.PSVersion.Major -lt 7) { Write-Warning 'Searching for the BC PowerShell 5 legacy modules because the current PowerShell session is lower than version 7.' } if ($BcVersion.VersionFolder -ge 260 -and $PSVersionTable.PSVersion.Major -lt 7) { Write-Error 'PowerShell modules compatible with PowerShell 5 are not available for BC26 and up.' return } # Disable app modules for Dynamics NAV. if($BcVersion.ProductAbb -eq 'NAV'){ $AppManagementModule = $false $AppToolsModule = $false } # Disable model tools, merged into management module in bc18 if([int] $BcVersion.VersionFolder -gt 170){ $ModelToolsModule = $false } # Get installation folders $BcComponent = Get-BcComponent -BcVersion $BcVersion.Version -Computer $Computer $Service = $BcComponent | Where-Object Component -eq 'NST' if([int] $BcVersion.VersionFolder -lt 180){ $Rtc = $BcComponent | Where-Object Component -eq 'RTC' } if (-not $Service.IsInstalled) { Write-Warning 'Cannot find the BC installation folder in the Windows Registery.' $Service.InstallLocation = 'C:\Program Files\Microsoft Dynamics 365 Business Central\{0}\Service' -f $BcVersion.VersionFolder } if($BcInstallationPath){ $Service.InstallLocation = $BcInstallationPath } # Convert installation path to UNC path if it's on a remote computer. if ($Computer -ne 'localhost' -and $Computer -ne $env:COMPUTERNAME) { $servicePath = $Service.InstallLocation | ConvertTo-UncPath -Computer $Computer if($rtc.InstallLocation){ $rtcPath = $rtc.InstallLocation | ConvertTo-UncPath -Computer $Computer } } else { $servicePath = $Service.InstallLocation $rtcPath = $rtc.InstallLocation } if((Test-Path $servicePath) -eq $false){ Write-Warning 'Cannot find the BC installation folder on the default location. Make sure the BC server component is installed.' return $false } $Modules = @() if($ManagementModule){ if($BcVersion.VersionFolder -ge 240 -and $PSVersionTable.PSVersion.Major -ge 7){ $Modules +='Microsoft.BusinessCentral.Management' } else { $Modules += 'Microsoft.Dynamics.Nav.Management' } } if($AppManagementModule){ if($BcVersion.VersionFolder -ge 240 -and $PSVersionTable.PSVersion.Major -ge 7){ $Modules +='Microsoft.BusinessCentral.Apps.Management' } else { $Modules += 'Microsoft.Dynamics.Nav.Apps.Management' } } if($AppToolsModule){ if($BcVersion.VersionFolder -ge 240 -and $PSVersionTable.PSVersion.Major -ge 7){ $Modules +='Microsoft.BusinessCentral.Apps.Tools' } else { $Modules += 'Microsoft.Dynamics.Nav.Apps.Tools' } } if($ModelToolsModule){ $Modules += 'Microsoft.Dynamics.Nav.Model.Tools' } $ModulesPath = @() foreach($Module in $Modules){ $ModulePath = (Get-ChildItem (Join-Path -Path $servicePath -ChildPath ($Module + ".psd1")) -Recurse).fullname if($ModulePath -and (Test-Path -Path $ModulePath)){ $ModulesPath += $ModulePath; continue } if($BcVersion.VersionFolder -ge 240 -and $PSVersionTable.PSVersion.Major -lt 7){ $ModulePath = (Get-ChildItem (Join-Path -Path $servicePath -ChildPath ($Module + ".psm1")) -ErrorAction SilentlyContinue).fullname } else { $ModulePath = (Get-ChildItem (Join-Path -Path $servicePath -ChildPath ($Module + ".psm1")) -Recurse).fullname } if($ModulePath -and (Test-Path -Path $ModulePath)){ $ModulesPath += $ModulePath; continue } if($rtcPath){ $ModulePath = (Get-ChildItem (Join-Path -Path $rtcPath -ChildPath ($Module + ".psd1")) -Recurse).fullname } if($ModulePath -and (Test-Path -Path $ModulePath)){ $ModulesPath += $ModulePath; continue } 'Could not find module {0}.' -f $Module | Write-Warning } # Workaround BC24.4 FormatsToProcess file name issue if ('Microsoft.BusinessCentral.Apps.Tools.psd1' -in ($ModulesPath | Split-Path -Leaf)){ $appMgntPath = Join-Path (($ModulesPath | Where-Object { $_ -like '*\Microsoft.BusinessCentral.Apps.Tools.psd1'}) | Split-Path -Parent) 'Microsoft.BusinessCentral.Apps.Tools.format.ps1xml' if((Test-Path $appMgntPath) -eq $false){ $appMgntPathOld = Join-Path ($appMgntPath | Split-Path -Parent) 'Microsoft.Dynamics.Nav.Apps.Tools.format.ps1xml' if(Test-Path $appMgntPathOld){ 'Workaround applied. Renamed "{0}" to "{1}".' -f $appMgntPathOld, $appMgntPath | Write-Host Rename-Item -Path $appMgntPathOld -NewName $appMgntPath } } } if ('Microsoft.BusinessCentral.Management.psd1' -in ($ModulesPath | Split-Path -Leaf)){ $appMgntPath = Join-Path (($ModulesPath | Where-Object { $_ -like '*\Microsoft.BusinessCentral.Management.psd1'}) | Split-Path -Parent) 'Microsoft.BusinessCentral.Apps.Management.format.ps1xml' if((Test-Path $appMgntPath) -eq $false){ $appMgntPathOld = Join-Path ($appMgntPath | Split-Path -Parent) 'Microsoft.Dynamics.Nav.Apps.Management.format.ps1xml' if(Test-Path $appMgntPathOld){ 'Workaround applied. Renamed "{0}" to "{1}".' -f $appMgntPathOld, $appMgntPath | Write-Host Rename-Item -Path $appMgntPathOld -NewName $appMgntPath } } } # End workaround $ModulesPath | ConvertTo-LocalPath } Export-ModuleMember -Function Get-BcModule function ConvertTo-UncPath { Param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [string[]] $Path, [string] $Computer = $env:COMPUTERNAME ) begin{ $Paths = @() } process { foreach($Item in $Path){ if($Item -match '\\\\'){ $Paths += $Item continue } $Qualifier = $Item | Split-Path -Qualifier $NewQualifier = '\\{0}\{1}' -f $Computer, $Qualifier.Replace(':','$').ToLower() $NewPath = $Item.Replace($Qualifier, $NewQualifier) $Paths += $NewPath } } end{ $Paths } } function ConvertTo-LocalPath { Param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [string[]] $Path ) begin{ $Paths = @() } process { foreach($Item in $Path){ if($Item -notmatch '\\\\'){ $Paths += $Item continue } $Drive = [System.IO.Path]::GetPathRoot($Item) $Dumps = $Item.Substring($Drive.Length) $Drive = $Drive.Substring($Drive.LastIndexOf('\') + 1).Replace('$',':') $Paths += "{0}{1}" -f $Drive.ToUpper(), $Dumps } } end{ $Paths } } |