- A code repository to store the build templates as well as the WVD Deploy and Update ARM Templates.
- Then use a Build Pipeline. The Pipeline uses that repository as well as an Azure Files SMB file share where we store the Application Install media for apps in our golden image. It then uses Key vault where we store the passwords for access for some sensitive services. This Build Pipeline builds an Azure Managed Image with those apps installed. It uses Hashicorp Packer to do that build.
- The second step uses a Release Pipeline to take that image and use the existing WVD ARM Templates to either build a new Host Pool or update an existing host pool. This will be configured so that we kick off a new build and ADO will not only complete the build but automatically deploy or update the host pool with no further interaction.
This all looks like this:
Click on Create and you will have your new ADO project ready to go:
Step 3. Create a Repo.
On the left Click on Repos.
Leave the defaults and click on Initialize at the bottom.
In the top right click on the Commit button.
In the Commit window just click on the Commit button at the bottom.
Then Browse to the mainTemplate,json file you downloaded earlier, then click on Commit in the bottom right.
Delete the README.md file as that is no longer required. Select the file then click on the ellipsis and Delete.
It is in here that we specify which build of Windows 10 we want. At line 32 we call 19h1-evd:
The application installs are done in this section from lines 79 - 86:
Select App Registrations.
Click on + New Registration.
Click on Register at the bottom.
Select your subscripton, and then Access Control (IAM).
On the right selct Add in the Add a role assignbement section.
Click on Certificates & secrets.
Click on + New client secret.
Enter a description and select an expiration.
The other way which will be quicker is to use Powershell.
Click on Create.
Give it a name and make sure you select the same Azure Region as you would like to deploy your new session hosts.
Click on + File Share:
Give the File share a name and a quota:
Click on Create at the bottom.
Go into the File share and click in Upload
Now upload the application install files and the install cmd files for each.
Select Windows and copy out the whole text:
Name of the Azure Storage Account
Storage account Access Key
AD account for doing doman joins
Password for above account
DevOps SPN App ID
Secret for above
WVD Service Principal Account
Secret for above
You should now have a list like this:
Then click on + Add Access Policy:
Make sure you click on Save at the top.
Step 21. Get those secrets from Key vault and place them in DevOps.
Then click on + Variable Group.
In the Blue Authorize button drop down select Advanced options
This will open the standard AAD authentication dialog. Enter your Azure admin credentials.
Click on Save at the top.
Now add in four new variables:
Your Subscription ID
Your Azure AD Tenant ID
This is the name of the resource group where the build pripeline will place the Image it builds. Use the same Resource Group that has your Key vault and storage account
This is the path to the Azure Files SMB file share. You should have copied this in step 17. It will look like\\packerbuildstore.file.core.windows.net\appinstalls
Click on Next.
Select Service principal (automatic) and Click on Next.
These are the variables we have defined already and should now be obvious what they relate to.
Step 27. Create a Virtual Network for the Image Template VM to reside upon
- We have created a DevOps project, into which we have uploaded the standard WVD ARM deployment and update templates.
- We have also uploaded two JSON templates for the building of a Windows 10 1903 and 1909 image.
- We have created an Azure Files share with software located in it for use in that build.
- We have created a key vault to store sensitive secrets, that we call from the build templates, as well as storing other variables within the project.
Click on Create Pipeline
Select Use the classic editor at the bottom.
Select Azure Repos Git and click on Continue.
In the Agent Job 1 section click on +
On the right type packer in to the search field, and then Select "Packer Tool Installer"
A Copy Files Task:
Click on the Link variable group:
Click the Radio button to the Left of the Azure Key Vault Variables,
Click on Link at the bottom.
Repeat this for your the My Variables Group:
Step 38. Importantly save this Pipeline.
- Installs Packer 1.3.4.
- It then builds an Azure VM using Packer. This build uses four secure variables from Key vault. It creates an output variable of BuildImage.
- It copies the contents of the ARM Templates folder which are the build and update ARM Templates from our Repo into the build artifact directory. They can then be used in our Release pipelines to build a new host pool or update an existing one.
- It then converts our variables into artifacts, so that they are preserved and available for use later in the Release Pipeline.
- It also uses the other variables needed in this pipeline that are not stored in Key vault.
On the Run pipeline screen click on Run at the bottom:
Your build will now commence.
Click on Packer Build in the Jobs section to see the progress:
The progress and any errors will be displayed in the Job run:
That link will take you to the artifacts which will look like this:
- You have typos in the names of your Azure Key vault variables or DevOps variables.
- You have errors in the name and or paths for your Azure File Share. Make sure the names and paths are as defined in the JSON template.
- The Install cmd files or the PS1 files are not correct.
Select Empty Job at the top.
Step 41. Give your host pool a name.
Click on Save at the top and OK
Step 43. Go to the Options tab at the top
Replace the Release name format with: REL$(rev:r). This will be used in the session host naming, and is important this is replaced as without the VM name will be too long.
Click on + Add
The Build Source type is the default, your ADO project will be selected in the Project field.
Select Variable Load Task and click on Add.
Click on Add.
- The Azure Subscription.
- The default action is fine of Create or update resource group.
- The Resource Group you want the Host Pool resources to be created within.
- The desired Location.
In the Override template parameters paste in the following text:
-_artifactsLocation "https://raw.githubusercontent.com/Azure/RDS-Templates/master/wvd-templates/" -_artifactsLocationSasToken "" -rdshImageSource CustomImage -vmImageVhdUri "" -rdshGalleryImageSKU "Windows-10-Enterprise-multi-session-with-Office-365-ProPlus" -rdshCustomImageSourceName $(BuildImage) -rdshCustomImageSourceResourceGroup $(wvd_goldimage_rg) -rdshNamePrefix VM-WVD-$(Release.ReleaseName) -rdshNumberOfInstances 1 -rdshVMDiskType Premium_LRS -rdshVmSize Standard_D2s_v3 -enableAcceleratedNetworking false -rdshUseManagedDisks true -storageAccountResourceGroupName "" -domainToJoin LOCALAD -existingDomainUPN $(DomainJoinAccountUpn) -existingDomainPassword $(DomainJoinAccountPassword) -ouPath OU=WVD,DC=LOCALAD,DC=COM -existingVnetName YOURVNET -newOrExistingVnet existing -existingSubnetName YOURSUBNET -virtualNetworkResourceGroupName YOURRG -rdBrokerURL https://rdbroker.wvd.microsoft.com -existingTenantGroupName "Default Tenant Group" -existingTenantName YOURTENANT -hostPoolName YOURHOSTPOOL -serviceMetadataLocation United-States -enablePersistentDesktop false -defaultDesktopUsers AUSERACCOUNT -tenantAdminUpnOrApplicationId $(WVDServicePrincipalAppID) -tenantAdminPassword $(WVDServicePrincipalSecret) -isServicePrincipal false -aadTenantId $(az_tenant_id) -location "North Europe"
- domainToJoin - this is your FQDN domain name
- existingVnetName - this is your vnet that the WVD Session hosts need to reside upon, i.e. one that has access to your AD DC.
- existingSubnetName - the subnet in the above vNet
- VirtualNetworkResourceGroupName - the RG the above vNet is in
- existingTenantName - your WVD tenants name
- HostPoolName -Your WVD Host Pool Name
- defaultDesktopUsers - a user account to present this published desktop to.
Then Select the Manual only Trigger.
Click on Save at the top and OK.
Click on the Deploy button and then Deploy.
The stage changes to Queued and then to In Progress.
Click on the Pre-Deployment conditions button:
Change the Trigger to After Release:
Change the name of this task to "Update Host Pool".
Click on OK
In the Override template parameters paste in the following:
-_artifactsLocation "https://raw.githubusercontent.com/Azure/RDS-Templates/master/wvd-templates/" -_artifactsLocationSasToken "" -rdshImageSource CustomImage -vmImageVhdUri "" -rdshGalleryImageSKU "Windows-10-Enterprise-multi-session-with-Office-365-ProPlus" -rdshCustomImageSourceName $(BuildImage) -rdshCustomImageSourceResourceGroup $(wvd_goldimage_rg) -rdshNamePrefix VM-WVD-$(Release.ReleaseName) -rdshNumberOfInstances 1 -rdshVMDiskType Premium_LRS -rdshVmSize Standard_D2s_v3 -enableAcceleratedNetworking false -rdshUseManagedDisks true -storageAccountResourceGroupName "" -domainToJoin LOCALAD -existingDomainUPN $(DomainJoinAccountUpn) -existingDomainPassword $(DomainJoinAccountPassword) -ouPath OU=WVD,DC=LOCALAD,DC=com -existingVnetName YOURVNET -newOrExistingVnet existing -existingSubnetName YOURSUBNET -virtualNetworkResourceGroupName YOURRG -rdBrokerURL https://rdbroker.wvd.microsoft.com -existingTenantGroupName "Default Tenant Group" -existingTenantName YOURTENANT -existingHostpoolName WYOURHOSTPOOL -serviceMetadataLocation United-States -enablePersistentDesktop false -tenantAdminUpnOrApplicationId $(WVDServicePrincipalAppID) -tenantAdminPassword $(WVDServicePrincipalSecret) -isServicePrincipal false -aadTenantId $(az_tenant_id) -actionOnPreviousVirtualMachines "Delete" -userLogoffDelayInMinutes 1 -userNotificationMessage "Scheduled maintenance, please save your work and logoff as soon as possible" -location "North Europe"
Click on Create at the bottom
The release task has now started.
This will show you the progress of this task:
There are plenty of other features and capabilities that could be used within this process such as automated testing, but that might get added to a "Part 2" article.