V24, here you go!

Last 5th of April, Microsoft released Business Central 2024 wave 1 (V24) for On Premises environments. As known, who use BC in Cloud don’t have to worry about upgrading: Microsoft will do it automatically.

In the last post I made some suggestions about “fast-upgrade” On Premises with Cumulative Updates. Now I want to share with you a similar approach also for major updates.

I remind you that V23 will no longer receive new features by Microsoft, now that V24 is released, so if you just upgraded to V23… you are already old! 😁

Notice

The following method must be adapted to your specific environment. Many steps are made at the same time, so doing a rollback could be impossibile. Try first on your test environment!

Here the Microsoft offical upgrade guide: Upgrading Microsoft System and Base Application to Version 24 – Business Central | Microsoft Learn

Step 1 – Uninstall previous version

Start the “Fast-Upgrade” Powershell script and select 1) to uninstall all APPs.

For each Web Server Instance, backup the “navsettings.json” file (common path is “C:\inetpub\wwwroot\INSTANCENAME“).

For each Service Instance, backup the “CustomSettings.config” file (common path is “C:\Program Files\Microsoft Dynamics 365 Business Central\VERSION\Service\Instances\INSTANCENAME“).

Remove all Web Server Instances with “Remove-NAVWebServerInstance” command.

Remove all Instances (except the default one) with “Remove-NAVServerInstance” command.

From the Control Panel, uninstall the previous version of Business Central and cleanup the filesystem from orphans files and directories.

Step 2 – Install new version

You can download the V24 On Premise version from here: Download Microsoft Dynamics 365 Business Central 2024 Release Wave 1 from Official Microsoft Download Center

Start the installer and apply the preferences that you want.

Tip: leave the default instance name and create after the instances that you need, with a non-versioned name. In this way you refer to your resources always with the same name, avoiding disruptions on each major upgrade. The default instance service can be disabled in the Control Panel.

Create the Service Instances with the same old name with “New-NAVServerInstance” command.

Create the Web Server Instances with the same old name with “New-NAVWebServerInstance” command.

Restore old “navsettings.json” and “CustomSettings.config“, make sure that the Windows Services have the right credentials to start.

Convert the database.

Start the services.

Import the new license file with “Import-NAVServerLicense” command.

Sync the tenat (use “S” option of the “Fast-Upgrade” script).

Reinstall all the old apps (use “4” option of the “Fast-Upgrade” script).

Step 3 – Play V24 with old APPs

In this example, V23 APPs are perfectly loaded in V24 environment. In the “NAV era” this task was called “platform upgrade“: you ran old application objects with the new version of executables.

Step 4 – Complete APPs upgrade

Now you can do all with “Fast-Upgrade” script.

Uninstall again all apps.

Publish and install new apps from Microsoft (pay attention that V24 has the new “Business Foundation” app between “System Application” and “Base Application”).

Tip: due to new dependencies, it could be necessary to run option “2” several times. Check that all Microsoft APPs has been installed with “N” option.

Clean up old Microsoft apps and reinstall older custom apps.

At the end, fix the addins with the new ZIPs provided by Microsoft (“F” option).

Open web client and… enjoy!

Strange things

During the script testing 😁 I caught this exception:

None of the published versions of extension 437dbf0e-84ff-417a-965d-ed2bb9650972 allowes take over of Table 308 No. Series. None of the published versions of extension 437dbf0e-84ff-417a-965d-ed2bb9650972 allowes take over of Table 309 No. Series Line. None of the published versions of extension 437dbf0e-84ff-417a-965d-ed2bb9650972 allowes take over of Table 310 No. Series Relationship. None of the published versions of extension 437dbf0e-84ff-417a-965d-ed2bb9650972 allowes take over of Table 1263 No. Series Tenant. None of the published versions of extension 437dbf0e-84ff-417a-965d-ed2bb9650972 allowes take over of Table 12145 No. Series Line Sales. None of the published versions of extension 437dbf0e-84ff-417a-965d-ed2bb9650972 allowes take over of Table 12146 No. Series Line Purchase.

This is caused by the new “MovedTo” property, now you finally can rearrange your extensions!

https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/properties/devenv-movedto-property

Going to look what’s happened to No Series, I noticed orphans columns in the Companion Table:

