PowerShell y los comandos de inicio en Dynamics AX 2012 (PS-III)

En los primeros artículos de esta serie, aprendimos las bases de PowerShell en general, y cómo utilizar librerías de cmdlets extra, incluyendo las que vienen con Microsoft Dynamics AX 2012 y permiten muchas acciones que facilitan la administración y el mantenimiento. PowerShell - jaestevan.com

Pero para poder utilizar PowerShell en nuestros sistemas DevOps reales, debemos unirlo todo y utilizar tanto cmdlets específicos, como la potencia de PowerShell para poder ejecutar todos los pasos necesarios en un despliegue típico de AX, y en muchas otras tareas de mantenimiento.

Empecemos con PowerShell estándar

Por ejemplo podemos utilizar los comandos base de PowerShell para buscar si en el sistema existe un AOS con un determinado nombre, e iniciarlo si no lo está, de esta forma (probablemente no es la mejor forma, pero resulta ilustrativa para este caso):

powershell-aos-service

$AxAOSName = "MicrosoftDynamicsAX"

$svcAOS = Get-Service AOS60* | Where { $_.DisplayName.EndsWith($AxAOSName) } -ErrorAction SilentlyContinue
if (-not ($svcAOS.Length -gt 0))
{
    throw "AOS service " + $AxAOSName + " can not be found."
}

Write-Host "AOS:" $svcAOS.DisplayName

if ($svcAOS.Status -ne 'Running')
{
    Start-Service $svcAOS -PassThru
}

Ejecutar comandos de la consola de Windows (cmd)

Sin embargo, para realizar una acción obligatoria en cualquier estrategia DevOps como es compilar el código X++, necesitamos ejecutar otra aplicación desde PowerShell. En concreto, necesitamos ejecutar AxBuild, el compilador multi-hilo que ejecutamos desde la consola de comandos. Podemos integrarlo como un paso más en nuestros scripts de esta forma:

$axCompiler = Join-Path $AxServerBin "\ax32serv.exe"
$axBuild = Join-Path $AxServerBin "\AxBuild.exe"

$axAosInstance = $svcAOS.Name.Split("$")[1]

Write-Host ("AOS: " + $axAosInstance + ", Compiler: " + $axCompiler)

& $axBuild 'xppcompileall' /compiler="$axCompiler" /log="$LogPath" /altbin="$AxClientBin" /aos="$axAosInstance"

Que da un resultado parecido a este:

PowerShell - AxBuild

Ejecutar ax32.exe con parámetros – SysStartupCmd

Tras compilar nuestro código X++, los siguientes pasos en nuestros procesos suelen ser compilar el código CIL y sincronizar la base de datos. Estas acciones sólo pueden ser iniciadas desde el cliente de AX 2012 (ax32.exe), y así tendremos que hacerlo desde PowerShell. Para iniciar el cliente desde PS tenemos varias opciones, pero las más comunes son:

Pasar un parámetro al ejecutable, de los disponibles en la clase SysStartupCmd. La cantidad de comandos disponibles en esta clase depende de nuestra versión de AX (incluso de las versiones menores), pero pueden ser consultados en la documentación, o más fácil, directamente en el código:

PowerShell - SysStartupCmd

En las últimas revisiones de AX 2012 (en la imagen un AX 2012 R3 CU9) disponemos de una gran variedad de estos comandos, pero en cualquier caso tendremos los básicos para compilar CIL, sincronizar la base de datos, actualizar referencias cruzadas, en algunas versiones importar datos (muy útil por ejemplo para importar casos de prueba antes de ejecutar Unit Test), o para importar datos de configuración en un proceso de despliegue, etc. Vale la pena echar un vistazo a la documentación y el código porque las opciones disponibles nos pueden ser de mucha ayuda en nuestras automatizaciones. Además, fijándonos en las clases que ya existen podemos crear comandos a medida para cubrir necesidades extra.

Para ejecutar estos comandos, nuestro código en PowerShell queda más o menos así:

$axClientBin = "C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin"
$axClient = Join-Path $axClientBin "\ax32.exe"

$argumentList ="-startupcmd=CompileIL", "-lazytableloading", "-lazyclassloading"

Write-Host ("Command: " + $axClient + " " + $argumentList)

Start-Process -FilePath $axClient -ArgumentList $argumentList -Verb RunAs -Wait -PassThru -ErrorAction Stop

El resultado es que nuestro cliente de AX se abre, ejecuta los comandos que pasamos automáticamente, y después se cierra. Mientras el cliente está abierto ejecutando su tarea, el script de PowerShell que lo ha invocado espera a que termine (por el comando -Wait), y cuando el cliente AX se cierra, el script continúa:

PowerShell - StartupCmd - CompileIL

Ejecutar ax32.exe con un XML como parámetro – SysAutoRun

Otra forma muy útil de ejecutar comandos al inicio del cliente es almacenar estos comandos en ficheros XML, de forma que el script de PowerShell sólo tendrá que usar como parámetro uno de esos comandos, y el sistema ejecutará el o los comandos que se hayan incluido. Para automatizar tareas comunes y repetitivas puede hacer el código más legible, pero funciona igual que el caso anterior.

Por ejemplo, utilizando el siguiente fichero XML (la sintaxis completa la podemos encontrar en la documentación, aunque como siempre el código es la documentación más actualizada):

<?xml version="1.0" ?>
<AxaptaAutoRun logFile="C:\TEMP\AXAutorun.log">
  <Synchronize />  
  <UpdateCrossReference />  
</AxaptaAutoRun>

Nuestro script PowerShell quedaría como sigue:

$axClientBin = "C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin"
$axClient = Join-Path $axClientBin "\ax32.exe"

$xmlCmdFile = "C:\TEMP\AXSync.xml"
$argumentList = "-startupcmd=Autorun_" + $xmlCmdFile

Write-Host ("Command: " + $axClient + " " + $argumentList)

Start-Process -FilePath $axClient -ArgumentList $argumentList -Verb RunAs -Wait -PassThru -ErrorAction Stop

Este procedimiento también puede extenderse para añadir nuestros propios comandos, echar un vistazo a la clase SysAutoRun y a la documentación.

El resultado es el mismo que antes:

powershell-xml-command

¡Reutilización!

Ahora que hemos visto todo lo que se puede hacer, mi consejo inicial es: ¡NO lo hagas! Es bueno conocer las bases, pero antes de hacer todas estas tareas manualmente, recomiendo probar alguna de las librerías de PowerShell dedicadas para trabajar con Dynamics AX. En ellas, no sólo se pueden encontrar soluciones para casi todos los casos posibles, sino que se encuentra una base de código inicial muy buena tanto para utilizarla, como para aprender cómo está hecha investigando su código. Antes de desarrollar todo tu proceso desde cero, considera probar alguna librería existente y contribuir a mejorarla.

Recomiendo la siguiente, disponible en CodePlex:

PowerShell Open Sourced!

Ya que hablamos de PowerShell, tengo que comentar la noticia de la semana. El anuncio de Microsoft de hacer PowerShell open-source, y compatible con sistemas Linux, con planes de ampliar esta compatibilidad en el futuro. Más información:

Y en el vídeo del lanzamiento: