Building Azure VM Images Using Packer & Azure Files

In this post, I will explain how I am using a freeware package called Packer to create SYSPREPed/generalised templates for Citrix Cloud / Windows Virtual Desktop (WVD) – including installing application/software packages from Azure Files.

My Requirement

Sometimes you need an image that you can quickly deploy. Maybe it’s for a scaled-out or highly-available VM-based application. Maybe it’s for a Citrix/Windows Virtual Desktop worker pool. You just need a golden image that you will update frequently (such as for Windows Updates) and be able to bring online quickly.

One approach is to deploy a Marketplace image into your application and then use some deployment engine to install the software. That might work in some scenarios, but not well (or at all) in WVD or Citrix Cloud scenarios.

A different, and more classic approach, is to build a golden image that has everything installed and then the  VM is generalised to create an image file. That image file can be used to create new VMs – this is what Citrix Cloud requires.

Options

You can use classic OS deployment tools as a part of the solution. Some of us will find familiarty in these tools but:

  • Don’t waste your time with staff under the age of 40
  • These tools aren’t meant for the cloud – you’ll have to daisy chain lots of moving parts, and that means complex failure/troubleshooting.

Maybe you read about Azure Image Builder? Surely, using a native image building service is the way to go? Unfortunately: no. AIB is a preview, driven by scripting, and it fails by being too complex. But if you dig into AIB, you’ll learn that it is based on a tool called Packer.

Packer

Packer, a free tool from Hashicorp, the people behind Terraform, is a simple command line tool that will allow you to build VM images on a number of platforms, including Azure ARM. The process is simple:

  • You build a JSON file that describes the image building process.
  • You run packer.exe to ingest that JSON file and it builds the image for you on your platform of choice.

And that’s it! You can keep it simple and run Packer on a PC or a VM. You can go crazy and build a DevOps routine around Packer.

Terminology

There are some terms you will want to know:

  • Builders: These are the types of builds that Packer can do – the platforms that it can build on. Azure ARM is the one I have used, but there’s a more complex/faster Builder for Azure called chroot that uses an existing build VM to build directly into a managed disk. Azure ARM builds a temporary VM, configures the OS, generalises it, and converts it into an image.
  • Provisioners: These are steps in the build process that are used to customise your operating system. In the Windows world, you are going to use the PowerShell provisioner a lot. You’ll find other built in provisioners for Ansible, Puppet, Chef, Windows Restart and more.
  • Custom/Community Provisioners: You can build additional provisioners. There is even a community of provisioners.

Accursed Examples

If you search for Windows Packer JSON Files, you are going to find the same file over and over. I did. Blog posts, powerpoints, training materials, community events – they all used the same example: Deploy Windows, install IIS, capture an image. Seriously, who is ever going to want an image that is that simple?

My Requirement

I wanted to build a golden image, a template, for a Citrix worker pool, running in Azure and managed by Citrix Cloud. The build needs to be monthly, receiving the latest Windows Updates and application upgrades. The solution should be independent of the network and not require any file servers.

Azure Files

The last point is easy to deal with: I put the application packages into Azure Files. Each installation is wrapped in a simple PowerShell script. That means I can enable a PowerShell provisioner to run multiple scripts:

      “type”: “powershell”,
      “scripts”: [
        “install-adobeReader.ps1
        “install-office365ProPlus.ps1”
      ]
This example requires that the two scripts listed in the array are in the same folder as packer.exe. Each script is run in turn, sequentially.

Unverified Executables

But what if one of those scripts, like Office, wants to run a .exe file from Azure Files? You will find that the script will stall while a dialog “appears” (to no one) on the build VM stating that “we can’t verify this file” and waits for a human (that will never see the dialog) to confirm execution. One might think “run unlock-file” but that will not work with Azure Files. We need to update HKEY_CURRENT_USER (which will be erased by SYSPREP) to truse EXE files from the FQDN of the Azure Fils share. There are two steps to this, which we solve by running another PowerShell provisioner:
    {
      “type”: “powershell”,
      “scripts”: [
        “permit-drive.ps1”
      ]
    },
That script will run two pieces of code. The first will add the FQDN of the Azure Files share to Trusted Sites in Internet Options:

set-location “HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains”
new-item “windows.net”
set-location “Windows.net”
new-item “myshare.file.core”
set-location “myshare.file.core”
new-itemproperty . -Name https -Value 2 -Type DWORD

The second piece of code will trust .EXE files:

set-location “HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies”
new-item “Associations”
set-location “Associations”
new-itemproperty . -Name LowRiskFileTypes -Value ‘.exe’ -Type STRING

SYSPREP Stalls

This one wrecked my head. I used an inline PowerShell provisioner to add Windows roles & features:

      “type”: “powershell”,
      “inline”: [
        “while ((Get-Service RdAgent).Status -ne ‘Running’) { Start-Sleep -s 5 }”,
        “while ((Get-Service WindowsAzureGuestAgent).Status -ne ‘Running’) { Start-Sleep -s 5 }”,
        “Install-WindowsFeature -Name Server-Media-Foundation,Remote-Assistance,RDS-RD-Server -IncludeAllSubFeature”
      ]
