Coffee Break: Use the PowerShell Runner Add-In

In this post we will look how to run your Windows PowerShell scripts using your favorite application: Dynamics NAV 🙂 . This can be done using .NET Framework libraries, but Microsoft Dynamics NAV 2016 also released an add-in called PowerShellRunner (found in service add-in folder). Libraries found here can be used to run PowerShell scripts from the Dynamics NAV client, for any scenario you might see useful. For example: avoiding using separate  msc service management consoles : manage your services from your Dynamics NAV client instead 🙂 ;  manage backup/restore or provisioning test or production environments; export, merge, compile objects, and so on.

So as an illustration, let us consider the following user scenario. Our customer is a small distribution company, somewhere in the snowy town of Drøbak (Norway). Their chief of operations (we’ll refer to him as S.Claus) is out on the road distributing goods for most of the December, and needs a possibility to provision companies, add requests, updates and do some general management ad-hoc in a simple manner, using his smartphone (for best network coverage in all sorts of remote places).

For this, his assistants have used the PowerShellRunner add-in and created a management interface in Dynamics NAV that S.Claus will use from his phone app.

They found the PowerShellRunner add-in in the service folder on the product media with all other add-ins, and they added it to the add-in table.

In its simplest, most basic form, running a PowerShell command would look something like this:

  1. Declare PowerShellRunner as a variable of type DotNet.
  2.  Create an instance of  PowerShellRunner.
  3. Tell PowershellRunner to write to the event log.
  4. Import the modules from PowerShellRunner.
  5. Set the various parameters for connection to a Dynamics NAV instance.
  6. Run the relevant cmdlets.

The following code snippet illustrates the kind of codeunit that S.Claus’ assistants might have written:

OBJECT Codeunit 50020 PS RUNNER
{
 OBJECT-PROPERTIES
 {
 Date=12/18/15;
 Time=[ 4:32:03 PM];
 Modified=Yes;
 Version List=;
 }
 PROPERTIES
 {
 OnRun=VAR
 PowerShellLogEntry@1000 : Record 8060;
 BEGIN
 AddService;
 EnableDebugging;
 StartService;
 MountTenant;
 END;

 }
 CODE
 {
 VAR
 PowerShellRunner@1000 : DotNet "'Microsoft.Dynamics.Nav.PowerShellRunner, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.Microsoft.Dynamics.Nav.PowerShellRunner";
 PSObject@1001 : DotNet "'System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.System.Management.Automation.PSObject";
 ResultEnumerator@1004 : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Collections.Generic.IEnumerator`1";
 ErrorEnumerator@1003 : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Collections.Generic.IEnumerator`1";
 Created@1002 : Boolean;
 LogOut@1005 : OutStream;
 Result@1006 : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.String";

 LOCAL PROCEDURE AddService@1();
 BEGIN
 PowerShellRunner := PowerShellRunner.CreateInSandbox;
 PowerShellRunner.WriteEventOnError := TRUE;
 //to enable logging

 //To import modules
 PowerShellRunner.ImportModule('C:\Program Files\Microsoft Dynamics NAV\90\Service\Microsoft.Dynamics.Nav.Management.dll');

 PowerShellRunner.AddCommand('New-NAVServerInstance');
 PowerShellRunner.AddParameter('ServerInstance','ProdNAV');
 PowerShellRunner.AddParameter('ManagementServicesPort','7055');
 PowerShellRunner.AddParameter('ClientServicesPort','7056');
 PowerShellRunner.AddParameter('SOAPServicesPort','7057');
 PowerShellRunner.AddParameter('ODataServicesPort','7058');
 PowerShellRunner.AddParameter('DatabaseServer','MyServerName');
 PowerShellRunner.AddParameter('DatabaseInstance','NAVDEMO');
 PowerShellRunner.AddParameter('DatabaseName','MyProd');
 PowerShellRunner.AddParameter('ServiceAccount','NetworkService');




 //Result := PowerShellRunner.GetLogMessageList;
 PowerShellRunner.WriteEventOnError := TRUE;
 //Created := TRUE

 PowerShellRunner.BeginInvoke;
 END;

 LOCAL PROCEDURE EnableDebugging@2();
 BEGIN
 PowerShellRunner := PowerShellRunner.CreateInSandbox;
 //PowerShellRunner.WriteEventOnError := TRUE;

 //To import modules
 PowerShellRunner.ImportModule('C:\Program Files\Microsoft Dynamics NAV\90\Service\Microsoft.Dynamics.Nav.Management.dll');

 PowerShellRunner.AddCommand('Set-NAVServerConfiguration');
 PowerShellRunner.AddParameter('ServerInstance','ProdNAV');
 PowerShellRunner.AddParameter('KeyName','EnableDebugging');
 PowerShellRunner.AddParameter('KeyValue','True');
 PowerShellRunner.BeginInvoke;
 END;

 LOCAL PROCEDURE StartService@3();
 BEGIN
 PowerShellRunner := PowerShellRunner.CreateInSandbox;

 PowerShellRunner.ImportModule('C:\Program Files\Microsoft Dynamics NAV\90\Service\Microsoft.Dynamics.Nav.Management.dll');

 PowerShellRunner.AddCommand('Set-NavServerInstance');
 PowerShellRunner.AddParameter('ServerInstance','ProdNAV');
 PowerShellRunner.AddParameter('Start');
 PowerShellRunner.BeginInvoke;
 END;

 LOCAL PROCEDURE MountTenant@4();
 BEGIN
 //new service is created as multitenant. To run a single tenant database, simply mount it.

 PowerShellRunner := PowerShellRunner.CreateInSandbox;

 PowerShellRunner.ImportModule('C:\Program Files\Microsoft Dynamics NAV\90\Service\Microsoft.Dynamics.Nav.Management.dll');

 PowerShellRunner.AddCommand('Mount-NAVTenant');
 PowerShellRunner.AddParameter('ServerInstance','ProdNAV');
 PowerShellRunner.AddParameter('Id','default');
 PowerShellRunner.AddParameter('DatabaseName','MyProd');
 PowerShellRunner.BeginInvoke;
 END;

 BEGIN
 END.
 }
}

In this example, ProdNAV is the name of the server instance, and MyProd is the name of the production database, in this case a restore of the demonstration database.

All of this is running server-side, so to be able to execute this, your service account (on the service that you are running this from), has to be a member of the administrators’ group. Then you can manage all other services, databases, and so on from one management service.
Add to this a bit of database structure and simple GUI, and S.Claus can roam the world with all his operations available at the flick of his thumb.

The coffee break team and the rest of the Dynamics NAV team wishes all of you:

Happy Holidays!