In previous consultancies I’ve worked, it was common practice to frequently patch corporate VDI templates. Whilst continuous patching is a good thing, it is quite often laborious. Any attempt to automate this is seen as difficult and organizations often give up and continue with manual processes. Here I will show how it can be done using Code Stream and HashiCorp Packer.
Other posts in this series:
Background
In HobbitCloud we use a mixture of Windows and Linux VDI desktops. Whilst the latter is my desktop of choice, some users still prefer Redmond’s offering.
To offer the most cost-efficient solution in terms of storage and manageability, we use linked-clone desktops with applications provided by VMware AppVolumes. This enables us to provision a clean base image, with all applications installed in an AppStack. While not every application is suitable for an AppStack (I would always put Microsoft Office/365 into the base image), fortunately the standard apps we use are.
Therefore all we need to build is a Windows 10 desktop, patched with the latest updates, with the AppVolumes, Dynamic Environment Manager and VMware Horizon Agents installed. Once we become familiar with how to build the solution in a scripted fashion, we can leverage VMware’s continuous delivery tool, Code Stream, to automate the process.
What we’ll need:
- HashiCorp Packer
- JetBrains Packer Builder for vSphere
- JSON configuration file
- JSON file for variables
- Windows 10 ISO
- Windows Autounattend.xml file
- VMware Tools
- Various scripts (for VMware Tools, agents etc)
- AppVolumes, DEM, Horizon Agents
- Access to VMware Code Stream
- (Optional) access to VMware vRealize Automation Cloud
Please note: be sure to choose the correct VMware Tools and software agents for your Horizon environment. Consult the support matrix where necessary.
Solution Overview
Here is a high-level plan for how the solution will work:
Getting Started
Create a folder with a meaningful name in your filesystem. I have gone with $HOME/git/packer/windows-10. This will be our root folder.
Download Packer 1.4.2 and unzip it to the root folder. Also download the JetBrains Packer Builder for vSphere (link above) and save it to the same folder.
Next, create a JSON file called windows-10.json with the following and save it to the root folder:
{ "builders": [ { "type": "vsphere-iso", "vcenter_server": "{{user `vcenter_server`}}", "username": "{{user `username`}}", "password": "{{user `password`}}", "insecure_connection": "true", "vm_name": "Windows 10 (LC) (PILOT)", "datastore": "{{user `datastore`}}", "create_snapshot": "false", "cluster": "{{user `cluster`}}", "network": "{{user `network`}}", "boot_order": "disk,cdrom", "vm_version": 15, "guest_os_type": "windows9_64Guest", "communicator": "winrm", "winrm_username": "{{user `winrm_username`}}", "winrm_password": "{{user `winrm_password`}}", "CPUs": 2, "RAM": 8192, "RAM_reserve_all": true, "disk_controller_type": "pvscsi", "disk_size": 51200, "disk_thin_provisioned": true, "network_card": "vmxnet3", "iso_paths": [ "[{{user `datastore_iso`}}] en-gb_windows_10_business_editions_version_1903_x64_dvd_4170a06f.iso", "[{{user `datastore_iso`}}] VMware-tools-windows-10.3.10-12406962.iso" ], "floppy_files": [ "{{template_dir}}/setup/" ], "floppy_img_path": "[{{user `datastore`}}] Floppies/pvscsi-Windows8.flp" } ], "provisioners": [ { "type": "powershell", "inline": [ "Get-AppXPackage -AllUsers | Where {($_.name -notlike \"Photos\") -and ($_.Name -notlike \"Calculator\") -and ($_.Name -notlike \"Store\")} | Remove-AppXPackage -ErrorAction SilentlyContinue", "Get-AppXProvisionedPackage -Online | Where {($_.DisplayName -notlike \"Photos\") -and ($_.DisplayName -notlike \"Calculator\") -and ($_.DisplayName -notlike \"Store\")} | Remove-AppXProvisionedPackage -Online -ErrorAction SilentlyContinue" ] }, { "type": "powershell", "scripts": [ "{{template_dir}}/setup/certs.ps1", "{{template_dir}}/setup/appvolumes.ps1", "{{template_dir}}/setup/dem.ps1", "{{template_dir}}/setup/agent.ps1", "{{template_dir}}/setup/updates.ps1" ] } ] }
Things to note:
- Line 11: here’s where you specify what you want the virtual machine to be named (substitute accordingly)
- Lines 25-26 and 30: here’s where you size your VM. 2 vCPUs, 8GB RAM and 50GB disk is the HobbitCloud default
- Lines 36-37: the Windows and VMware Tools ISO need to exist on a datastore of your choosing
- Line 42: this is where we will store our scripts (more on this later)
- Lines 51-52: some PowerShell commands for hacking out all the unnecessary Windows garbage. Delete as necessary.
- Line 58 onwards: these call out the scripts we will be using. Feel free to include/exclude as necessary. I would remove them all at first, get the solution working, then add them one at a time.
Create a JSON file named variables.json and add the following (substitute accordingly):
{ "vcenter_server":"nl-utc-p-mgt-01.nl.mdb-lab.com", "username":"vcenter_user", "password":"VMware1!", "datastore":"vsanDatastore", "datastore_iso":"ISO", "cluster": "Management", "network": "VLAN70", "winrm_username": "Administrator", "winrm_password": "VMware1!" }
Things to note:
- Lines 9-10: these need to match what is defined in Autounattend.xml file (see next section)
Windows 10
Now we need to start defining how our Windows 10 box will be built. Before we do that, upload the Windows 10 and VMware Tools ISOs (defined in windows-10.json) to the datastore defined in variables.json. As I configure my Windows desktop to use the pvscsi driver, you will also need to upload the floppy image for this too. This is defined at line 43 of windows-10.json, but if you don’t use it you can ignore that and hack it out.
Create a folder under the root folder called setup. Download the Autounattend.xml file from here and save it to this folder.
Create a command script called vmtools.cmd in the setup folder using:
@rem Silent mode, basic UI, no reboot e:\setup64 /s /v "/qb REBOOT=R"
Lastly, create a PowerShell script called setup.ps1 with the following and save it to the setup folder:
$ErrorActionPreference = "Stop" # Switch network connection to private mode # Required for WinRM firewall rules $profile = Get-NetConnectionProfile Set-NetConnectionProfile -Name $profile.Name -NetworkCategory Private # Enable WinRM service winrm quickconfig -quiet winrm set winrm/config/service '@{AllowUnencrypted="true"}' winrm set winrm/config/service/auth '@{Basic="true"}' # Reset auto logon count # https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-autologon-logoncount#logoncount-known-issue Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name AutoLogonCount -Value 0
You should now have enough to stand up the base build.
Try it…
In the root folder, run the following:
packer build -force -var-file variables.json windows-10.json
If all goes well, then you should get some green text appearing in your terminal window:
Coming up
In part 2 of this series will install our VDI agents, before moving on to automate the entire solution in part 3.
Pingback: vToolbelt - October 2019 - Cybersylum
Pingback: Newsletter: October 5, 2019 – Notes from MWhite
Pingback: Automating VDI Template Creation with VMware Code Stream and HashiCorp Packer – Part 2: Installing the VDI Agents | virtualhobbit
Pingback: Automating VDI Template Creation with VMware Code Stream and HashiCorp Packer – Part 3: Automating the Solution | virtualhobbit
Quick question – why are you calling your PowerShell scripts from the {{template_dir}} instead of from the floppy disk that gets mounted to the image throughout the build process? From my understanding including the scripts in the floppy_files would attach them locally and packer wouldn’t need to transfer the script files across WinRM as they are already there. Just a thought that I had while trying to replicate your process myself.
Great blog post and it’s been working great regardless!
LikeLike
At one point I ran into the size limitation of floppy disks so I had to find a workaround 🙂
LikeLike
Pingback: Minimal Touch VDI Image Building With MDT, PowerCLI, and Chocolatey | The Virtual Horizon
Pingback: EUC Weekly Digest – November 16, 2019 – Carl Stalhood
Pingback: Using GitLab CI/CD Pipelines to Automate your HashiCorp Packer Builds | virtualhobbit
Pingback: My Golden Image build using HashiCorp Packer – Retouw.nl
Pingback: Using Continuous Deployment to Provision VDI Desktops | virtualhobbit
Pingback: Managing Windows hosts using Ansible Tower/AWX and SSH | virtualhobbit