Actualiza automáticamente como…
Actualiza automáticamente como…

Ahora que Microsoft va a actualizar los entornos sandbox adicionales de Dynamics 365 Finance and Operations, los partners y clientes solo nos tendremos que ocupar de los entornos hospedados en la nube (cloud-hosted environments), como hemos hecho siempre.

Estoy seguro de que cada equipo gestiona esto a su manera, quizá dejando que cada desarrollador actualice su máquina, o que hay alguien en el partner que se lo hace. Y eso en el mejor de los casos, quizá nadie actualiza las máquinas de desarrollo…

Si quieres saber más sobre builds, releases y el ALM de desarrollo de Dynamics 365 puedes leer mi guía sobre MSDyn365 y Azure DevOps ALM.

¡Hoy os traigo un script de PowerShell que podemos ejecutar en un pipeline para actualizar automáticamente todas las máquinas de desarrollo!

¡A actualizar se ha dicho!

Como ya he hecho varias veces, voy a usar las d365fo.tools de Mötz Jensen para ejecutar todas las operaciones.

Este es el script al completo:

# CHANGE THIS!!
$AssetId = "LCS_ASSET_ID"
$User = "YOUR_USER"
$Pass = "YOUR_USER_PASSWORD"
$ClientId = "AAD AppId"
$ProjectId = "LCS_PROJECT_ID"
#Get LCS auth token
Get-D365LcsApiToken -ClientId $ClientId -Username $User -Password $Pass -LcsApiUri https://lcsapi.lcs.dynamics.com | Set-D365LcsApiConfig -ProjectId $ProjectId
Get-D365LcsApiConfig
# Get list of all LCS project environments
$Environments = Get-D365LcsEnvironmentMetadata -TraverseAllPages
$StartedEnvs = @()
Write-Host "=================== STARTING ENVIRONMENTS ==================="
Foreach ($Env in $Environments)
{
    # Start Dev VMs only
    if ($Env.EnvironmentType -eq "DevTestDev" -and $Env.CanStart)
    {
        $EnvStatus = Invoke-D365LcsEnvironmentStart -EnvironmentId $Env.EnvironmentId
        if ($EnvStatus.IsSuccess -eq "True") {
            Write-Host ("Environment {0} started." -f $Env.EnvironmentName)
            $StartedEnvs += $Env.EnvironmentId
        }
        else {
            Write-Host ("Environment {0} couldn't be started. Error message: {1}" -f $Env.EnvironmentName, $EnvStatus.ErrorMessage)
        }
    }
}
Write-Host "=================== STARTING ENVIRONMENTS DONE ==================="
Write-Host "=================== SLEEPING FOR 180 seconds ==================="
# Wait 3 minutes for the VMs to start
Start-Sleep -Seconds 180
$Retries = 0
Write-Host "=================== STARTING DEPLOYMENT ==================="
Do
{
    Foreach ($EnvD in $StartedEnvs)
    {
        $EnvStatus = Get-D365LcsEnvironmentMetadata -EnvironmentId $EnvD
        # If the VM has started, deploy the DP
        if ($EnvStatus.DeploymentStatusDisplay -eq "Deployed")
        {
            $OpResult = Invoke-D365LcsDeployment -AssetId $AssetId -EnvironmentId $EnvD
            if ($OpResult.IsSuccess -eq "True") {
                Write-Host ("Updating environment {0} has started." -f $EnvD)
                $StartedEnvs = $StartedEnvs -notmatch $EnvD
            }
            else {
                Write-Host ("Updating environment {0} has failed. Error Message: {1}." -f $EnvD, $OpResult.ErrorMessage)
                Write-Host ("Will retry {0} more time(s)" -f 3 - $Retries)
            }
        }
    }
    $Retries++
} While ($StartedEnvs.Count -ne 0 -or $Retries -eq 3)
Write-Host "=================== STARTING DEPLOYMENT DONE ==================="
Write-Host "Done"

Vamos a ver qué hace paso a paso.

Autenticación y obtener entornos

El primer paso será autenticarse en LCS con el cmdlet Get-D365LcsApiToken y obtener una lista de nuestros entornos con Get-D365LcsEnvironmentMetadata. Esto va a incluir todos los entornos sandbox e incluso producción, pero no hay que preocuparse, no los vamos a actualizar.

En la última línea inicializaremos un array para guardar los ID de los entornos arrancados en el siguiente paso.

# CHANGE THIS!!
$AssetId = "LCS_ASSET_ID"
$User = "YOUR_USER"
$Pass = "YOUR_USER_PASSWORD"
$ClientId = "AAD AppId"
$ProjectId = "LCS_PROJECT_ID"
#Get LCS auth token
Get-D365LcsApiToken -ClientId $ClientId -Username $User -Password $Pass -LcsApiUri https://lcsapi.lcs.dynamics.com | Set-D365LcsApiConfig -ProjectId $ProjectId
Get-D365LcsApiConfig
# Get list of all LCS project environments
$Environments = Get-D365LcsEnvironmentMetadata -TraverseAllPages
$StartedEnvs = @()

