It’s been quite a while since I posted anything. I’ve been busy working on our Dynamics Additions for NAV. However, I spent a pleasant hour working with PowerShell yesterday afternoon on a solution I thought it was worth sharing.

The Problem

We have several servers in Azure for hosting NAV service tiers. We want some way of checking the licence that has been saved into each database (that doesn’t involve someone connecting the development environment to each database in turn).

The Solution

PowerShell…of course.

The plan is pretty straightforward.

  1. Load the NAV management module
  2. Get a list of service tiers that are running
  3. For each service tier export the licence information and read certain values that we are interested in: account no., name, configuration
  4. Build a custom object to collect the results and present in a GridView

The Code

if ([IO.File]::Exists('C:\Program Files\Microsoft Dynamics NAV\90\Service\Microsoft.Dynamics.Nav.Management.dll')) 
        Import-Module 'C:\Program Files\Microsoft Dynamics NAV\90\Service\Microsoft.Dynamics.Nav.Management.dll'
        Import-Module 'C:\Program Files\Microsoft Dynamics NAV\80\Service\Microsoft.Dynamics.Nav.Management.dll'
    $NAVServers = Get-NAVServerInstance | Where-Object -Property State -eq 'Running'
   $LicenceConfigs = @()
  foreach ($NAVServer in $NAVServers)
        $ServerConfig = Get-NAVServerConfiguration $NAVServer.ServerInstance
        $DatabaseName = ($ServerConfig | Where-Object -Property Key -EQ DatabaseName).Value
        if (($LicenceConfigs | Where-Object -Property Database -eq $DatabaseName).Count -eq 0)
            $LicenceConfig = New-Object System.Object
            $LicenceInfo = Export-NAVServerLicenseInformation $NAVServer.ServerInstance         
            $LicenceConfig | Add-Member -MemberType NoteProperty -Name 'Database' -Value $DatabaseName
            $LicenceConfig | Add-Member -MemberType NoteProperty -Name 'ServerInstance' -Value $NAVServer.ServerInstance
            $LicenceConfig | Add-Member -MemberType NoteProperty -Name 'AccountNo' -Value ([Regex]::Match($LicenceInfo,'VOICE Acc.*:.*').Value.Substring(26)).TrimEnd([Environment]::NewLine)
            $LicenceConfig | Add-Member -MemberType NoteProperty -Name 'Name' -Value ([Regex]::Match($LicenceInfo,'Licensed to *:.*').Value.Substring(26)).TrimEnd([Environment]::NewLine)
            if ([Regex]::Match($LicenceInfo,'Configuration *:.*').Success)
                $LicenceConfig | Add-Member -MemberType NoteProperty -Name 'Configuration' -Value ([Regex]::Match($LicenceInfo,'Configuration *:.*').Value.Substring(26)).TrimEnd([Environment]::NewLine)
                $LicenceConfig | Add-Member -MemberType NoteProperty -Name 'Configuration' -Value ''
            $LicenceConfigs += $LicenceConfig
    $LicenceConfigs | Sort-Object -Property DatabaseName

How it Works

First, we need to load the NAV management module. If it exists in the 90 folder (NAV 2016) use that, if not use the 2015 version in the 80 folder. Clearly, there is room for improvement here. I’ve assumed that NAV is installed in the default path and I’ll also need to change the path when we install a newer version of NAV. It’s a little ugly, but for my purposes this is OK.

Having done that, find NAV service tiers which are running and foreach through them. Find the database that the service tier is connected to and only proceed if we don’t already have a result for that database. We have multiple service tiers connecting to the same database but they will all share the same licence details.

Use the Export-NAVServerLicenseInformation cmdlet to obtain the text of the licence information (the same thing you can find in the development environment with Tools, License Information).

Use Regex to match the particular lines of information that we are interested in and write the values into the properties of a custom object. Add that object to an array and finally sort that array by the DatabaseName property.

Executing Remotely

The above gets us an array of objects with the information that we are after for the local machine. All good and well, but we’ve got several servers that we need to retrieve the information from.

If you haven’t already, run Enable-PSRemoting on each of the severs you need to execute commands on remotely. This punches a hole in the firewall, sets up some security and performs some other wizardry.

First, package all of the above code into a script block. Like so,

$ScriptBlock = { all of the above }

The script will no longer be executed, but saved into the $ScriptBlock variable for later use. We can use it with Invoke-Command like this:

Invoke-Command $ScriptBlock –ComputerName remote_computer_name

The script will be executed on the remote server and results returned to the parent PowerShell session from whence it was called. I want to gather the results from each of the servers and display them into a single output. I can do that with another array, something like the below:

$Results = @()
$Results += Invoke-Command $ScriptBlock -ComputerName first_server 
$Results += Invoke-Command $ScriptBlock -ComputerName last_server
$Results | Out-GridView -Title 'Dynamics NAV Licence Details'

Leave a Reply