Bug in the upgrade process or something new is coming about indexes between Main and Companion table? 😁

Conclusion

Upgrading from V23 to V24 in several scenarios took me less than 30 minutes per environment. Once again, why not do it?

Fast-Upgrade script

# remote
$dvd = "C:\Temp\Dynamics.365.BC.18056.IT.DVD"
$dvdVersion = "240"

$upgradeDev = "$dvd\ModernDev\program files\Microsoft Dynamics NAV\$dvdVersion\AL Development Environment"
$upgradeWeb = "$dvd\WebClient\Microsoft Dynamics NAV\$dvdVersion\Web Client"
$upgradeService = "$dvd\ServiceTier\program files\Microsoft Dynamics NAV\$dvdVersion\Service"
$upgradeWebPublish = "$dvd\WebClient\Microsoft Dynamics NAV\$dvdVersion\Web Client\WebPublish"

#local
$targetDev = "C:\Program Files (x86)\Microsoft Dynamics 365 Business Central\240\AL Development Environment"
$targetWeb = "C:\Program Files\Microsoft Dynamics 365 Business Central\240\Web Client"
$targetSites = ,"C:\inetpub\wwwroot\WDEV"
$targetService = "C:\Program Files\Microsoft Dynamics 365 Business Central\240\Service"

$mgmtPath = "C:\Program Files\Microsoft Dynamics 365 Business Central\240\Service\Admin"
$instance = "WDEV"

# DVD provided apps
$apps = "ModernDev\program files\Microsoft Dynamics NAV\240\AL Development Environment\System.app",
		"Applications\system application\source\Microsoft_System Application.app",
		"Applications\BusinessFoundation\source\Microsoft_Business Foundation.app",
		"Applications\BaseApp\Source\Microsoft_Base Application.app",
		"Applications\Application\Source\Microsoft_Application.app"

Import-Module "$mgmtPath\NavAdminTool.ps1"

Write-Host ""
Write-Host "1) Uninstall all apps"
Write-Host "2) Publish and install new Microsoft apps"
Write-Host "3) Clean up old Microsoft apps"
Write-Host "4) Re-install other apps"
Write-Host ""
Write-Host "C) Convert database"
Write-Host "F) Fix addins"
Write-Host "N) App status"
Write-Host "S) Sync tenant"
Write-Host "U) Service upgrade"
Write-Host ""

$choice = Read-Host "Enter step number"

if (("n", "N").contains($choice))
{
	Get-NAVAppInfo -ServerInstance $instance -TenantSpecificProperties -Tenant default | Format-Table -Property Name, Publisher, Version, IsInstalled
	exit
}

if (("c", "C").contains($choice))
{
	[xml]$serviceConf = Get-Content $targetService\Instances\$instance\CustomSettings.config 
	
	$node = Select-Xml -Xml $serviceConf -XPath "/appSettings/add[@key='DatabaseServer']"
	$dbServer = $node.Node.value.ToString()
	
	$node = Select-Xml -Xml $serviceConf -XPath "/appSettings/add[@key='DatabaseName']"
	$dbName = $node.Node.value.ToString()
	
	Invoke-NAVApplicationDatabaseConversion -DatabaseName $dbName -DatabaseServer $dbServer
	exit 
}

if (("s", "S").contains($choice))
{
	Sync-NAVTenant -ServerInstance $instance -Mode Sync
	exit
}

if (("u", "U").contains($choice))
{
	Copy-Item $upgradeDev\* $targetDev -Recurse -Force
	Copy-Item $upgradeWeb\* $targetWeb -Recurse -Force

	$serviceConf = Get-Content $targetService\CustomSettings.config
	Copy-Item $upgradeService\* $targetService -Recurse -Force	
	Set-Content -Path $targetService\CustomSettings.config -Value $serviceConf	

	foreach ($ts in $targetSites) {
		$webConf = Get-Content $ts\NavSettings.json
		Copy-Item $upgradeWebPublish\* $ts -Recurse -Force
		Set-Content -Path $ts\NavSettings.json -Value $webConf
	}

	exit
}

