This manual applies only to the on-premises installation of Anywhere Mobility Solutions. Download the installation package and unzip it. This manual covers the installation of the Anywhere Mobility Solutions APP on the framework part. For the installation of the Anywhere Mobility Solutions portal, see: Portal installation.
Before installing Anywhere Mobility Solutions for Microsoft Dynamics 365 D365 BC, take care of the server installation requirements defined at: Installation requirements
Note
Run the unpacking and installation process on the same machine with the same environment to prevent Windows security from blocking the executables.
Using Windows PowerShell for the installation
The script below installs the app in Windows PowerShell. STAEDEAN does not provide support on this script, see disclaimer on: Installation of STAEDEAN add-ons. Partners are expected to have the knowledge to install an app/extension for Microsoft Dynamics 365 D365 BC.
# Set the variables before running the script$serverInstance = 'BC150'$AppsFolder = 'C:\users\\desktop\NewApps'#Optional: Create a list of the requested apps, this ensures that only the apps in the list are installed and not all the apps in the $AppsFolder#When omitting this step, all the apps available in the directory will be installed#Remove the # prefix from TIApps#$TIApps = "TI-Common" #Mandatory for All TI Apps#BIS (BIS is part of the underlayer in ANY framework)#$TIApps += ",TI-BIS"#ANY #$TIANYApps# When running this script in a seperate session in ISE the user need to import the modules againImport-Module"C:\Program Files\Microsoft Dynamics 365 Business Central\150\Service\Microsoft.Dynamics.Nav.Apps.Management.psd1"Import-Module"C:\Program Files\Microsoft Dynamics 365 Business Central\150\Service\Microsoft.Dynamics.Nav.Management.psd1"# The installation script publishes and installs the TI apps in the correct sequencefunctionSort-AppFoldersByDependencies {
Param(
[Parameter(Mandatory=$true)]
[string[]] $appFolders,
[Parameter(Mandatory=$false)]
[string] $baseFolder = "",
[Parameter(Mandatory=$false)]
[ref] $unknownDependencies
)
if ($baseFolder) {
$baseFolder = $baseFolder.TrimEnd('\')+'\'
}
# Read all app.json objects, populate $apps$apps = $()
$folders = @{}
$appFolders | ForEach-Object {
$appFolder = "$baseFolder$_"$appJsonFile = Join-Path$appFolder"app.json"if (-not (Test-Path-Path$appJsonFile)) {
Write-Warning"$appFolder doesn't contain app.json"
}
else {
$appJson = Get-Content-Path$appJsonFile | ConvertFrom-Json$alreadyAdded = $apps | Where-Object { $_.Id -eq$appJson.Id }
if (-not ($alreadyAdded)) {
$folders += @{ "$($appJson.Id)" = $appFolder }
$apps += @($appJson)
}
}
}
# Populate SortedApps and UnresolvedDependencies$script:sortedApps = @()
$script:unresolvedDependencies = $()
functionAddAnApp { Param($anApp)
$alreadyAdded = $script:sortedApps | Where-Object { $_.Id -eq$anApp.Id }
if (-not ($alreadyAdded)) {
AddDependencies -anApp$anApp$script:sortedApps += $anApp
}
}
functionAddDependency { Param($dependency)
$dependentApp = $apps | Where-Object { $_.Id -eq$dependency.AppId }
if ($dependentApp) {
AddAnApp -AnApp$dependentApp
}
else {
if (-not ($script:unresolvedDependencies | Where-Object { $_-and$_.AppId -eq$dependency.AppId })) {
Write-Warning"Dependency $($dependency.appId):$($dependency.publisher.Replace('/',''))_$($dependency.name.Replace('/',''))_$($dependency.version)).app not found"$script:unresolvedDependencies += @($dependency)
}
}
}
functionAddDependencies { Param($anApp)
if (($anApp) -and ($anApp.Dependencies)) {
$anApp.Dependencies | ForEach-Object { AddDependency -Dependency$_ }
}
}
$apps | ForEach-Object { AddAnApp -AnApp$_ }
$script:sortedApps | ForEach-Object {
($folders[$_.id]).SubString($baseFolder.Length)
}
if ($unknownDependencies) {
$unknownDependencies.value = @($script:unresolvedDependencies | ForEach-Object { if ($_) { "$($_.appId):$($_.publisher.Replace('/',''))_$($_.name.Replace('/',''))_$($_.version).app" } })
}
}
functionGetAppFolders {
Param(
[Parameter(Mandatory = $true)]
[string]$baseFolder,
[Parameter(Mandatory = $false)]
[string]$apps
)
$appFolders = ''$AllAppJsonFiles = Get-ChildItem-Path$baseFolder-Filter"app.json"-Recurseforeach ($AllAppJsonFilein$AllAppJsonFiles) {
$a = Get-Content$AllAppJsonFile.fullname | ConvertFrom-Jsonif (($apps.Split(',') -contains ($a | Select-Object-expand name)) -or ($apps-eq'')) {
Set-Location$baseFolder$relativePath = Get-Item$AllAppJsonFile.PSParentPath | Resolve-Path-Relativeif ($appFolders) {
$appFolders = $appFolders + ',' + $relativePath.Substring(2)
}
else {
$appFolders = $relativePath.Substring(2)
}
}
}
return$appFolders.Replace('\', '/')
}
$appFolders = GetAppFolders -baseFolder$AppsFolder-apps$TIApps$appFoldersSort-AppFoldersByDependencies-appFolders$appFolders.Split(',') -baseFolder$buildArtifactFolder-WarningAction SilentlyContinue | ForEach-Object {
Write-Host"Publishing $_"Get-ChildItem-Path (Join-Path$AppsFolder$_) -Filter"*.app" | ForEach-Object {
Publish-NAVApp-Path$_.FullName -ServerInstance$serverInstance$name = (Get-Content (Join-Path (Split-Path$_.FullName) ('app.json')) | ConvertFrom-Json | Select-Object-expand name)
$version = (Get-Content (Join-Path (Split-Path$_.FullName) ('app.json')) | ConvertFrom-Json | Select-Object-expand version)
Sync-NAVApp-Name$name-ServerInstance$serverInstance-Version$versionInstall-NAVApp-Name$name-ServerInstance$serverInstance-Version$version
}
}
End of script
Note
Register Codeunit 11158646 (ANY function list 2) for ANYWHERE.
Register Codeunit 11070243 (BIS function list 2) for Business Integration Solutions.