Arrancar las máquinas de desarrollo

Ahora que tenemos una lista con los entornos, tenemos que arrancar solo los hospedados en la nube. Lo haremos recorriendo los entornos que obtuvimos en la primera parte y filtrando por la propiedad EnvironmentType cuando sea igual a DevTestDev. Y, usando el comando Invoke-D365LcsEnvironmentStart arrancamos cada máquina.

Ahora comprobamos si la operación ha ido bien o no. Cuando lo hayamos hecho para todas las máquinas, llamaremos a Start-Sleep y les daremos 3 minutos para que terminen de arrancar.

Write-Host "=================== STARTING ENVIRONMENTS ==================="
Foreach ($Env in $Environments)
{
    # Start Dev VMs only
    if ($Env.EnvironmentType -eq "DevTestDev" -and $Env.CanStart)
    {
        $EnvStatus = Invoke-D365LcsEnvironmentStart -EnvironmentId $Env.EnvironmentId
        if ($EnvStatus.IsSuccess -eq "True") {
            Write-Host ("Environment {0} started." -f $Env.EnvironmentName)
            $StartedEnvs += $Env.EnvironmentId
        }
        else {
            Write-Host ("Environment {0} couldn't be started. Error message: {1}" -f $Env.EnvironmentName, $EnvStatus.ErrorMessage)
        }
    }
}
Write-Host "=================== STARTING ENVIRONMENTS DONE ==================="
Write-Host "=================== SLEEPING FOR 180 seconds ==================="
# Wait 3 minutes for the VMs to start
Start-Sleep -Seconds 180

Lanzar los updates

En la parte final iniciaremos los despliegues en cada máquina de las que estén arrancadas. Recorreremos el array que hemos creado al principio, y usando el comando Get-D365LcsEnvironmentMetadata obtendremos su estado, y si está lista llamaremos al despliegue con Invoke-D365LcsDeployment.

Si la operación va bien, quitaremos ese entorno del array y continuaremos, si no lo vamos a volver a probar hasta tres veces (ved que está todo dentro de un Do-While).

$Retries = 0

Write-Host "=================== STARTING DEPLOYMENT ==================="
Do
{
    Foreach ($EnvD in $StartedEnvs)
    {
        $EnvStatus = Get-D365LcsEnvironmentMetadata -EnvironmentId $EnvD

        # If the VM has started, deploy the DP
        if ($EnvStatus.DeploymentStatusDisplay -eq "Deployed")
        {
            $OpResult = Invoke-D365LcsDeployment -AssetId $AssetId -EnvironmentId $EnvD

            if ($OpResult.IsSuccess -eq "True") {
                Write-Host ("Updating environment {0} has started." -f $EnvD)

                $StartedEnvs = $StartedEnvs -notmatch $EnvD
            }
            else {
                Write-Host ("Updating environment {0} has failed. Error Message: {1}." -f $EnvD, $OpResult.ErrorMessage)
                Write-Host ("Will retry {0} more time(s)" -f 3 - $Retries)
            }
        }
    }

    $Retries++
} While ($StartedEnvs.Count -ne 0 -or $Retries -eq 3)

Write-Host "=================== STARTING DEPLOYMENT DONE ==================="

Write-Host "Done"

Y una vez hecho esto deberíamos tener nuestras máquinas desplegando en LCS.

Ejecutándolo en un pipeline

Una vez el script funciona, ejecutarlo en un pipeline es algo trivial, y lo podemos hacer en un pipeline de build o release, a gusto de cada uno. Mi pipeline es así:

Actualizar con un pipeline
Actualizar con un pipeline

Instalo las d365fo.tools en el primer paso con este script:

Install-Module -Name d365fo.tools -AllowClobber -Scope CurrentUser -Force -Confirm:$false

Y en la segunda tarea ejecuto el script de actualización que acabamos de ver al principio de este post.

Por supuesto se puede hacer todo en una única tarea, pero yo prefiero separarlo porque me parece más bonito.

Recuerda, esta no es la automatización que estamos buscando
Recuerda, esta no es la automatización que estamos buscando

Unos consejos

Credenciales

Si vais a ejecutar esto en un pipeline NO pongáis las credenciales de la cuenta de servicio ahí, usad un Azure Key Vault o un grupo de variables con valores secretos:

Grupo de variables en Azure DevOps
Grupo de variables en Azure DevOps

En realidad no es tan automático

Y por supuesto la única parte que es automágica es el arranque y la actualización de las máquinas. Cuando termina el despliegue hay que pararlas. Claro que se puede hacer con otro pipeline que las pare pasadas X horas, tú decides.

Además, si el despliegue falla hay que resumir la operación o arreglar lo que sea que ha ido mal y reintentar, esto es bastante manual.

Y eso es todo, espero que sea de ayuda, sobre todo si tenéis tropocientasmil máquinas, porque ir de una en una en LCS es bastante lento.

¡Suscríbete!

Recibe un correo cuando se publique un nuevo post
Author

Microsoft Dynamics 365 Finance & Operations technical architect and developer. Business Applications MVP since 2020.

Write A Comment

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

ariste.info