Release Management for VS2013 … and AX : The first tool

In part 1 of this series, we discussed the pro and cons of Release Management for VS2013 and scratched the surface of how we are going to use it with Dynamics AX. As that post has been there for a while, new updates have been available for Release Management (RM from now on) adding some interesting features like deployment agent-less deployment using Desired State Configuration. But anyway, I have been working with RM lately together with my colleague Kevin Roos to automate deployment of daily TFS build drops to a test Dynamics AX 2012 environment. Today I want to start scratching the surface and show you how to create a first tool within RM to clean the AX artifact folders. It is one of the simplest tools that we are going to use but it shows the following:

  • Creating a powershell module that contains generic functions to use with Dynamics AX (The module also takes care of loading other libraries like the ones from Joris De Gruyter)
  • Creating a powershell script to act as a bridge between RM and the PS module
  • Creating a tool and corresponding action to use in RM

So the goal here is to have a tool / action in RM that removes AX artifacts. To achieve this, we use a PowerShell script representing the clean artifacts tool and that script will in it’s turn make use of a generic PowerShell module that contains a library of functions to be used with Dynamics AX 2012.

 Creating the powershell module

First things first, before wiring up RM, let’s create a PowerShell module to contain all kinds of functions to be used with AX. (Cleaning of folders, reading configuration files, starting compilations, …). A good introduction to PowerShell modules can be found on the SimpleTalk blog article : An Introduction to PowerShell modules.

So for our module here, we created a default model manifest and added the following stuff:

RequiredAssemblies = @('CodeCrib.AX.Config.dll', 'CodeCrib.AX.AXBuild.dll', 'CodeCrib.AX.Client.dll')
ModuleToProcess = @('RDAXManagement.psm1')
NestedModules = @('CodeCrib.AX.Config.PowerShell.dll', 'RDAX.CodeCribWrapper.dll')

The RequiredAssemblies line makes sure that the CodeCrib dll files we use are loaded when we load our module. ModuleToProcess shows the module where this definition applies to. And finally, NestedModules will load additional Cmdlets available in the specified dll files.

So, our definition file is ready, let’s create the module file itself. So create a PowerShell file named RDAXManagement.psm1 and put in the following function:

function Clear-AXArtifactFolders
	[Parameter(	Position    = 0, 
			Mandatory   = $true)]
        [Parameter(	Position   = 1, 
			Mandatory  = $true)]

        # Read the client configration file
        $serverConfiguration = Get-ServerConfiguration -filename $serverConfigName
	$serverAltBinDir = $serverConfiguration.AlternateBinDirectory

	$LocalAppDataFolder = [Environment]::GetFolderPath('LocalApplicationData')
	$FolderPath = [string]::Format("{0}Application\Appl\Standard\*",$ServerAltBinDir)
	Write-Host "Cleaning server label artifacts ($FolderPath)"
	Remove-Item -Path $FolderPath -Include ax*.al? -Recurse
	$FolderPath = [string]::Format("{0}XppIL\*",$ServerAltBinDir)
	Write-Host "Cleaning server XppIL artifacts ($FolderPath)"
	Remove-Item -Path $FolderPath -Include *.* -Recurse
	$FolderPath = [string]::Format("{0}VSAssemblies\*",$ServerAltBinDir)
	Write-Host "Cleaning server VSAssemblies artifacts ($FolderPath)"
	Remove-Item -Path $FolderPath -Include *.* -Recurse

	$FolderPath = [string]::Format("{0}\*", $LocalAppDataFolder)
	Write-Host "Cleaning client cache artifacts ($FolderPath)"
	Remove-Item -Path $FolderPath -Include .auc,kti

	$FolderPath = [string]::Format("{0}\Microsoft\Dynamics Ax\*", $LocalAppDataFolder)
	Write-Host "Cleaning client VSAssemblies artifacts ($FolderPath)"
	Remove-Item -Path $FolderPath -Filter "VSAssemblies"

So there we have the first function of our generic library available. It’s time to create a wrapper script that we can attach to a tool within the RM client.

Creating the PowerShell RM tool wrapper

There is a good reason why we use wrapper scripts that are linked to RM tools. By creating several tools, the parameter list passed to a specific tool is smaller than creating one big script having to deal with all of the possible actions/parameter combinations to feed the RDAXManagement PowerShell module. And trust me, some of the tools coming up later already have a bunch of parameter sets to deal with things.

But anyway, create a PowerShell script called RDAXFolderCleaner.ps1 and put in the following code:

< #
	Cleans up the Ax artifacts
	This script will delete cache files, xppil files, label caches, ... from the Ax folders
.PARAMETER AxClientConfigName
	The client configuration to load client side folder metadata
.PARAMETER AxServerConfigName
	The server configuration to load server side folder metadata

    [string]$AxClientConfigName = $(throw "The client configuration file name must be provided."),
    [string]$AxServerConfigName = $(throw "The server configuration file name must be provided.")

# This makes sure that ReleaseManagement also fails the step instead of continuing execution
$ErrorActionPreference = "Stop"


$ExitCode = 0

	# Determine the working directory of the deploy agent
	$InvocationDir 		= Split-Path $MyInvocation.MyCommand.Path

	# Load the Dynamics AX Management PowerShell module
	$AXModuleFileName 	= [string]::Format("{0}\RDAXManagement.psd1", $InvocationDir);
	Import-Module -Name $AXModuleFileName

	# Call the cleanup routine
	Clear-AXArtifactFolders -clientConfigName $AxClientConfigName -serverConfigName $AxServerConfigName

	"`nCleaning of artifacts finished."
Catch [system.exception]
	$ErrorMessage = $_.Exception.Message
	"Error : RM Cleaning of folder failed. Exception message: $ErrorMessage"	
	$ExitCode = 1

exit $ExitCode

So to summarize the above code, the script takes the needed parameters from RM for this specific action and passes them AX generic PowerShell module. Apart from the business logic, the most important line is the one telling PowerShell to stop when an error is encountered. If you do not put this line in there, PowerShell will pop up errors in the log, but RM will just keep on thinking the steps in the release sequence finish successful.

Creating the RM tool and corresponding action

Now that we have the business logic in the PowerShell module and a script that acts as a bridge between RM and the module, let’s create a tool and action for it in RM itself. Tools are used to group several actions that can be done with one and the same tool. In RM, go to the tab page Inventory, select Tools and create a new tool. Then you can setup the tool as in the picture below.


As you can see the tool will invoke PowerShell and pass the folder cleaner tool script. Parameters can be specified by using the double underscores ‘__’ before and after the parameter name. By doing this, the parameters will become available in the workflow shapes later on.

Now we’re almost there, the only thing remaining now is adding the needed resources for the tool. When the Deployment Agent needs to run the tool, it will need the PowerShell script, our module and the related dll files that are used. By adding these references in the bottom part of the tool screen, they get deployed on the Deployment Agent when running the tool. This is actually the easiest way to get the PowerShell scripts of the standard scripts available in RM since you cannot save a local copy of those in the RM client.


So there we have our first tool. The only thing left to do now in this already grossing blog post is creating an action we can use within our deployment sequences. Next to the tools seciont, you can find the Actions tab. Now create a new action as seen below. Notice that when you select the tool this action uses, the command is copied from the tool and can be modified for this action. This is convenient when using the same tool for multiple actions that require different parameter sets.


With all of the in place, you can start using this tool in deployment sequences.


In the following blog posts, we will discuss the Release Paths / Environments and get closer to the actual Release Templates. And in between, Tools and Actions for dealing with custom Dynamics AX stuff will pop up as we go.

Leave a Reply

Your email address will not be published. Required fields are marked *