if (("f", "F").contains($choice))
{
	Set-NAVAddIn -ServerInstance $instance -AddinName 'Microsoft.Dynamics.Nav.Client.BusinessChart' -PublicKeyToken 31bf3856ad364e35 -ResourceFile ($AppName = Join-Path $targetService 'Add-ins\BusinessChart\Microsoft.Dynamics.Nav.Client.BusinessChart.zip')
	Set-NAVAddIn -ServerInstance $instance -AddinName 'Microsoft.Dynamics.Nav.Client.FlowIntegration' -PublicKeyToken 31bf3856ad364e35 -ResourceFile ($AppName = Join-Path $targetService 'Add-ins\FlowIntegration\Microsoft.Dynamics.Nav.Client.FlowIntegration.zip')
	Set-NAVAddIn -ServerInstance $instance -AddinName 'Microsoft.Dynamics.Nav.Client.OAuthIntegration' -PublicKeyToken 31bf3856ad364e35 -ResourceFile ($AppName = Join-Path $targetService 'Add-ins\OAuthIntegration\Microsoft.Dynamics.Nav.Client.OAuthIntegration.zip')
	Set-NAVAddIn -ServerInstance $instance -AddinName 'Microsoft.Dynamics.Nav.Client.PageReady' -PublicKeyToken 31bf3856ad364e35 -ResourceFile ($AppName = Join-Path $targetService 'Add-ins\PageReady\Microsoft.Dynamics.Nav.Client.PageReady.zip')
	Set-NAVAddIn -ServerInstance $instance -AddinName 'Microsoft.Dynamics.Nav.Client.PowerBIManagement' -PublicKeyToken 31bf3856ad364e35 -ResourceFile ($AppName = Join-Path $targetService 'Add-ins\PowerBIManagement\Microsoft.Dynamics.Nav.Client.PowerBIManagement.zip')
	Set-NAVAddIn -ServerInstance $instance -AddinName 'Microsoft.Dynamics.Nav.Client.RoleCenterSelector' -PublicKeyToken 31bf3856ad364e35 -ResourceFile ($AppName = Join-Path $targetService 'Add-ins\RoleCenterSelector\Microsoft.Dynamics.Nav.Client.RoleCenterSelector.zip')
	Set-NAVAddIn -ServerInstance $instance -AddinName 'Microsoft.Dynamics.Nav.Client.SatisfactionSurvey' -PublicKeyToken 31bf3856ad364e35 -ResourceFile ($AppName = Join-Path $targetService 'Add-ins\SatisfactionSurvey\Microsoft.Dynamics.Nav.Client.SatisfactionSurvey.zip')
	Set-NAVAddIn -ServerInstance $instance -AddinName 'Microsoft.Dynamics.Nav.Client.VideoPlayer' -PublicKeyToken 31bf3856ad364e35 -ResourceFile ($AppName = Join-Path $targetService 'Add-ins\VideoPlayer\Microsoft.Dynamics.Nav.Client.VideoPlayer.zip')
	Set-NAVAddIn -ServerInstance $instance -AddinName 'Microsoft.Dynamics.Nav.Client.WebPageViewer' -PublicKeyToken 31bf3856ad364e35 -ResourceFile ($AppName = Join-Path $targetService 'Add-ins\WebPageViewer\Microsoft.Dynamics.Nav.Client.WebPageViewer.zip')
	Set-NAVAddIn -ServerInstance $instance -AddinName 'Microsoft.Dynamics.Nav.Client.WelcomeWizard' -PublicKeyToken 31bf3856ad364e35 -ResourceFile ($AppName = Join-Path $targetService 'Add-ins\WelcomeWizard\Microsoft.Dynamics.Nav.Client.WelcomeWizard.zip')

	exit
}

$o1 = Get-NAVAppInfo -ServerInstance $instance -TenantSpecificProperties -Tenant default
$o2 = Get-NAVAppInfo -ServerInstance $instance -SymbolsOnly
$oldApps = $o1 + $o2

if ($choice -eq "1")
{
	foreach ($old in $oldApps)
	{
		if ($old.IsInstalled)
		{
			Write-Output "Uninstalling $($old.Name)"
			Uninstall-NAVApp -ServerInstance $instance -Name $old.Name -Version $old.Version -Publisher $old.Publisher -Force
		}
	}
}