But then the Sysprep task at the end of the JSON file stalled. Later I realised that I should have done a reboot after my roles/features add. And for safe measure, I also put one in before the Sysprep:
    {
      “type”: “windows-restart”
    },
You might want to run Windows Update – I’d recommend it at the start (to patch the OS) and at the end (to patch Microsoft software and catch any missing OS updates). Grab a copy of the community Windows-Update provisioner and place it in the same folder as Packer.exe. Then add this provisioner to your JSON – I like how you can prevent certain updates with the query:
    {
      “type”: “windows-update”,
      “search_criteria”: “IsInstalled=0”,
      “filters”: [
        “exclude:$_.Title -like ‘*Preview*'”,
        “include:$true”
      ]
    },

Summary

Why I like Packer is that it is simple. You don’t need to be a genius to make it work. What I don’t like is the lack of original documentation. That means there can be a curve to getting started. But once you are working, the tool is simple and extensible.

Microsoft Ignite 2018: Office in Virtual Desktop Environments

Speakers: Gama Aguilar-Gamez & Sandeep Patnik

Goal: Make Office 365 Pro Plus a first class experience in virtualized environments.

Windows Virtual Desktop

  • The only mutli-user Windows 10 experience – note that this is RDmi and it also supports session hosts.
  • Optimized for Office 365 Pro Plus
  • Deploy and scale in minutes

Windows 10 Enterprise Multi-User

  • Scalable multi-user modern Windows user experience with Windows 10 Enterprise security
  • Windows 10
  • Multiple users
  • Win32, UWP
  • Office 365 Po Plus
  • Semi-Annual Channel

This is a middle ground between RDSH on Windows Server and VDI on Windows 10.

Demo

The presentation is actually being run from a WVD VM in the cloud. PowerPoint is a published application – we can see the little glyph in the taskbar icon.

User Profile Disks

High performance persistence of cached user profile data across all Office 365 apps and services.

  • Outlook OST/PST files – will be improved for GA of WVD. Support for UNC paths
  • OneDrive sync roots
  • OneNote notebook cache

Improving Outlook Start Up

  • Virtual environment friendly default settings
  • Sync Inbox before calendar for faster startup experience
  • Admin option to reduce calendar sync window
  • Reduce the number of folders that are synced by default
  • Windows Desktop Search is no per-user

See Exchange Account Settings to configure how much past email should be synced

Windows Desktop Search

  • Enables the full Outlook search experience that users expect
  • Per user index files are stored in the user profile for each roaming
  • No impact to CPU usage at steady state, minimal impact at sign in

With 100 users in a machine signing in simultaneously, enabling Windows Search has a 0.02% impact on the CPU.

Demo

Desktop of the remote machine is stretched across multiple displays – this demo is with a published desktop hosted in Windows 10 multi-user. Windows Desktop search is enabled. Instant search results in Outlook. OneDrive sync is working in a non-persistent machine – fully functional enabling the full collaboration experience in O365. Selective Sync works here too. Sync is cloud-cloud so the performance is awesome. In Task Manager, we see 3 users signed into a single Windows 10 VM via RDS.

OneDrive

  • Co-authoring and collaborative capabilities in wXP, powered by OneDrive.
  • OneDrive sync will run in non-persistent environments
  • Files on-demand capabilities
  • Automatically populate something

Support

  • Search products stay in sync with each other
  • Office 365 Pro Plus will always be supported with Win 10 SAC
  • Office 365 Pro Plus won Windows Server 2016 will be supported through October 2025

Best Practices

Outlook:

  • The OST file should be stored on local storage.
  • Outlook deployed with the primary mailbox in cached echange mode with the OST file stored on network storage, and an aggressive archiving strategy to an online archive mailbox
  • Outlook deploy in cached exchange mode with slider set to one month.

Office 365:

  • Licensing token roaming: Office 365 Pro-Plus 1704 or newer. You can configure the licensing token to roam with the users profile or be location on a shared folder on the network. This especially helpful  for non persistent VDI scenarios.
  • SSO recommended. We recommend using SSO for good and consistent user experience. SSO reduces how often the users are prompted to sign in for activation. With SSO configured, Office activates with the credentials the user uses to sign into Windows if the user is also licensed for O365 Pro Plus.
  • If you don’t use SSO, consider using roaming profiles.

Preview

Sign up: https://aka.ms/wvdpreview

Public preview later 2018.

GA early 2019.

Q&A

If you want to use RDSH on Windows Server 2019 then Office 365 Pro Plus is not supported. You would have to use persistent Office 2019 so you get a lesser product. The alternatives are RDSH on Windows Server 2016 or Windows 10 Multi User (Azure). 

Widows 10 Multi User is only available in Azure via Windows Virtual Desktop.

A lot of the above optimization, such as search indexing, rely on the user having a persistent profile on the latest version of Windows 10. So if that profile is a roaming profile or a UPD, then this works, in RDS or on physical,