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…
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.
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: