ariste.info
  • MSDyn365 & Azure DevOps ALM
  • Get my book!
  • ISV License Generator
  • About me
    • About me
    • Subscribe
    • Contact
  • Logo
  • LinkedIn

Unified experience ALM

  • Welcome to the new ALM guide
    • Introduction
    • Prerequisites
  • Create and prepare Azure DevOps organization and project
    • Create an Azure DevOps organization
    • Create an Azure DevOps project
    • Enable TFVC projects in Azure DevOps
    • Add CI/CD agents with an Azure subscription
  • Unified development environment
    • What are unified developer environments?
    • Transition to a capacity-based model
    • Deploying a unified developer environment using PowerShell
    • Deploy an UDE environment from PPAC
    • Upgrade version in a Unified Development Environment
    • Useful links
  • Using Visual Studio
    • Connect Visual Studio to your UDE
    • Deploy code to a Unified Development Environment
  • Pipelines
    • What’s new in the pipelines?

Legacy Guide

  • Welcome
    • Welcome!
  • Dynamics 365 for Finance & Operations & Azure DevOps
    • Intro
    • Package and model planning
    • Azure DevOps
    • First steps
    • The build server
    • Visual Studio
    • Some advice
    • Branching strategies
  • Azure Pipelines
    • Builds
    • Continuous integration
    • Gated check-ins
    • Set up the new Azure DevOps tasks for Packaging and Model Versioning
  • Azure hosted build for Dynamics 365 Finance & SCM
    • Intro
    • Azure agents
    • How does it work?
    • What do I need?
    • Azure DevOps artifacts
    • Prepare Azure DevOps
    • Configure pipeline
    • Update for version 10.0.18 and greater
  • Azure DevTest Labs powered builds
    • Intro
    • Azure DevTest Labs
    • Getting and preparing the VHD
    • Create a DevTest Labs account
    • Creating the VM
    • Preparing the VM
    • Create a new image
    • Azure DevOps pipelines
    • Run the build
    • Times
    • Show me the money
    • Some final remarks
  • Add and build .NET projects
    • Intro
    • Build .NET in your pipeline
    • Add a C# project to FnO
    • Build pipelinebui
    • Things I don’t like/understand/need to investigate
  • Release Pipelines
    • Intro
    • Setting up Release Pipeline in Azure DevOps for Dynamics 365 for Finance and Operations
    • AAD app creation
    • Create the release pipeline in DevOps
    • Creating the LCS connection
    • New Azure DevOps release tasks: MSAL authentication and ADAL deprecation
  • Automation
    • Update VMs using pipelines and d365fo.tools
    • Builds
    • Releases
    • But I like to add some human touch to it
    • Extra bonus
    • Update a variable in a release
  • LCS DB API
    • Call the LCS Database Movement API from your Azure DevOps Pipelines
    • Automating Prod to Dev DB copies
    • Restore a data package with Azure DevOps Pipelines
  • Secure your Azure Pipelines with Azure Key Vault
    • Azure Key Vault
    • Securing your Azure DevOps Pipelines
View Categories
  • ariste.info
  • Dynamics 365 F&O Dev ALM guide
  • Legacy Guide
  • Azure DevTest Labs powered builds
  • Creating the VM

Creating the VM

We’ve got the essential, a VHD ready to be used as a base to create a virtual machine in Azure. Our next step is finding a way to make the deployment of this VM predictable and automated. We will attain this thanks to Azure ARM templates.

Go back to your DevTest Labs overview page and click the “Add” button, on the “Choose base” page select the base you’ve just created, and on the next screen click on the “Add or Remove Artifacts” link:

Add artifacts to the VM
Add artifacts to the VM

Search for WinRM, select “Configure WinRM”, and on the next screen enter “Shared IP address” as the hostname box and click “Add”.

Note:if when the VM runs the artifacts can’t be installed check whether the Azure VM Agent is installed on the base VHD. Thanks to Joris for pointing this out!

Configure Azure DevOps Agent Service #

Option A: use an artifact #

Update: thanks to Florian Hopfner for reminding me this because I forgot… If you choose Option A to install the agent service you need to do some things first!

The first thing we need to do is running some PowerShell scripts that create registry entries and environment variables in the VM, go to C:\DynamicsSDK and run these:

Import-Module $(Join-Path -Path "C:\DynamicsSDK" -ChildPath "DynamicsSDKCommon.psm1") -Function "Write-Message", "Set-AX7SdkRegistryValues", "Set-AX7SdkEnvironmentVariables" Set-AX7SdkEnvironmentVariables -DynamicsSDK "C:\DynamicsSDK" Set-AX7SdkRegistryValues -DynamicsSDK "c:\DynamicsSDK" -TeamFoundationServerUrl "https://dev.azure.com/YOUR_ORG" -AosWebsiteName $AosWebsiteName "AosService"

The first one will load the functions and make them available in the command-line and the other two create the registry entries and environment variables.

Now we need to add an artifact for the Azure DevOps agent service. This will configure the agent service on the VM each time the VM is deployed. Search for “Azure Pipelines Agent” and click it. You will see this:

DevTest Labs Azure DevOps Agent
DevTest Labs Azure DevOps Agent

We need to fill some information:

On “Azure DevOps Organization Name” you need to provide the name of your organization. For example if your AZDO URL is https://dev.azure.com/blackbeltcorp you need to use blackbeltcorp.

On “AZDO Personal Access Token” you need to provide a token generated from AZDO.

On “Agent Name” give your agent a name, like DevTestAgent. And on “Agent Pool” a name for your pool, a new like DevTestPool or an existing one as Default.

On “Account Name” use the same user that we’ll use in our pipeline later. Remember this. And on “Account Password” its password. Using secrets with a KeyVault is better, but I won’t explain this here.

And, finally, set “Replace Agent” to true.

Option B: Configure Azure DevOps Agent in the VM #

To do this you have to create a VM from the base image you created before and then go to C:\DynamicsSDK and run the SetupBuildAgent script with the needed parameters:

SetupBuildAgent.ps1 -VSO_ProjectCollection "https://dev.azure.com/YOUR_ORG" -ServiceAccountName "myUser" -ServiceAccountPassword "mYPassword" -AgentName "DevTestAgent" -AgentPoolName "DevTestPool" -VSOAccessToken "YOUR_VSTS_TOKEN"

WARNING: If you choose option B you must create a new base image from the VM where you’ve run the script. Then repeat the WinRM steps to generate the new ARM template which we’ll see next.

ARM template #

Then go to the “Advanced Settings” tab and click the “View ARM template” button:

Get the ARM template
Get the ARM template

This will display the ARM template to create the VM from our pipeline. It’s something like this:

{  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",  "contentVersion": "1.0.0.0",  "parameters": {    "newVMName": {      "type": "string",      "defaultValue": "aariste001"    },    "labName": {      "type": "string",      "defaultValue": "aristeinfo"    },    "size": {      "type": "string",      "defaultValue": "Standard_B4ms"    },    "userName": {      "type": "string",      "defaultValue": "myUser"    },    "password": {      "type": "securestring",      "defaultValue": "[[[VmPassword]]"    },    "Configure_WinRM_hostName": {      "type": "string",      "defaultValue": "Public IP address"    },    "Azure_Pipelines_Agent_vstsAccount": {      "type": "string",      "defaultValue": "ariste"    },    "Azure_Pipelines_Agent_vstsPassword": {      "type": "securestring"    },    "Azure_Pipelines_Agent_agentName": {      "type": "string",      "defaultValue": "DevTestAgent"    },    "Azure_Pipelines_Agent_agentNameSuffix": {      "type": "string",      "defaultValue": ""    },    "Azure_Pipelines_Agent_poolName": {      "type": "string",      "defaultValue": "DevTestPool"    },    "Azure_Pipelines_Agent_RunAsAutoLogon": {      "type": "bool",      "defaultValue": false    },    "Azure_Pipelines_Agent_windowsLogonAccount": {      "type": "string",      "defaultValue": "aariste"    },    "Azure_Pipelines_Agent_windowsLogonPassword": {      "type": "securestring"    },    "Azure_Pipelines_Agent_driveLetter": {      "type": "string",      "defaultValue": "C"    },    "Azure_Pipelines_Agent_workDirectory": {      "type": "string",      "defaultValue": "DevTestAgent"    },    "Azure_Pipelines_Agent_replaceAgent": {      "type": "bool",      "defaultValue": true    }  },  "variables": {    "labSubnetName": "[concat(variables('labVirtualNetworkName'), 'Subnet')]",    "labVirtualNetworkId": "[resourceId('Microsoft.DevTestLab/labs/virtualnetworks', parameters('labName'), variables('labVirtualNetworkName'))]",    "labVirtualNetworkName": "[concat('Dtl', parameters('labName'))]",    "vmId": "[resourceId ('Microsoft.DevTestLab/labs/virtualmachines', parameters('labName'), parameters('newVMName'))]",    "vmName": "[concat(parameters('labName'), '/', parameters('newVMName'))]"  },  "resources": [    {      "apiVersion": "2018-10-15-preview",      "type": "Microsoft.DevTestLab/labs/virtualmachines",      "name": "[variables('vmName')]",      "location": "[resourceGroup().location]",      "properties": {        "labVirtualNetworkId": "[variables('labVirtualNetworkId')]",        "notes": "Dynamics365FnO10013AgentLessV2",        "customImageId": "/subscriptions/6715778f-c852-453d-b6bb-907ac34f280f/resourcegroups/devtestlabs365/providers/microsoft.devtestlab/labs/devtestd365/customimages/dynamics365fno10013agentlessv2",        "size": "[parameters('size')]",        "userName": "[parameters('userName')]",        "password": "[parameters('password')]",        "isAuthenticationWithSshKey": false,        "artifacts": [          {            "artifactId": "[resourceId('Microsoft.DevTestLab/labs/artifactSources/artifacts', parameters('labName'), 'public repo', 'windows-winrm')]",            "parameters": [              {                "name": "hostName",                "value": "[parameters('Configure_WinRM_hostName')]"              }            ]          },          {            "artifactId": "[resourceId('Microsoft.DevTestLab/labs/artifactSources/artifacts', parameters('labName'), 'public repo', 'windows-vsts-build-agent')]",            "parameters": [              {                "name": "vstsAccount",                "value": "[parameters('Azure_Pipelines_Agent_vstsAccount')]"              },              {                "name": "vstsPassword",                "value": "[parameters('Azure_Pipelines_Agent_vstsPassword')]"              },              {                "name": "agentName",                "value": "[parameters('Azure_Pipelines_Agent_agentName')]"              },              {                "name": "agentNameSuffix",                "value": "[parameters('Azure_Pipelines_Agent_agentNameSuffix')]"              },              {                "name": "poolName",                "value": "[parameters('Azure_Pipelines_Agent_poolName')]"              },              {                "name": "RunAsAutoLogon",                "value": "[parameters('Azure_Pipelines_Agent_RunAsAutoLogon')]"              },              {                "name": "windowsLogonAccount",                "value": "[parameters('Azure_Pipelines_Agent_windowsLogonAccount')]"              },              {                "name": "windowsLogonPassword",                "value": "[parameters('Azure_Pipelines_Agent_windowsLogonPassword')]"              },              {                "name": "driveLetter",                "value": "[parameters('Azure_Pipelines_Agent_driveLetter')]"              },              {                "name": "workDirectory",                "value": "[parameters('Azure_Pipelines_Agent_workDirectory')]"              },              {                "name": "replaceAgent",                "value": "[parameters('Azure_Pipelines_Agent_replaceAgent')]"              }            ]          }        ],        "labSubnetName": "[variables('labSubnetName')]",        "disallowPublicIpAddress": true,        "storageType": "Premium",        "allowClaim": false,        "networkInterface": {          "sharedPublicIpAddressConfiguration": {            "inboundNatRules": [              {                "transportProtocol": "tcp",                "backendPort": 3389              }            ]          }        }      }    }  ],  "outputs": {    "labVMId": {      "type": "string",      "value": "[variables('vmId')]"    }  }}

NOTE: if you’re using option B you won’t have the artifact node for the VSTS agent.

This JSON file will be used as the base to create our VMs from the Azure DevOps pipeline. This is known as Infrastructure as Code (IaC) and it’s a way of defining our infrastructure in a file as it were code. It’s another part of the DevOps practice that should solve the “it works on my machine” issue.

If we take a look to the JSON’s parameters node there’s the following information:

  • newVMName and labName will be the name of the VM and the DevTest Labs lab we’re using. The VM name is not really important because we’ll set the name later in the pipeline.
  • size is the VM size, a D3 V2 in the example above, but we can change it and will do it later.
  • userName & passWord will be the credentials to access the VM and must be the same we’ve used to configure the Azure DevOps agent.
  • Configure_WinRM_hostName is the artifact we added to the VM template that will allow the pipelines to run in this machine.

To do it faster and for demo purposes I’m using a plain text password in the ARM template, changing the password node to something like this:

"password": {      "type": "string",      "defaultValue": "yourPassword"    },

I will do the same with all the secureString nodes, but you shouldn’t and should instead use an Azure KeyVault which comes with the DevTest Labs account.

Of course you would never upload this template to Azure DevOps with a password in plain text. There’s plenty of resources online that teach how to use parameters, Azure KeyVault, etc. to accomplish this, for example this one: 6 Ways Passing Secrets to ARM Templates.

OK, now grab that file and save it to your Azure DevOps repo. I’ve created a folder in my repo’s root called ARM where I’m saving all the ARM templates:

ARM templates on Azure DevOps
ARM templates on Azure DevOps

Subscribe! #

Receive an email when a new post is published
What are your Feelings
Share This Article :
  • Facebook
  • X
  • LinkedIn
  • Pinterest
Still stuck? How can I help?

How can I help?

Create a DevTest Labs accountPreparing the VM

Write A Comment Cancel Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Table of Contents
  • Configure Azure DevOps Agent Service
    • Option A: use an artifact
    • Option B: Configure Azure DevOps Agent in the VM
  • ARM template
  • Dynamics 365 Community
  • Subscribe!
  • Microsoft MVP
  • LinkedIn
  • Privacy Policy
  • Contact
  • About me

© 2024 ariste.info. Designed by CazaPelusas.

Top

    Type above and press Enter to search. Press Esc to cancel.