if ($choice -eq "2")
{
	# publish
	foreach ($a in $apps)
	{
		$nfo = Get-NAVAppInfo -Path "$dvd\$a"
		
		if ($nfo.Name -eq "System")
		{
			Write-Output "Publishing $($nfo.Name)"
     		Publish-NAVApp -ServerInstance $instance -Path "$dvd\$a" -PackageType SymbolsOnly
		}
		else
		{
			Write-Output "Publishing $($nfo.Name)"
			Publish-NAVApp -ServerInstance $instance -Path "$dvd\$a"
		}
	}
	
	#sync
	foreach ($a in $apps)
	{
		$nfo = Get-NAVAppInfo -Path "$dvd\$a"
		$nfo = Get-NAVAppInfo -ServerInstance $instance -Name $nfo.Name -Publisher $nfo.Publisher -Version $nfo.Version -TenantSpecificProperties -Tenant default
		if ($nfo.Count -eq 0)
		{
			continue
		}
			
		$nfo = $nfo[0]

		Write-Output "Syncing $($nfo.Name)"
		Sync-NAVApp -ServerInstance $instance -Name $nfo.Name -Publisher $nfo.Publisher -Version $nfo.Version
	}
	
	Sync-NAVTenant -ServerInstance $instance -Mode Sync -Force
	Start-NavDataUpgrade -ServerInstance $instance -FunctionExecutionMode Serial -Force
	
	#data upgrade
	foreach ($a in $apps)
	{
		$nfo = Get-NAVAppInfo -Path "$dvd\$a"
		$nfo = Get-NAVAppInfo -ServerInstance $instance -Name $nfo.Name -Publisher $nfo.Publisher -Version $nfo.Version -TenantSpecificProperties -Tenant default
		if ($nfo.Count -eq 0)
		{
			continue
		}
			
		$nfo = $nfo[0]

		Write-Output "Data upgrading $($nfo.Name)"
		Start-NAVAppDataUpgrade -ServerInstance $instance -Name $nfo.Name -Publisher $nfo.Publisher -Version $nfo.Version
	}
	
	#install
	foreach ($a in $apps)
	{
		$nfo = Get-NAVAppInfo -Path "$dvd\$a"
		$nfo = Get-NAVAppInfo -ServerInstance $instance -Name $nfo.Name -Publisher $nfo.Publisher -Version $nfo.Version -TenantSpecificProperties -Tenant default
		if ($nfo.Count -eq 0)
		{
			continue
		}
			
		$nfo = $nfo[0]
		
		Write-Output "Installing $($nfo.Name)"
		Install-NAVApp -ServerInstance $instance -Name $nfo.Name -Version $nfo.Version -Publisher $nfo.Publisher -Force
	}
	
	#application Version
	foreach ($a in $apps)
	{
		$nfo = Get-NAVAppInfo -Path "$dvd\$a"

		if ($nfo.Name -eq "Base Application")
		{
			Write-Output "Setting application version to $($nfo.Version)"
			Set-NAVApplication -ServerInstance $instance -Force -ApplicationVersion $nfo.Version
		}
	}
	
	Sync-NAVTenant -ServerInstance $instance -Mode Sync -Force
	Start-NavDataUpgrade -ServerInstance $instance -FunctionExecutionMode Serial -Force
}

if ($choice -eq "3")
{
	foreach ($a in $apps)
	{
		$nfo = Get-NAVAppInfo -Path "$dvd\$a"
		
		foreach ($old in $oldApps)
		{
			if (($nfo.Name -eq $old.Name) -and ($nfo.Publisher -eq $old.Publisher) -and ($nfo.Version -gt $old.Version))
			{
				Write-Output "Unpublishing $($nfo.Name)"
				Unpublish-NAVApp -ServerInstance $instance -Name $old.Name -Publisher $old.Publisher -Version $old.Version
			}
		}
	}	
}

if ($choice -eq "4")
{
	foreach ($old in $oldApps)
	{
		if (($old.IsInstalled -ne $True) -and ($old.SyncState -ne $null) -and ($old.SyncState.ToString() -eq "Synced"))
		{
			Write-Output "Installing $($old.Name)"
			Install-NAVApp -ServerInstance $instance -Name $old.Name -Version $old.Version -Publisher $old.Publisher -Force
		}
	}
}