When attempting to access the Dynamics NAV Web Client the following error is displayed in the browser:
Dynamics NAV Web Client – Server Error in Application
Server Error in '/' Application.
Configuration Error
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
Parser Error Message: It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS.
Source Error:
Line 8: <compilation debug="false" defaultLanguage="c#" targetFramework="4.0"/>
Line 9: <httpRuntime requestValidationMode="2.0" />
Line 10: <sessionState mode="InProc"/>
Line 11: <trust legacyCasModel="true" level="Full" />
Line 12: <!-- Uncomment to only allow https connection authentication mode
Source File: C:\inetpub\wwwroot\sr-dev\webclient\web.config Line: 10
As the parser error message states above “This error can be caused by a virtual directory not being configured as an application in IIS.”, we need to check that the Web Client directory in IIS has been set as an application. To do this:
Open IIS Manager (hit the Windows key and type IIS) on the server hosting the Web Client components.
Look for the Web Client directory, usually under Sites/Default Web Site.
Expand to show the directory called WebClient, right click on this directory and select Convert to Application:
Web Client Components – Convert to Application
After clicking Convert to Application a dialog box will pop up, click OK. You should notice the icon on the WebClient directory has changed.
Try to open the Web Client again and hopefully the issue is fixed!
Bonus points if anyone can tell me why it broke in the first place…
This week Microsoft Dynamics 365 Business Central was leaked and later officially announced by Microsoft as the new name for Dynamics 365 for Finance and Operations Business Edition (Microsoft’s cloud version of Dynamics NAV). Business Central is offering the full Dynamics NAV functionality in the cloud, as apposed to Dynamics 365 for Finance and Operations Business Edition’s slimmed down functionality.
Previously code named as Dynamics 365 Tenerife, many (myself included) were hoping that NAV would find some place in the new name. Alas , that was not to be, but the new name “Business Central” does make a lot more sense than the pseudo-acronym “NAV”… and at least it’s more catchy than “Dynamics 365 for Finance and Operations Business Edition”.
Counter to earlier reports, we will not be seeing Dynamics NAV 2018 R2 released with Dynamics 365 Business Central. Instead, Microsoft will release the new re-branded version of Dynamics NAV as Dynamics 365 Business Central (Hosted / On-premise) in autumn 2018.. Cumulative updates for Dynamics NAV 2018 will be released as normal.
Dynamics NAV / Dynamics 365 Business Central Roadmap
To update Dynamics NAV licenses of multiple databases used to be a bit of a headache. We have customers running independent NAV instances in the hundreds using LS Retail POS. Imagine having to log into each machine manually:
Connect to the remote host.
Upload the Dynamics NAV license file to the remote host.
Import the license file.
Restart the Dynamics NAV Service Tiers.
Maybe you have multiple development / test machines which need a yearly license update?
In this blog post I demonstrate how you can update NAV licenses on multiple remote hosts all from the comfort of your own PowerShell prompt. Hopefully, along the way you’ll pick up some PowerShell tricks to make your life easier!
Update Dynamics NAV License Centrally on Multiple NAV Servers
Before we get started there are a few prerequisites to this technique:
The remote hosts are on the same domain.
The user account running the PowerShell script has local admin on the host.
Connecting to a remote host with PowerShell
PowerShell comes with a utility called PowerShell Remoting. This allows us to connect to remote servers which have PowerShell Remoting enabled. Windows Server 2012 R2 and above have PowerShell Remoting enabled by default, but if we need to enable this manually we can run the following command on the host:
> Enable-PSRemoting -force
If the -force option is not used a prompt asking if we want to continue will occur.
A password prompt will appear if we specify a user account.
The Enter-PSSession cmdlet is handy when we want to enter into an interactive session with a remote host, but it will come up short when we want to start automating our scripts.
New-PSSession is used to create a PowerShell session. This session can be a remote session and we can assign this session to a variable. This session variable can be used with the Invoke-Command cmdlet.
For example, we could create a remote session and get a list of services on the remote host with:
In a scenario where we have a list of remote hosts to process, we will likely want to keep a note of any hosts that fail to respond. A simple method is to write any failures out to a text file. We can catch these failures in a try / catch block:
The Add-Content cmdlet will append values to the end of the file specified, creating the file if it doesn’t exist.
Send the local NAV license file to the host machine
I thought about a few options for getting the license file on the host machine:
Put the license file on a web server or fileshare and download from the host.
Copy the file through the Copy-Item Cmdlet using the -FromSession parameter.
But the most convenient in this scenario is to put the license data in a byte array and pass it into the Import-NAVServerLicense Cmdlet using the -LicenseData parameter.
To create a byte array from the NAV license file we can use the following code:
$LicenseData now contains the new NAV license, but we’ve created this variable in our local PowerShell session. Once we’ve created the remote session we will need to pass this variable in to the script block we are going to execute in the remote session. To do this, we can utilise script block parameters:
You may have noticed the -ArgumentList value looks a bit weird: (,$LicenseData). This is because the -ArgumentList parameter expects an array value, and will pass our byte array through as individual elements. That said, I’ve no idea why this syntax works… Stack Overflow to the rescue!
If you don’t use the (,$ArrayVar) syntax, expect an error message like this:
So far we can create a remote session, move the license data to the remote host and execute script block on the remote host. Next we need to import the license into the remote Dynamics NAV instance. This is done using the Import-NAVServerLicense cmdlet:
> Import-NAVServerLicense <NAV Service Instance> -LicenseData <License Data>
The minimum parameters we need are the Dynamics NAV service instance name and the license data. We’ve already got the license data in the $LicenseData byte array, so lets look at getting a service to use.
To make this simple, I’m going to apply the license to any running services on the host. I’ve blogged about getting running services previously, here’s some PowerShell to return the service names of any running NAV services:
The following script will get a list of running Dynamics NAV services, apply the license using the first service found and then restart all Dynamics NAV services:
# Put license data in Byte array
[Byte[]]$LicenseData = Get-Content -Path "C:\Temp\License.flf" -Encoding Byte
# Get list of running NAV services
$NAVServices = Get-NAVServerInstance | Where-Object {$_.State -eq 'running'} | Select-Object -ExpandProperty "ServerInstance"
# If variable is an array get the first index
If ($NAVServices -is [array]) {
$NAVService = $NAVServices[0]
} else {
$NAVService = $NAVServices
}
# Check we have a NAV service before we try to import a license
if (-Not [string]::IsNullOrEmpty($NAVService)) {
Import-NAVServerLicense $NAVService -LicenseData $LicenseData
}
# Restart the service(s)
Restart-Service -Name $NAVServices
Putting it all together: Update Dynamics NAV Licenses on remote machines
OK, we’ve run through all the parts. Lets put this all in to one script:
# Array of host machines
$RemoteHosts = "NAVSERV01", "NAVSERV02", "NAVSERV03"
# Text file with list of host machines
# $RemoteHosts = Get-Content -Path "C:\Temp\NAVHostsList.txt"
[Byte[]]$LicenseData = Get-Content -Path "C:\Temp\License.flf" -Encoding Byte
$ScriptBlock = {
param ($LicenseData)
Import-Module 'C:\Program Files\Microsoft Dynamics NAV\110\Service\NAVAdminTool.ps1'
$NAVServices = Get-NAVServerInstance | Where-Object {$_.state -eq 'running'} | Select-Object -ExpandProperty "ServerInstance"
# If variable is an array get the first index
If ($NAVServices -is [array]) {
$NAVService = $NAVServices[0]
} else {
$NAVService = $NAVServices
}
# Check we have a NAV service before we try to import a license
if (-Not [string]::IsNullOrEmpty($NAVService)) {
Import-NAVServerLicense $NAVService -LicenseData $LicenseData
# Restart the service(s)
Restart-Service -Name $NAVServices
}
}
foreach ($RemoteHost in $RemoteHosts) {
try {
$session = New-PSSession -Computer $RemoteHost
Invoke-Command -Session $session -ScriptBlock $ScriptBlock -ArgumentList (,$LicenseData)
} catch {
Add-Content -Path "C:\Temp\ErrorLog.txt" -Value ("Error updating license on: " + $RemoteHost)
}
}
Whilst this does the job, there is plenty of room for improvement. Error handling is very lightweight for a start. Issues connecting to a remote host will be logged in the ErrorLog file, but if any errors occur in the remote session you’ll only be able to view them from the console output. Also, this script only allows for a single version of NAV and assumes all services on a remote host are connected to the same database.
So, feel free to use and adapt this script.. but do so at your own risk.
Update: Since Docker 1.13 (API version 1.25) the prune command has been available. You can remove all unused images with > docker image prune –all
If like me, you’ve been experimenting with Docker since Microsoft made the Dynamics NAV images available, you’ll probably notice you’re using up a fair bit of hard drive space. So how do we remove Docker Images?
Dynamics NAV Docker Images
The image above is a tad misleading however, as Docker shares images saving space. The microsoft/windowsservercore image for example is around 10GB, and is reused by all the other Dynamics NAV images. The size you see in the screenshot above is the total size of the image if you were to save an archive using the docker save command. Still, my Docker folder was somewhere around 40-50GB in size.
So today I decided to have a clean up and remove all the images from my machine. I could have removed each image one by one using docker rmi:
Docker tip: When referencing Docker Image or Containers in Docker commands, for brevity, you can use the first x number of characters of the Image or Container ID. Where x is the minimum number needed to identify a unique ID on your system. The first three characters will be fine in most cases.
But.. repetition is a computers job right?
To automate this we’ll need to get a list of our Docker Image IDs and pass them to the docker rmi command.
To get a list of Image IDs on our system, we can use the docker images command with the -q option:
Get Docker Image IDs
We can then take the list of image IDs and iterate through them using a PowerShell foreach statement:
So far so good.. we can remove Docker images with a PowerShell script. But what if we want to keep the base image? It’s around 12GB, so we probably don’t want to download it again next time we pull a NAV image.
The docker images command takes the repository name as an optional parameter. We can use this to filter on our NAV images:
> docker images microsoft/dynamcis-nav
List NAV Docker Images
Keeping the base image
The problem is, unless we’ve explicitly requested the base image it doesn’t show up in our image list. This means it will get removed with the last NAV image referencing it. To get around this we just need to do a pull request for the base image.
To understand this concept, it’s important to know that Docker images are built in layers. Instead of building an entire image from scratch every time, when creating an image you can base it on an existing image. All Dynamics NAV images are built on an image called microsoft/nav-docker. Docker images can be built from a Dockerfile. We can view the Dockerfile for microsoft/nav-docker and see that this image is currently based on the microsoft/dotnet-framework:4.7-windowsservercore image.
So back to the pull request:
> docker pull microsoft/nav-docker
Cant Pull nav-docker Image
Microsoft has restricted access, or just not published this image. We can use the image that microsoft/nav-docker is based on instead:
Running this command didn’t download the image again as Docker found it locally. However, it will now list the microsoft/dotnet-framework:4.7-windowsservercore image alongside our NAV images:
Docker Images with a base image available
As we can see from the size attributes, the 4.7-windowsservercore image makes up the bulk of the NAV image size.
To remove all the microsoft/dynamics-nav images but leave the microsoft/dotnet-framework image for later use, we can run the following PowerShell script:
To have a look at another filtering option lets explore another scenario. What if we want to keep the most recently pulled NAV image, but remove Docker images previous to this?
The docker images command has a –filter option. We can use this to filter on the image created date. It’s important to note that this is based on the time the images were created on your system (when it was pulled), not when the vendor created or published the image.
Using a before filter we can get a list of all image IDs that where pulled before microsoft/dynamics-nav:latest:
So far we’ve used a foreach loop to iterate through the list of image IDs we get back from the docker images command. I think this approach makes the script easier to read, but we can also use this list directly with the docker rmi command on the same line:
The Microsoft.Dynamics.Nav.Server.exe.config file is found in the Dynamics NAV service install directory, which (if you accepted the default) will be in the following location:
The following field must be included into the table’s primary key:
The following field must be included into the table’s primary key: Field User Name Table: User
The issue originates in the TableRelation property of the underlying table. In this instance, a field (“User ID”) on a custom table is using the User table for lookup:
The field used in the TableRelation property (“User Name”) must be part of the primary key of the related table (User). Although the User table has “User Name” defined as a secondary key, it is not part of the primary key.
Standard NAV table User Setup (Table ID 91) provides a solution to this issue:
As you can see in the image above, the ValidateTableRelation Property has been set to “No”. This allows the user to enter any value in the field without NAV validating that the record exists in the related table, which will avoid the error, but still allow the user to lookup the User ID in the User table.
If you set the ValidateTableRelation property to No, then you should also set the TestTableRelation property to No. Otherwise, a database test on the field relations in a database may fail.
Instead, Microsoft have added code to validate that the User Name specified exists which replaces the ValidateTableRelation property.
This means a a test on the field relations should pass, as the table relation test includes secondary keys:
[TestTableRelation] Sets whether to include this field when evaluating field relations between primary and secondary indexes.
In conclusion
Setting the ValidateTableRelation field property to “No” can be used to stop NAV from validating a foreign key relationship, whilst still enabling the standard lookup functionality via the TableRelation property. If you do set this property to “No”, you’ll most likely want to create your own validation in code (OnValidate trigger for instance), or if you really don’t care if the value exists in the related table, then set the TestTableRelation property to “No”.
In this blog post I explain how you can restart Dynamics NAV services with Powershell, while also exploring a few of the available Cmdlets for selecting services and properties.
Restarting a NAV service
Restart-Service is a standard Powershell Cmdlet that will stop and then start Windows services. If the service is already stopped, then it will simply start the service.
Restarting the default NAV 2017 service can be done as follows:
The unnamed parameter ‘MicrosoftDynamicsNavServer$DynamicsNAV100’ is the service name, this is always the Dynamics NAV Server instance name prefixed with MicrosoftDynamicsNavServer$.
The properties of the default NAV 2017 service
Restarting multiple NAV services
Restarting multiple services can be done simply by using the * wildcard in the service name parameter:
The above command will restart every service with a name beginning with MicrosoftDynamicsNavServer.
So far the services selected for restart have been very indiscriminate, we’ve simply restarted all NAV services on the machine… What if we need to be a bit more selective?
Get-Service provides us with the ability to get objects representing Windows services. To get all services on your machine run Get-Service with no parameters:
PS C:\Windows\System32>Get-Service
The above command will print out a list of services and there statuses:
Output of the Get-Service Cmdlet
The same wildcard used for the Restart-Service Cmdlet can be used with Get-Service using the -Name parameter:
Get running NAV services with Get-Service and Where-Object
The output of Where-Object can be piped into Restart-Service.. so by piping Get-Service into Where-Object into Restart-Service, we can now restart all currently running NAV services with the following:
As always, there are many ways to skin a cat.. We could also approach this problem from another direction. The Get-NavServerInstance Cmdlet is available in the NavAdminTool.ps1 script file found in the NAV service folder. The script file will need to be loaded into your Powershell environement using the Import-Module Cmdlet:
You can change the execution policy using the Execution-Policy Cmdlet. In the following image you can see that I get the current execution policy for reference and then after changing the execution policy, I am able to run the Import-Module Cmdlet:
Powershell change execution policy
For security reasons it’s good practice to change the execution policy back:
Get-NavServerInstance returns a list of NAV services, but the output is not compatable with the Restart-Service Cmdlet:
Output of Get-NavServerInstance
We can however pipe the output into the Select-Object Cmdlet which we can use to get the service names as string objects: PS C:\Windows\system32> Get-NavServerInstance | Select-Object -ExpandProperty "ServerInstance"
Get-NavServerInstance ServerInstance Property
The string objects can then be piped directly into the Restart-Service Cmdlet:
Occasionally when working with Lanham Pack Line Scanning for Dynamics NAV a single item needs to be shipped in two (or more) separate packages. In this blog post I’ll offer two solutions to this issue.
Solution 1 – Empty Package
This can be achieved using the create extra package command (//CEP) which will create an “empty” Package record. For example:
Open order
Scan item
Close package
Create empty package (//CEP)
Close package
Close order
A drawback of solution 1 is that the empty package won’t have any package lines and won’t be associated with any items.
Solution 2 – Part Quantities
Another solution is to manipulate the item quantity on the package to only assign part of the item. For example packing a single NAV item in two packages could be done with a quantity of 0.5 in each package:
Open order
Scan item
Open Package Card
Change quantity to 0.5
Close package
Scan item again (This will display over pack warning)
Open Package Card
Change quantity to 0.5
Close package
Close order
This solution has a few more steps, but will result in the package being associated with an item.
I recently had an issue where a customer was importing sales orders into Dynamics NAV 2015 from their website using a third-party interface module. Shipping charges were being created as G/L Account sales order lines. The orders were being processed using the Lanham WMS and E-Ship modules.
The problem was that when the Lanham Pack Line Scanning close order command was given, the packed item lines were being shipped and invoiced correctly, but the the shipping charges were being ignored stopping the sales order from being completely shipped and invoiced.
What I found was that Lanham have modified Codeunit 7324 Whse. Activity Post (function; InitSourceDocument) to set the Quantity To Ship to zero if the function AllowInWarehousePosting() of the Sales Line table returns false.
The fix was to set the Shipping Charge field (field number 14000701) to true on Sales Line records for the shipping charge lines. Note; the Shipping Charge field is not available on the Sales Order Card so will require a customisation if the shipping charge lines are to be added manually.
A handy tip for when you want to export all the NAV Objects you can in text format but you keep getting licence permission errors when hitting objects out of your licence range (third-party add-ins for instance).
The Lock function in the NAV Development Environment allows you to lock an object to stop other developers modifying objects you’re currently working on. Why am I telling you this? Well, a nice little feature of Lock is it will only lock Objects in the current licence range… Thus, If you select all objects from the Object Designer and invoke the Lock function (File->Lock or Ctrl+Alt+L) you can now filter on all locked objects.
Finding Unlicensed Objects
Tip #2: You want to test a NAV licence against the Objects in a database. In the NAV Development Environment change the licence to the one you wish to test and attempt to lock all objects (as described above). Filtering on the Objects where locked = No will give you a list of all unlicensed Objects.