We have been quiet for a while. Not because we have not been tinkering, but because we’ve been very busy tinkering.
To be precise we’ve been tinkering with our Echelon type 83331-3IAAD Smart Meters (power meters) and how to read out the consumption in a nice way…
At the Danish gathering Sommerhack.dk 2021 we’ll be presenting a session (Friday @ 16:00 CET) about our process and the current state of this project. See you there?
It is yet to be determined how much details we can share because we are currently under NDA (Non-Disclosure Agreement) with the product owner NES (Networked Energy Services) about the details… But that will hopefully change soon.
Are you interested in communicating with your Echelon Smart Meter?
Stay tuned for more info. on how to do it… coming to dabbler.dk very soon now…
Off cause BC supports Java Script control add ins, but downloading a Java Script Tetris clone and simply calling it in a BC JavaScript control add in would not really be a challenge at all.
The true nature of the challenge must be to create a playable Tetris clone in AL, controlled by AL and only use a minimum amount of HTML and Java Script.
On top of that the game should probably be implemented with very few AL objects, to limit the footprint when installing. And why not add controls with the cursor keys and game sound effects now we are busy anyway?
If you just want to see it – well here we go (disclaimer: I’m a developer, NOT a gamer!)
ALTris was developed in BC14, but as BC apps are compatible with other versions it should be installable and playable on other versions too. It probably also helps that I’m not using a bunch of calls to the standard BC base application. I didn’t find any usable – probably Microsoft didn’t think of BC as much of a games platform :-).
Feel free to use the code, look into the code, change the code, complain about the code or whatever you prefer as long as you keep my name, SIMTEQ A/S and links to my LinkedIn and SIMTEQs homepage in there.
Use this code on your own risk and costs…. and enjoy!
Updates: * 2020-09-08: Found and fixed a few spell bugs (text only), so we are now at version 1.0.0.1 π
Did you also wonder where the English and Danish (and probably other languages as well) help pages went?
In Microsoft Dynamics Business Central 2019 wave 1 aka Business Central 14 (and possible newer versions) after the RTM-release in April 2019, the help simply does not work out-of-the-box anymore.
It seems Microsoft are more focused on the SaaS solution these days and the On-Premise version is suffering a bit from it.
Note: I’ve actually contacted Microsoft about these help issues, but due to the SaaS focus and the help beeing a community effort now (see https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/help/contributor-guide), they are actually NOT planning to fix this! Also they are trying to reduce the size of the install DVD. That is an unofficial answer though, so if we all report it, they might change their minds :-). For now this is something you need to repair in your installation yourself – i.e. by following this blog post…
This is actually two “errors”:
(1) If you have selected the en-US language and you try to open the help using the icon or CTRL+F1 you get this:
…actually this is quite easily fixed. The English language is per default installed in “C:\inetpub\wwwroot\DynamicsNAV140Help\help\en”, but BC is trying to open it from “C:\inetpub\wwwroot\DynamicsNAV140Help\help\en-US”. So let us just create a link:
C:>cd C:\inetpub\wwwroot\DynamicsNAV140Help\help
C:\inetpub\wwwroot\DynamicsNAV140Help\help>mklink /d en-US en
symbolic link created for en-US <<===>> en
C:\inetpub\wwwroot\DynamicsNAV140Help\help>dir
Volume in drive C has no label.
Volume Serial Number is C6AF-373F
Directory of C:\inetpub\wwwroot\DynamicsNAV140Help\help
06/23/2020 07:03 AM
.
06/23/2020 07:03 AM ..
03/30/2020 10:53 AM da-DK
03/30/2020 10:53 AM en
06/23/2020 07:03 AM en-US [en]
01/31/2020 07:11 AM 22,060 feedback.js
03/30/2020 10:53 AM local
01/31/2020 07:11 AM 79 shortcutCold.gif
2 File(s) 22,139 bytes
…problem solved π
2020-10-05 GL: Please see Jani KivilΓ€hde’s comment below: “For fix (1), the use of SYMLINK breaks the search in Help Server. Windows Search does not traverse SYMLINKs.”. So the correct fix is – as mentioned by Jani – to rename or copy the folder.
(2) If you on the other hand have selected the da-DK (Danish) language – or presumable any other language besides en-US, you’ll get this error:
…and if you have a look at the server in the destination folder “C:\inetpub\wwwroot\DynamicsNAV140Help\help\da-DK”, you’ll discover why:
Actually, I’ve checked most versions of the Danish install DVD, an the .cab-file with help files are only included in full on the RTM version – NOT in all the CU versions (you’ll find the .cab-file on the DVD in the folder “Installers\DK\WebHelp\DynamicsNAV140Help\help\da-DK”). In the RTM-version the .cab-file is above 4MB in file size, while it is only 18KB on the CU versions.
Note: The latter solution is probably the preferred one, because you then get the exact help files matching your BC version. The GitHub repository might contain functionality not yet introduced in your major version.
Another note: the .cab-file or “Cabinet File” is actually a .zip-file, so you can rename it to .zip to open it in Windows or simply open it with 7-Zip or similar archiving utility. And then copy the contents to the correct language help folder.
Yet another note: In the “old days” where this worked out-of-the-box, the translated help files was typically NOT updated with each CU release. That makes sense as CUs rarely contains a lot of new functionality and it is probably quite expensive to keep the translations updated.
And a final note: I’ve not confirmed this issue for Microsoft Business Central 2019 wave 2 aka BC15 and/or 2020 wave 1 aka BC16. But as this might be caused by Microsoft prioritizing SaaS, it might be the same story in all versions after BC14. Hopefully we will be able to extract the help from the RTM versions…
As always: These fixes comes with NO warranty. Use this completely at your own risk and costs. Also it would probably be a very good idea to make a copy of the existing installation before overwriting or adding anything.
Extra hint – can you search in your help? If not, did you remember to:
enable Windows Search on your IIS help server (WindowsServer Manager)
verify that the Windows Indexing Service is running (Windows Task Manager)
verify the help folder is included in the indexing (Windows Control Panel)
Unfortunately this has not been updated to run Windows ServerCore 1890 and Microsoft SQL Server 2019 – so this is what this blog post is about…
Note 2: We are only taking about minor changes here – so I’m not in ANY way trying to claim credits for these scripts – all credits goes to the original author for these scripts – see the above mentioned official link!
Note 3: If you try to use the official Microsoft SQL Server Developer Edition image and you get the error “The container operating system does not match the host operating system.”, it is probably because that image is not Windows Server 1809 compatible. This will also solve that as this image is based on the “mcr.microsoft.com/windows/servercore:1809” Windows Server image.
Enough notes for now :-). Let’s roll with this – first you need to create these two files:
# 2020-05-11 GL
# The script sets the sa password and start the SQL Service
# Also it attaches additional database from the disk
# The format for attach_dbs
param(
[Parameter(Mandatory=$false)]
[string]$sa_password,
[Parameter(Mandatory=$false)]
[string]$ACCEPT_EULA,
[Parameter(Mandatory=$false)]
[string]$attach_dbs
)
if($ACCEPT_EULA -ne "Y" -And $ACCEPT_EULA -ne "y")
{
Write-Verbose "ERROR: You must accept the End User License Agreement before this container can start."
Write-Verbose "Set the environment variable ACCEPT_EULA to 'Y' if you accept the agreement."
exit 1
}
# start the service
Write-Verbose "Starting SQL Server"
start-service MSSQLSERVER
if($sa_password -eq "_") {
if (Test-Path $env:sa_password_path) {
$sa_password = Get-Content -Raw $secretPath
}
else {
Write-Verbose "WARN: Using default SA password, secret file not found at: $secretPath"
}
}
if($sa_password -ne "_")
{
Write-Verbose "Changing SA login credentials"
$sqlcmd = "ALTER LOGIN sa with password=" +"'" + $sa_password + "'" + ";ALTER LOGIN sa ENABLE;"
& sqlcmd -Q $sqlcmd
}
$attach_dbs_cleaned = $attach_dbs.TrimStart('\\').TrimEnd('\\')
$dbs = $attach_dbs_cleaned | ConvertFrom-Json
if ($null -ne $dbs -And $dbs.Length -gt 0)
{
Write-Verbose "Attaching $($dbs.Length) database(s)"
Foreach($db in $dbs)
{
$files = @();
Foreach($file in $db.dbFiles)
{
$files += "(FILENAME = N'$($file)')";
}
$files = $files -join ","
$sqlcmd = "IF EXISTS (SELECT 1 FROM SYS.DATABASES WHERE NAME = '" + $($db.dbName) + "') BEGIN EXEC sp_detach_db [$($db.dbName)] END;CREATE DATABASE [$($db.dbName)] ON $($files) FOR ATTACH;"
Write-Verbose "Invoke-Sqlcmd -Query $($sqlcmd)"
& sqlcmd -Q $sqlcmd
}
}
Write-Verbose "Started SQL Server."
$lastCheck = (Get-Date).AddSeconds(-2)
while ($true)
{
Get-EventLog -LogName Application -Source "MSSQL*" -After $lastCheck | Select-Object TimeGenerated, EntryType, Message
$lastCheck = Get-Date
Start-Sleep -Seconds 2
}
…and then you have to run these docker commands (replace “<path to a directory with the above mentioned two files>” with the path to the above mentioned two files: dockerfile and start.ps1 – and “<password>” with the sa-password you want):
docker build --memory 4g --tag dabbler/mssql-server-windows-developer:winsrv1809-sql2019 "<path to a directory with the above mentioned two files>"
docker run --name SQLServer2019 -e ACCEPT_EULA=Y -e sa_password=<password> -p 1433:1433 -d dabbler/mssql-server-windows-developer:winsrv1809-sql2019
If you are lucky, you will now have a running SQL Server 2019 Developer Edition and you can connect directly to it with Microsoft SQL Server Management Studio directly on the host running Docker (use “SQL Server Authentication” with host: “localhost”, login: “sa” and the password stated above).
As described here, it can be kind of a Catch-22 to try to install Microsoft Dynamics 365 Business Central if you don’t have a local SQL Server, but want to use AzureSQL.
Although I know the approach in the before mentioned Kine Info blog post works, I came across a easier solution during my struggles with this issue.
Although the installer setup.exe does not have a “Postpone Server Startup” setting in the GUI, it actually support it.
You just need to create a configuration and hit Save before actually starting the installation. You can do that when you finish filling out all the settings on the setting page (the one with port numbers, database server and database name etc.). After you saved the configuration, close the setup.exe installer.
Now open the XML file you saved, locate the “PostponeServerStartup” setting and change it’s default value of “false” to “true”:
Now restart setup.exe and load the configuration – and start the installation. The installer will not try to start the service tier, so it won’t fail that and roll back the installation.
We can only hope that Microsoft at some point will add this option to the setup.exe GUI :-).
2020-02-28 Update: I’ve suggested it to Microsoft. It is not a high priority issue (because of the above described workaround). For anybody interested it has been logged with internal Microsoft ID 346773.
Have you tried to rename a company (from the Companies page or from PowerShell (Rename-NAVCompany cmdlet) in Microsoft Dynamics NAV 2018 and you get this error: “The task cannot be run because the user account that is assigned to run the task has been altered”, you are hit by a side effect of a new Service Tier Setting.
Specifies whether user consistency checks are done on tasks. Setting this to true helps guard against impersonation of users in tasks. When enabled, only the user who created the task can edit the task. If a task is edited by different user account, an error similar to the following occurs: The task cannot be run because the user account that is assigned to run the task has been altered. The task has been canceled.
Default: true
Dynamically Updatable: No
…so if this protection is not important to you – you can easily work around the error by setting this key to false. If this protection is important to you, you should off cause just set it to false while renaming the company and then set it back to true again.
In the past I worked a lot with Microsoft Dynamics C5 and I just stumbled across an old quirk when you add database to a large existing database. You simply does not always get what you pay for.
For Microsoft Dynamics C5 you purchase additional database in packages of these sizes: +25MB, +125MB, +250MB, +500MB and +2,500MB. Unfortunately internally the Microsoft Dynamics C5 kernel and license codes handles additional database size like this:
Database interval
Increments
Notes
0 – 45MB
+5MB
45MB is included in the initial Microsoft Dynamics C5 license
45 – 120MB
+5MB
120 – 2,020MB
+25MB
2,020 – 12,020MB
+100MB
12,020 – 112,020MB
+1,000MB
This actually means that if you have a database of 2,020MB and purchases +25MB, Microsoft Dynamics C5 will state the available space as 2,120MB, while your license states only 2,045MB.
Actually – according to the above mentioned information link to PartnerSource, you are NOT allowed to use more database than the license states. So you should add an extra database package when you reach 2,045MB in the above example.
If you don’t do that, this will also cause some huge confusion when you reach 2,120MB – because you might then add another +25MB and you’ll get NOTHING. The license will say 2,070MB, but Microsoft Dynamics C5 will still state it as 2,120MB…
Bonus info.: How much database storage can you purchase to a Microsoft Dynamics C5 installation? Exactly 112,020MB. After this the Microsoft Dynamics C5 kernel will stop calculating the DB size and you will not be required to purchase extra database license (but you are not likely to ever reach this limit π ).
Note: To my knowledge all of this is also true for Microsoft XAL because it was build on the same kernal as Microsoft Dynamics C5
So you think you are SUPER, but you are not able to log in to your Microsoft Dynamics 365 Business Center using the web client? (because of some access denied error).
Well… This is not a very common error, because these needs to be true to trigger it:
You are trying to login using the web client
Your installation is using a (partner) license with an expiration date, and the expiration dates is less than a month away (so you get a warning about it on every login (in web-, windows- and development-clients)
Your permissions are created specific on one or more companies only – so you don’t have i.e. BASIC without a company name
Just after entering your credentials, you’ll get the warning about the expiring license:
…and as soon as you click OK you get this (sorry about the mixup of Danish and English here – maybe that is also a part of the bug? Translation is in the image description below):
Your configuration is valid and works for the windows client, but unfortunately the web client have a bug preventing this from working.
This is a platform bug I’ve found in Microsoft Dynamics 365 Business Center 13 with CU 7 (i.e. BC13 CU7 which is the October 2018 release with cumulative update 7). I’ve NOT tested other versions, but I believe that it is also an issue in the latest CU for BC13 and possible also a bug in BC14 and BC15.
This bug HAS been reported to Microsoft and will be fixed in later CUs of the respective BC versions. It was assigned bug ID 332507.
Workarounds while waiting for the fixed cumulative update?
Use Windows client. It is not affected by this bug
You can add your permission sets without a company name. Maybe even create a new one that does not really grant you access to companies you should not have access to – or simply just add “BASIC”. As long as it is without company name the web client will work
Avoid using a license that is about to expire. Re-new your license
Note: When hit by this error, you will also see these event log entries on the server (sorry – also partly in Danish):
Server instance: xxxxxx
Category: Security
ClientSessionId: 5e339103-92dd-4ba3-b4cc-874531ba692b
ClientActivityId: 1b071e5f-13c4-4352-9a3d-a7835ca50d9a
ServerSessionUniqueId: 759dfb07-9b76-4eeb-bf7c-8a77cb0379d1
ServerActivityId: 585927d0-5273-43b7-9c65-cdcc612115bd
EventTime: 11/01/2019 14:47:44
Message (NavPermissionException): RootException: NavPermissionException
You do not have the following permissions on TableData Profile: Read.
To view details about your permissions, see the Effective Permissions page. To report a problem, refer to the following server session ID: '85'.
CallerStackTrace:
at Microsoft.Dynamics.Nav.Runtime.PermissionSetBase.VerifyPermissions(NavApplicationObjectBase securableObject, PermissionMask permissionMask, LimitedUserPermissionChecker limitedUserPermissionChecker, Func2 checkTableEmpty, PermissionMask additionalIndirectPermissions, Boolean countAsLimitedUserAllowedTable) at Microsoft.Dynamics.Nav.Runtime.RecordImplementation.VerifyPermissions(PermissionMask permissionMask, Boolean checkForEmptyTable) at Microsoft.Dynamics.Nav.Runtime.RecordImplementation.IssueFindRequest(DataError errorLevel, Boolean reversed, FindType findType, Boolean useCache) at Microsoft.Dynamics.Nav.Runtime.RecordImplementation.FindFirstRecord(DataError errorLevel) at Microsoft.Dynamics.Nav.Runtime.NavRecord.ALFindFirst(DataError errorLevel) at Microsoft.Dynamics.Nav.Runtime.ProfileTableDataHandler.<GetAllItems>d__1.MoveNext() at System.Linq.Enumerable.<ConcatIterator>d__591.MoveNext()
at Microsoft.Dynamics.Nav.Runtime.EagerVirtualDataProvider.TryGetByPrimaryKey(RecordIdProviderRequest request, ReadOnlyRecordBuffer& recordBuffer)
at Microsoft.Dynamics.Nav.Runtime.DataAccess.InternalTryGetByPrimaryKey(RecordIdCacheRequest request, MutableRecordBuffer& recordBuffer)
at Microsoft.Dynamics.Nav.Runtime.DataAccess.TryHandleAsPrimaryKeyLookup(DataCacheRequest request, Boolean cacheOnly, MutableRecordBuffer& recordBuffer)
at Microsoft.Dynamics.Nav.Runtime.DataAccess.InnerFind(FindCacheRequest request, Boolean fromPosition, Func`1 onlyCurrentKeyNeededForNextRow)
at Microsoft.Dynamics.Nav.Runtime.RecordImplementation.IssueFindRequest(DataError errorLevel, Boolean reversed, FindType findType, Boolean useCache)
at Microsoft.Dynamics.Nav.Runtime.RecordImplementation.FindFirstRecord(DataError errorLevel)
at Microsoft.Dynamics.Nav.Runtime.NavRecord.ALFindFirst(DataError errorLevel)
at Microsoft.Dynamics.Nav.XmlMetadata.NavConfigurationProfile.GetProfileRoleCenterId(NavProfileKey profile)
at Microsoft.Dynamics.Nav.XmlMetadata.MetadataProvider.GetHomepageID(NavProfileKey profileKey)
at Microsoft.Dynamics.Nav.XmlMetadata.MetadataProvider.GetNavigationFrame(Boolean applyPersonalization, NavProfileKey profileKey)
at SyncInvokeGetNavigationFrame(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.RunInTransactionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass24_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.TransientErrorRetryCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass24_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.ErrorMappingCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass24_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.PushPopCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass24_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationTracer.TraceScopeCombinator(Category telemetryCategory, ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass24_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass9_0.b__0()
at Microsoft.Dynamics.Nav.Runtime.NavPerformanceCounterSetter.UpdatePerformanceCountersWithAverageServiceOperationDuration(Stopwatch stopWatch, Action action)
at Microsoft.Dynamics.Nav.Runtime.NavPerformanceCounterSetter.UpdatePerformanceCountersWithAverageServiceOperationAction(Action action, NavSession session)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.PerformanceCounterCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass24_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.InitClientTelemetryIdsCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass24_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.TlsClearCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass24_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
at System.ServiceModel.Dispatcher.MessageRpc.Wrapper.Resume(Boolean& alreadyResumedNoLock)
at System.ServiceModel.Dispatcher.ThreadBehavior.ResumeProcessing(IResumeMessageRpc resume)
at Microsoft.Dynamics.Nav.Runtime.NavSynchronizationContext.<>c__DisplayClass1_0.b__0(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
ProcessId: 21660
Tag: 00000XO
ThreadId: 26
CounterInformation:
Der opstod fejl under forsΓΈg pΓ₯ adgang til webstedet
Type: Microsoft.Dynamics.Nav.Types.NavPermissionException
Message: You do not have the following permissions on TableData Profile: Read.
To view details about your permissions, see the Effective Permissions page. To report a problem, refer to the following server session ID: '85'.
StackTrace:
ved Microsoft.Dynamics.Nav.Client.ConnectionStateManager.CallServer[T](BeginCallServerMethod beginCallServerMethod, EndCallServerMethod1 endCallServerMethod, ServerCallOptions options) i S:\Depot\Platform-Core\platform\client\Shared\Prod.Client.ServiceConnection\ConnectionStateManager.cs:linje 145 ved Microsoft.Dynamics.Nav.Client.ServiceConnection.CallServer[T](BeginCallServerMethod beginCallServerMethod, EndCallServerMethod1 endCallServerMethod) i S:\Depot\Platform-Core\platform\client\Shared\Prod.Client.ServiceConnection\ServiceConnection.cs:linje 2020
ved Microsoft.Dynamics.Nav.Client.MetadataHandler.GetNavigationFrame(Boolean applyPersonalization, Boolean getNavigationFrameFromServer) i S:\Depot\Platform-Core\platform\client\Shared\Prod.Client.ServiceConnection\MetadataHandling\MetadataHandler.cs:linje 559
ved Microsoft.Dynamics.Nav.Client.Web.NavWebBuilderSessionInitializer.NavigationServiceNavigationRootNeeded(Object sender, Object e) i S:\Depot\Platform-Core\platform\client\web\Prod.Client.WebCommon\NavBuilder\NavWebBuilderSessionInitializer.cs:linje 48
ved Microsoft.Dynamics.Framework.UI.Web.ResponseManager.<>c__DisplayClass23_0.b__3() i S:\Depot\Platform-Core\platform\client\web\Prod.Client.Web\Callbacks\ResponseManager.cs:linje 175
ved Microsoft.Dynamics.Framework.UI.LogicalOperationInvoker.<>c__DisplayClass21_0.b__0() i S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\Threading\LogicalOperationInvoker\LogicalOperationInvoker.cs:linje 178
ved Microsoft.Dynamics.Framework.UI.LogicalOperationInvoker.InvokeAndHandleExceptions(Func`1 action, IExceptionHandler exceptionHandler) i S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\Threading\LogicalOperationInvoker\LogicalOperationInvoker.cs:linje 415
Source: Microsoft.Dynamics.Nav.Client.ServiceConnection----------------------------------
Type: Microsoft.Dynamics.Nav.Types.NavPermissionException
Message: You do not have the following permissions on TableData Profile: Read.
To view details about your permissions, see the Effective Permissions page. To report a problem, refer to the following server session ID: '85'.
StackTrace:
at Microsoft.Dynamics.Nav.Runtime.PermissionSetBase.VerifyPermissions(NavApplicationObjectBase securableObject, PermissionMask permissionMask, LimitedUserPermissionChecker limitedUserPermissionChecker, Func2 checkTableEmpty, PermissionMask additionalIndirectPermissions, Boolean countAsLimitedUserAllowedTable) at Microsoft.Dynamics.Nav.Runtime.RecordImplementation.VerifyPermissions(PermissionMask permissionMask, Boolean checkForEmptyTable) at Microsoft.Dynamics.Nav.Runtime.RecordImplementation.IssueFindRequest(DataError errorLevel, Boolean reversed, FindType findType, Boolean useCache) at Microsoft.Dynamics.Nav.Runtime.RecordImplementation.FindFirstRecord(DataError errorLevel) at Microsoft.Dynamics.Nav.Runtime.NavRecord.ALFindFirst(DataError errorLevel) at Microsoft.Dynamics.Nav.Runtime.ProfileTableDataHandler.<GetAllItems>d__1.MoveNext() at System.Linq.Enumerable.<ConcatIterator>d__591.MoveNext()
at Microsoft.Dynamics.Nav.Runtime.EagerVirtualDataProvider.TryGetByPrimaryKey(RecordIdProviderRequest request, ReadOnlyRecordBuffer& recordBuffer)
at Microsoft.Dynamics.Nav.Runtime.DataAccess.InternalTryGetByPrimaryKey(RecordIdCacheRequest request, MutableRecordBuffer& recordBuffer)
at Microsoft.Dynamics.Nav.Runtime.DataAccess.TryHandleAsPrimaryKeyLookup(DataCacheRequest request, Boolean cacheOnly, MutableRecordBuffer& recordBuffer)
at Microsoft.Dynamics.Nav.Runtime.DataAccess.InnerFind(FindCacheRequest request, Boolean fromPosition, Func`1 onlyCurrentKeyNeededForNextRow)
at Microsoft.Dynamics.Nav.Runtime.RecordImplementation.IssueFindRequest(DataError errorLevel, Boolean reversed, FindType findType, Boolean useCache)
at Microsoft.Dynamics.Nav.Runtime.RecordImplementation.FindFirstRecord(DataError errorLevel)
at Microsoft.Dynamics.Nav.Runtime.NavRecord.ALFindFirst(DataError errorLevel)
at Microsoft.Dynamics.Nav.XmlMetadata.NavConfigurationProfile.GetProfileRoleCenterId(NavProfileKey profile)
at Microsoft.Dynamics.Nav.XmlMetadata.MetadataProvider.GetHomepageID(NavProfileKey profileKey)
at Microsoft.Dynamics.Nav.XmlMetadata.MetadataProvider.GetNavigationFrame(Boolean applyPersonalization, NavProfileKey profileKey)
at SyncInvokeGetNavigationFrame(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.RunInTransactionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass24_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.TransientErrorRetryCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass24_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.ErrorMappingCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
Source: Microsoft.Dynamics.Nav.Ncl
Error accessing Website
Type: Microsoft.Dynamics.Nav.Types.NavProfileException
Message: You don't have permission to use the Role Center 'ORDREBEHANDLER'.
StackTrace:
at Microsoft.Dynamics.Nav.Client.NavRunHomepagePropertyBagInvokedAction.Validate(FormPropertyBag queryParameters, UISession uiSession, Object invocationState) in S:\Depot\Platform-Core\platform\client\Shared\Prod.Client.UI\NavRunHomepagePropertyBagInvokedAction.cs:line 61
at Microsoft.Dynamics.Framework.UI.LogicalFormActivator.GeneratePropertyBagCommand(FormPropertyBag propertyBagToUse, UISession uiSession, Object invocationState) in S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\URL\LogicalFormActivator.cs:line 157
at Microsoft.Dynamics.Framework.UI.LogicalFormActivator.ValidateAndInvokePropertyBag(FormPropertyBag propertyBagToUse, UISession uiSession, Object invocationState) in S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\URL\LogicalFormActivator.cs:line 60
at Microsoft.Dynamics.Framework.UI.OpenFormInteraction.InvokeCore(OpenFormInteractionInput logicalInteractionInput) in S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\Interactions\SystemInteractions\OpenFormInteraction.cs:line 0
at Microsoft.Dynamics.Framework.UI.InteractionInvoker.Invoke[T](String interactionName, Action1 invokeMethod, T input) in S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\Interactions\InteractionInvoker.cs:line 42 at Microsoft.Dynamics.Framework.UI.LogicalInteraction1.Invoke(T logicalInteractionInput) in S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\Interactions\LogicalInteraction.cs:line 40
at Microsoft.Dynamics.Framework.UI.InteractionManager.<>c__DisplayClass8_2.b__4() in S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\Interactions\InteractionManager.cs:line 125
Source: Microsoft.Dynamics.Nav.Client.UI
Have you tried to configure a Microsoft Dynamics Business Central 2019 Spring release (BC14) RTM with LoginName authentication, just to find that it did not work?
You are right.
You won’t be able to login to the Web- or Windows-client and will get errors in your event log like these:
Server instance: BC140
Category: Runtime
ClientSessionId: 1396b6cf-5cfd-4dae-b98a-9ee3a6d3d3e1
ClientActivityId: 8665e7ca-3a27-49f3-b928-4a013317be94
ServerSessionUniqueId: 00000000-0000-0000-0000-000000000000
ServerActivityId: 5d8ecef1-6d64-4d05-9031-03a0248c9138
EventTime: 08/09/2019 10:14:40
Message (NullReferenceException): RootException: NullReferenceException
Object reference not set to an instance of an object.
ExceptionStackTrace:
at Microsoft.Dynamics.Nav.Service.NSServiceBase.<>c__DisplayClass14_0.b__0()
at Microsoft.Dynamics.Nav.Service.NSServiceBase.ValidateAndCreateSession(ConnectionRequest connectionRequest, Boolean requireNavUser)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)
CallerStackTrace:
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass27_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationTracer.TraceScopeCombinator(Category telemetryCategory, ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass27_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass9_0.b__0()
at Microsoft.Dynamics.Nav.Runtime.NavPerformanceCounterSetter.UpdatePerformanceCountersWithAverageServiceOperationDuration(Stopwatch stopWatch, Action action)
at Microsoft.Dynamics.Nav.Runtime.NavPerformanceCounterSetter.UpdatePerformanceCountersWithAverageServiceOperationAction(Action action, NavSession session)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.PerformanceCounterCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass27_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.InitClientTelemetryIdsCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass27_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.TlsClearCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass27_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
at System.ServiceModel.Dispatcher.MessageRpc.Wrapper.Resume(Boolean& alreadyResumedNoLock)
at System.ServiceModel.Dispatcher.ThreadBehavior.ResumeProcessing(IResumeMessageRpc resume)
at Microsoft.Dynamics.Nav.Runtime.NavSynchronizationContext.<>c__DisplayClass1_0.b__0(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
Server instance: BC140
Tenant ID:
User: xxx
Type: System.NullReferenceException
Message: Object reference not set to an instance of an object.
StackTrace:
at Microsoft.Dynamics.Nav.Service.NSServiceBase.<>c__DisplayClass14_0.b__0()
at Microsoft.Dynamics.Nav.Service.NSServiceBase.ValidateAndCreateSession(ConnectionRequest connectionRequest, Boolean requireNavUser)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)
Source: Microsoft.Dynamics.Nav.Service
HResult: -2147467261
StackTrace:
at Microsoft.Dynamics.Nav.Service.NSServiceBase.<>c__DisplayClass14_0.b__0()
at Microsoft.Dynamics.Nav.Service.NSServiceBase.ValidateAndCreateSession(ConnectionRequest connectionRequest, Boolean requireNavUser)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)
Type: Microsoft.Dynamics.Nav.Client.NavClientClosingException
Fatal: False
ShowError: True
Message: The server "BC140" was unable to process the request. The application will close.
StackTrace:
at Microsoft.Dynamics.Nav.Client.WinClient.ExceptionHandler.DoExecute(Func1 execute) at Microsoft.Dynamics.Nav.Client.WinClient.StartWinFormsClient.RunCore() Source: Microsoft.Dynamics.Nav.Client.WinClient HResult: -2146233088 StackTrace: at Microsoft.Dynamics.Nav.Client.WinClient.ExceptionHandler.DoExecute(Func1 execute)
at Microsoft.Dynamics.Nav.Client.WinClient.StartWinFormsClient.RunCore()
Type: Microsoft.Dynamics.Nav.Types.Exceptions.NavServerSessionException
Message: The server "BC140" was unable to process the request. The application will close.
StackTrace:
at Microsoft.Dynamics.Nav.Client.ConnectionEstablisher.OpenConnection[TChannel](ConnectFailedEventArgs connectFailedArgs, ConnectionRequest connectionRequest, ConnectionOptions connectionOptions, SpnSetting spnSettingToTry, Boolean allowSpnSettingsSwap, UserSettings& userSettings)
at Microsoft.Dynamics.Nav.Client.ConnectionEstablisher.OpenConnection[TChannel](ConnectionRequest connectionRequest, ConnectionOptions connectionOptions, UserSettings& userSettings)
at Microsoft.Dynamics.Nav.Client.ServiceConnection.OpenConnection()
at Microsoft.Dynamics.Nav.Client.ServiceConnection.Initialize()
at Microsoft.Dynamics.Nav.Client.FormBuilder.BuilderSessionInitializer.OpenConnectionToServer()
at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.OpenServerConnectionCore()
at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.OpenServerConnectionWithMultipleLoginAttempts()
at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.InitializeUISession()
at Microsoft.Dynamics.Framework.UI.Windows.ClientSessionBase.InitCore()
at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.InitCore()
at Microsoft.Dynamics.Framework.UI.ClientSessionCore.Init()
at Microsoft.Dynamics.Framework.UI.Windows.ClientSessionBase.Run()
at Microsoft.Dynamics.Nav.Client.WinClient.NavClientErrorHandler.ExecuteAndCatchExceptions(Func`1 execute)
Source: Microsoft.Dynamics.Nav.Client.ServiceConnection
HResult: -2146233088
StackTrace:
at Microsoft.Dynamics.Nav.Client.ConnectionEstablisher.OpenConnection[TChannel](ConnectFailedEventArgs connectFailedArgs, ConnectionRequest connectionRequest, ConnectionOptions connectionOptions, SpnSetting spnSettingToTry, Boolean allowSpnSettingsSwap, UserSettings& userSettings)
at Microsoft.Dynamics.Nav.Client.ConnectionEstablisher.OpenConnection[TChannel](ConnectionRequest connectionRequest, ConnectionOptions connectionOptions, UserSettings& userSettings)
at Microsoft.Dynamics.Nav.Client.ServiceConnection.OpenConnection()
at Microsoft.Dynamics.Nav.Client.ServiceConnection.Initialize()
at Microsoft.Dynamics.Nav.Client.FormBuilder.BuilderSessionInitializer.OpenConnectionToServer()
at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.OpenServerConnectionCore()
at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.OpenServerConnectionWithMultipleLoginAttempts()
at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.InitializeUISession()
at Microsoft.Dynamics.Framework.UI.Windows.ClientSessionBase.InitCore()
at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.InitCore()
at Microsoft.Dynamics.Framework.UI.ClientSessionCore.Init()
at Microsoft.Dynamics.Framework.UI.Windows.ClientSessionBase.Run()
at Microsoft.Dynamics.Nav.Client.WinClient.NavClientErrorHandler.ExecuteAndCatchExceptions(Func`1 execute)
Type: Microsoft.Dynamics.Nav.Types.Exceptions.NavServerSessionException
Message: The server "BC140" was unable to process the request. The application will close.
HResult: -2146233088
Type: System.NullReferenceException
Message: Object reference not set to an instance of an object.
StackTrace:
at Microsoft.Dynamics.Nav.Service.NSServiceBase.<>c__DisplayClass14_0.b__0()
at Microsoft.Dynamics.Nav.Service.NSServiceBase.ValidateAndCreateSession(ConnectionRequest connectionRequest, Boolean requireNavUser)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)
Source: Microsoft.Dynamics.Nav.Service
HResult: -2147467261
StackTrace:
at Microsoft.Dynamics.Nav.Service.NSServiceBase.<>c__DisplayClass14_0.b__0()
at Microsoft.Dynamics.Nav.Service.NSServiceBase.ValidateAndCreateSession(ConnectionRequest connectionRequest, Boolean requireNavUser)
at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)
Part of the story is that the same setup simply works with earlier versions, and that Windows-authentication also works without any glitches.
At least the fix is simple: Upgrade your platform to Cumulative Update 1 (or actually I recommend the latest while you are at it anyway π ).
If you have been using the Dotnet ClickOnce technology to roll out your Dynamics NAV / 365 Business Central Windows Clients, you know it have some limitations (click here to read all about the limitations).
But if you start pulling the ClickOnce technology apart, you will find that the client files are in fact present on your harddrive, but in a obscure directory – which can be hard to locate (actually you can just start the client and go to task manager. Right click the running program and select to open the directory).
What if someone could make a small program or script that would locate all installed ClickOnce Dynamics NAV / 365 Business Central Windows Clients, present you with a list to choose from and then simply start the selected client with the appropriate parameters?
Maybe we can even register this small program or script as the protocol handler for the DynamicsNAV:// protocol?
Well, here is my first attempt of a PowerShell script I call NAVBCProtocolHandlerHelper.ps1 :-):
# Version: 2019-08-06
$SearchPath = "C:\Users\$($env:UserName)\AppData\Local\Apps\2.0\"
$WindowsClientFileName = "Microsoft.Dynamics.Nav.Client.exe"
$ClientUserSettingsFileName = "ClientUserSettings.config"
if(($args[0] -eq "?") -or ($args[0] -eq "-?") -or ($args[0] -eq "-h") -or ($args[0] -eq "-help")) {
Write-Host "#######################################################################" -ForegroundColor Cyan
Write-Host "# Microsoft Dynamics NAV/365 Business Central Protocol Handler Helper #" -ForegroundColor Cyan
Write-Host "#######################################################################" -ForegroundColor Cyan
Write-Host "# Copyright 2019, Gert Lynge, www.dabbler.dk #" -ForegroundColor Cyan
Write-Host "#######################################################################" -ForegroundColor Cyan
Write-Host "# This script is free to use, modify and distribute as long as these #" -ForegroundColor Cyan
Write-Host "# lines are kept intact. NO WARRANTY! Use at your own risk! #" -ForegroundColor Cyan
Write-Host "#######################################################################" -ForegroundColor Cyan
Write-Host ""
Write-Host "Examples:" -ForegroundColor Cyan
Write-Host ""
Write-Host "Install NAV/365BC Protocol Handler:" -ForegroundColor Cyan
Write-Host "$($MyInvocation.MyCommand.Definition) -InstallProtocolHandler"
Write-Host "Be warned: This will override any existing DynamicsNAV:// protocol handler" -ForegroundColor Red
Write-Host ""
Write-Host "Remove NAV/365BC Protocol Handler:" -ForegroundColor Cyan
Write-Host "$($MyInvocation.MyCommand.Definition) -RemoveProtocolHandler"
Write-Host "Be warned: This will remove any DynamicsNAV:// protocol handler installed" -ForegroundColor Red
Write-Host ""
Write-Host "Show list of NAV/365BC ClickOnce Windows Clients and let you select one to start:" -ForegroundColor Cyan
Write-Host "$($MyInvocation.MyCommand.Definition)"
Write-Host ""
Write-Host "Show this help page:" -ForegroundColor Cyan
Write-Host "$($MyInvocation.MyCommand.Definition) -help"
exit
}
elseif(($args[0] -eq "InstallProtocolHandler") -or ($args[0] -eq "-InstallProtocolHandler")) {
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if(-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Throw "Installing the DynamicsNAV:// Protocol handler requires this script to be run as Administrator"
}
New-PSDrive -Name HKCR -PSProvider Registry -Root "HKEY_CLASSES_ROOT" -ErrorAction SilentlyContinue | Out-Null
New-Item -Path "HKCR:\DynamicsNAV" -Force | Out-Null
New-ItemProperty -Path "HKCR:\DynamicsNAV" -Name "(Default)" -Value "Dynamics NAV Protocol" -Force | Out-Null
New-ItemProperty -Path "HKCR:\DynamicsNAV" -Name "URL Protocol" -Force | Out-Null
New-Item -Path "HKCR:\DynamicsNAV\DefaultIcon" -Force | Out-Null
New-ItemProperty -Path "HKCR:\DynamicsNAV\DefaultIcon" -Name "(Default)" | Out-Null
New-Item -Path "HKCR:\DynamicsNAV\Shell" -Force | Out-Null
New-ItemProperty -Path "HKCR:\DynamicsNAV\Shell" -Name "(Default)" | Out-Null
New-Item -Path "HKCR:\DynamicsNAV\Shell\Open" -Force | Out-Null
New-ItemProperty -Path "HKCR:\DynamicsNAV\Shell\Open" -Name "(Default)" | Out-Null
New-Item -Path "HKCR:\DynamicsNAV\Shell\Open\Command" -Force | Out-Null
New-ItemProperty -Path "HKCR:\DynamicsNAV\Shell\Open\Command" -Name "(Default)" -Value "PowerShell.exe -WindowStyle Hidden -File ""$($MyInvocation.MyCommand.Definition)"" ""%1""" | Out-Null
Write-Host "Protocol Handler DynamicsNAV:// installed" -ForegroundColor Green
exit
}
elseif(($args[0] -eq "RemoveProtocolHandler") -or ($args[0] -eq "-RemoveProtocolHandler")) {
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if(-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Throw "Removing the DynamicsNAV:// Protocol handler requires this script to be run as Administrator"
}
New-PSDrive -Name HKCR -PSProvider Registry -Root "HKEY_CLASSES_ROOT" -ErrorAction SilentlyContinue | Out-Null
Remove-Item -Path "HKCR:\DYNAMICSNAV" -Recurse -Force | Out-Null
Write-Host "Protocol Handler DynamicsNAV:// removed" -ForegroundColor Green
exit
}
$WindowsClients = New-Object System.Data.DataTable
$WindowsClients.Columns.Add("Product","System.String") | Out-Null
$WindowsClients.Columns.Add("Server","System.String") | Out-Null
$WindowsClients.Columns.Add("Port","System.String") | Out-Null
$WindowsClients.Columns.Add("Instance","System.String") | Out-Null
$WindowsClients.Columns.Add("Tenant","System.String") | Out-Null
$WindowsClients.Columns.Add("Authentication","System.String") | Out-Null
$WindowsClients.Columns.Add("Version","System.Version") | Out-Null
$WindowsClients.Columns.Add("Path","System.String") | Out-Null
foreach($File in Get-ChildItem -Path "$SearchPath$WindowsClientFileName" -Recurse | Select-Object FullName) {
$Path = (Split-Path -Path $File.FullName -Parent)
if(Test-Path "$Path\$ClientUserSettingsFileName" -PathType Leaf) {
[xml]$XmlDocument = Get-Content -Path "$Path\$ClientUserSettingsFileName"
$ChildNodes = $XmlDocument.configuration.appSettings.ChildNodes
$WindowsClient = $WindowsClients.NewRow()
$WindowsClient.Path = $Path
$WindowsClient.Version = [System.Version][System.Diagnostics.FileVersionInfo]::GetVersionInfo($File.FullName).FileVersion
$WindowsClient.Server = ($ChildNodes | Where-Object {($_.key -eq "Server")}).value
$WindowsClient.Port = ($ChildNodes | Where-Object {($_.key -eq "ClientServicesPort")}).value
$WindowsClient.Instance = ($ChildNodes | Where-Object {($_.key -eq "ServerInstance")}).value
$WindowsClient.Tenant = ($ChildNodes | Where-Object {($_.key -eq "TenantId")}).value
$WindowsClient.Authentication = ($ChildNodes | Where-Object {($_.key -eq "ClientServicesCredentialType")}).value
$WindowsClient.Product = ($ChildNodes | Where-Object {($_.key -eq "ProductName")}).value
$WindowsClients.Rows.Add($WindowsClient)
}
}
$WindowsClients = $WindowsClients | Group-Object -Property Server,ClientServicesPort,ServerInstance,TenantId | `
foreach { $_.Group | Sort-Object @{Expression="Version";Descending="$True"} | Select-Object -First 1 }
$Picked = $WindowsClients | Out-GridView -PassThru -Title "Select which Microsoft Dynamics NAV/365 Business Central ClickOnce Windows Client to run"
if(-not $Picked) {
exit
}
$Command = "$($Picked.Path)\$WindowsClientFileName"
if($args[0]) {
& "$Command" "-protocolhandler" $args[0]
}
else {
& "$Command"
}
Please run NAVBCProtocolHandlerHelper.ps1 from a powershell CLI with the -help parameter and read the possibilities. It has five ways of running:
Show the help: NAVBCProtocolHandlerHelper.ps1 -help
Install itself as the DynamicsNAV:// protocol handler (OVERWRITING the existing one): NAVBCProtocolHandlerHelper.ps1 -InstallProtocolHandler
Remove ANY DynamicsNAV:// protocol handler (also ones the script did not install itself): NAVBCProtocolHandlerHelper.ps1 -RemoveProtocolHandler
Show list of installed ClickOnce Windows Clients for Dynamics NAV/365 Business Central and lets you choose one. The chosen one is started: NAVBCProtocolHandlerHelper.ps1
Started through the DynamicsNAV:// protocol. A list of installed ClickOnce Windows Clients for Dynamics NAV/365 Business Central will be shown. When you chose one, it is started and the URL is passed as a parameter to it (just like if it was called directly from the protocol handler): DynamicsNAV://<your parameters>
This is still work in progress and can be improved in many ways. Feel free to send me your comments and wishes.
You can use and modify this free of charge as long as you keep the blocks shown in the help intact. This is completely without any warranty of any kind – so use at your own risk! Parameters and functionalities are subject to changes as this is work in progress.