Tag Archives: Automation

Puppet and Windows Package Names RTFM Moment

Puppet and Windows Package Names RTFM Moment

After writing the article on how to install Citrix Provisioning Services Server 1912 CU1 using Puppet last month I promptly powered off the VM as it wasn’t needed for my lab environment at that time. Fast forward a month or so and I needed it to work out some things so I powered it on and configured the Farm etc which was all good. What I soon realised though was that the PVS Services were stopping without warning on the server and I had to hop on and start them again.

Continue reading Puppet and Windows Package Names RTFM Moment

Puppet – Creating A Domain Join Declaration For All Windows Machines

Puppet – Creating A Domain Join Declaration For All Windows Machines

Introduction

Puppet is a Configuration Management tool that is used for deploying, configuring and managing servers. Puppet uses a Master Slave architecture in which the Master and Slave communicate through a secure encrypted channel with the help of SSL.

This article explains how to configure a Puppet manifest to join all Windows agents to a Windows Domain using the domain_membership module by trinkin available at https://forge.puppet.com/trlinkin/domain_membership. The puppet code uses facts from the agent to assess if the machine is a Windows machine or not before applying the class declaration.

Test Environment

For this article I’ll be using an already deployed Puppet Master server on CentOS which has a very basic manifest configured to Domain Join any Windows machines when the puppet agent contacts the server.

Active Directory is also configured in the environment with DNS on a server named Lab-Lokse (The reason I mention it’s name will come in to play later).

The Domain Controller was deployed using Puppet also by following the article below which also provides the steps to encrypt a password using hiera: https://geekdudes.wordpress.com/2018/11/01/installing-domain-controller-using-puppet/

Installing The Domain Membership Module

To implement the domain membership module perform the following steps:

  • Logon to the Puppet Master
  • Install the module by executing the following
puppet module install trlinkin-domain_membership --version 1.1.2
  • The module will also install the modules it depends upon
  • Once installed confirm that module and it’s dependencies are installed (Highlighted in bold below) by executing puppet module list:
/etc/puppetlabs/code/environments/production/modules
├── jriviere-windows_ad (v0.3.2)
├── puppet-download_file (v3.2.0)
├── puppet-windows_env (v3.2.0)
├── puppet-windowsfeature (v3.2.2)
├── puppetlabs-acl (v2.1.0)
├── puppetlabs-chocolatey (v3.3.0)
├── puppetlabs-dsc (v1.9.4)
├── puppetlabs-iis (v4.5.1)
├── puppetlabs-powershell (v2.3.0)
├── puppetlabs-reboot (v2.4.0)
├── puppetlabs-registry (v2.1.0)
├── puppetlabs-stdlib (v5.2.0)
├── puppetlabs-windows (v6.1.0)
├── puppetlabs-wsus_client (v1.1.0)
└── trlinkin-domain_membership (v1.1.2)

Adding The Domain Join Resource Declaration

Once the domain membership module is installed the next step is to edit the puppet manifest and add the domain join resource declaration. I added it at the top of my manifest for convenience after a default node declaration. I also learned recently that the ordering setting in puppet.conf has been depreciated and it now defaults to use the order the declarations are listed in the manifest.

As my Puppet server is running on CentOS my manifest files are stored under /etc/puppetlabs/code/environment/production/manifests and I’m starting a new manifest file called lab-setup.pp.

To add the declaration to the puppet manifest perform the following steps:

  • Open the new manifest file (I use vi as I’m on CentOS)
  • Insert the following at the top of the new file:

#########################################
# Default node to catch undefined nodes
#########################################

node default {}
  • Next add in a lookup for the Domain Admin password which has been stored using hiera
#########################################
# Importing Domain Password from hiera
#########################################
$adminpassword = lookup('windowspassword')
  • Using a lookup for the Domain Admin password is useful as it means we don’t have to hard code it into the manifest !
  • Next add the puppet code and class declaration below to the manifest:
#########################################
# Domain join logic for Windows servers
#########################################
if $facts['os']['family'] == 'windows' {
   if $facts['networking']['hostname'] == 'Lab-Lokse' {
      }
   else {
      class { 'domain_membership': 
         domain => 'lab.lost-it.org',
         username => 'Administrator', 
         password => $adminpassword, 
         join_options => '3',
         } 
      }
   }
}
  • Save and exit the manifest file

Puppet Code Explanation

Below is a breakdown of the Domain Join resource declaration piece by piece to show what means what and why it’s being used:

  1. node default {} – Not strictly necessary but without it my Foreman reports show errors for any deployed servers which haven’t been added to the manifest yet.
  2. $adminpassword = lookup(‘windowspassword’) – Used to lookup the encrypted Domain Admin password and store it as a variable in the manifest for later use.
  3. if $facts[‘os’][‘family’] == ‘windows’ { – This checks the facts reported from the agent and if it’s OS Family matches windows (Lower case was important in my case) it continues to execute the puppet code.
  4. if $facts[‘networking’][‘hostname’] == ‘Lab-Lokse’ { – I added this second piece of logic so that if the agent is my Domain Controller it doesn’t attempt to join it. Again, not strictly necessary but stopped any errors in logs and reports to Foreman !
  5. class { ‘domain_membership’: – Invokes the domain_membership class from the domain_membership module.
  6. username => ‘Administrator’, – The username to use when joining the Domain. For the sake of ease I used the Domain Administrator account but this could be changed to a restricted account for security.
  7. password => $adminpassword, – Passes the hiera encrypted Domain Administrator password to the module using the $adminpassword variable.
  8. join_options => ‘3’, – Joins the computer to the Domain and creates the computer object.

Final Thoughts

Now when I deploy out my Windows sysprep’d image with the puppet agent installed it contacts the Puppet master, joins the Domain and reboots without me needing to do anything !

My next task is to make it more corporate friendly and change the logic when checking if the server is a Domain Controller using a naming convention like Lab-DC0x so it can handle multiple Domain Controllers. I’ve already done it in a manifest to match nodes to a naming convention for different roles in my lab so fingers crossed it should be too difficult.

Tested On

This simple piece of puppet code has been tested successfully on the following Operating Systems:

  • CentOS 7 (Tested to ensure a non Windows server ignores the logic
  • Windows Server 2012 R2
  • Windows Server 2012 R2 Core
  • Windows Server 2016
  • Windows Server 2016 Core
  • Windows Server 2019
  • Windows Server 2019 Core

Puppet – Deploying PVS 1912 CU1 Server Software Using Puppet

Puppet – Deploying PVS 1912 CU1 Server Software Using Puppet

Change Log

  • 16-11-2020 – Updated the package resource section after finding an issue with the naming used.
  • 16-11-2020 – Added the package resource section for installing the Provisioning Services 1912 CU1 Console.

Introduction

Citrix Provisioning Services (PVS) is software streaming technology that delivers patches, updates, and other configuration information to multiple virtual desktop endpoints through a shared desktop image. It centralizes virtual machine management while reducing the operational and storage costs of a virtualized desktop environment.

Puppet is a Configuration Management tool that is used for deploying, configuring and managing servers. Puppet uses a Master Slave architecture in which the Master and Slave communicate through a secure encrypted channel with the help of SSL.

This article explains how to use Puppet to perform unattended installations of both the Citrix Provisioning Services server and console.

Test Environment

For this article I’ll be using an already deployed Puppet Master server on CentOS which has a very basic manifest configured to Domain Join any Windows machines when the puppet agent contacts the server.

My manifest files is named lab-setup.pp and is stored under /etc/puppetlabs/code/environment/production/manifests.

Active Directory is also configured in the environment with DNS and a network share created to hold the PVS installation files so that they can be called as part of the Puppet manifest directives.

The Provisioning Services Server itself is a flat install of Windows Server 2019 Standard Desktop Edition (GUI) which has already has the puppet agent installed, configured, and running on it. The server has also been joined to the Domain via puppet (see my article Creating A Domain Join Declaration For All Windows Machines for details on how to do this) and the DOT Net 4.5 Core feature applied as part of my standard OVF build for deploying servers through Bolt.

The Issue

Installing PVS server and the console silently is well documented in the current release product documentation below:

https://docs.citrix.com/en-us/provisioning/current-release/install/install-wizard-silent.html

It’s straightforward enough to perform using the basic command line switches as shown below :

PVS_Server_x64.exe /S /v "/qn" 

The issue I encountered was when trying to pass the options through as it would always start the gui when I ran a puppet apply. I tried as a normal install_options setting, escaping the double quotes around /qn, and replacing the single quotes with double ones, and setting them as a variable which I then passed to the options but nothing worked. In the end I came across a page on the web about using square brackets to break out the options.

This finally worked and allowed me to deploy a new VM which joined the Domain and then installed PVS server without any interaction.

Installing Provisioning Services Server using Puppet

To install the Provisioning Services Server software using Puppet follow the steps below:

  • Connect to the Puppet server over SSH
  • Open the lab-setup.pp file (I use vi as I’m on CentOS)
  • The First thing to do is declare the nodes this resource will apply to:
######################################
# LAB-PVS Servers Configuration
######################################

node /^(lab-halusky01|lab-halusky02).lab.lost-it.org$/ {
  • The next piece is to add the package resource as follows:
package {"Citrix 1912 LTSR CU1 - Provisioning Server x64":
 ensure => installed,
 subscribe => Class['domain_membership'],
 source => "\\lab-schnitzel\software\PVS-1912-CU1\Server\PVS_Server_x64.exe",
 install_options => [
   '/S /v',
   '/qn',
   ],
}
  • The final piece is to add in a reboot as follows:
reboot {'pvsserver_reboot':
 message => 'PVS Install has requested a reboot',
 when => pending,
}
  • Save and exit the manifest file

Puppet Code Explanation

Below is a breakdown of the PVS Server install code piece by piece to show what means what and why it’s being used:

  1. node /^(lab-halusky01|lab-halusky02).lab.lost-it.org$/ { – Node declaration using pattern matching to apply to two different PVS servers
  2. package {“Citrix 1912 LTSR CU1 – Provisioning Server x64: – Updated 16-11-2020 to use the Display Name for the application as shown in Control Panel as this is what is used by the Puppet package resource to check if the software is installed.
  3. ensure => installed, – Used to check that the software is installed and if not execute the install
  4. subscribe => Class[‘domain_membership’], – Subscribes to a previous class resource to ensure that PVS Server is only installed once the server has joined the domain.
  5. source => “\lab-schnitzel\software\PVS-1912-CU1\Server\PVS_Server_x64.exe”,
  6. install_options => [ – Defines the install options to be passed to the installer. The square bracket is used to allow specifying sets of options on different lines. The important part for using this method is that puppet will put double quotes around each of the following lines and separates them with a space.
  7. ‘/S /v’, – Sets the first two options which are passed by puppet as “/S /v”
  8. ‘/qn’, – Sets the quiet no gui options which are passed by puppet as “/qn”
  9. ], – Closes the square bracket used to define the install options.
  10. } – Closes the package function.

Installing Provisioning Services Console using Puppet

To install the Provisioning Services Console software using Puppet follow the steps below:

  • Connect to the Puppet server over SSH
  • Open the lab-setup.pp file (I use vi as I’m on CentOS)
  • The next piece is to add the package resource as follows:
package {"Citrix 1912 LTSR CU1 - Provisioning Console x64":
 ensure => installed,
 subscribe => Package["Citrix 1912 LTSR CU1 - Provisioning Server x64"],
 source => "\\lab-schnitzel\software\PVS-1912-CU1\Console\PVS_Console_x64.exe",
 install_options => [
   '/S /v',
   '/qn',
   ],
}
  • Save and exit the manifest file

Puppet Code Explanation

Below is a breakdown of the PVS Console install code piece by piece to show what means what and why it’s being used:

  1. package {“Citrix 1912 LTSR CU1 – Provisioning Console x64: – Set to the same as the Display Name for the application as shown in Control Panel.
  2. ensure => installed, – Used to check that the software is installed and if not execute the install
  3. subscribe => Package[“Citrix 1912 LTSR CU1 – Provisioning Server x64”], – Subscribes to a previous class resource to ensure that PVS Console is only installed once the PVS Server software has been installed.
  4. source => “\lab-schnitzel\software\PVS-1912-CU1\Server\PVS_Console_x64.exe”,
  5. install_options => [ – Defines the install options to be passed to the installer. The square bracket is used to allow specifying sets of options on different lines. The important part for using this method is that puppet will put double quotes around each of the following lines and separates them with a space.
  6. ‘/S /v’, – Sets the first two options which are passed by puppet as “/S /v”
  7. ‘/qn’, – Sets the quiet no gui options which are passed by puppet as “/qn”
  8. ], – Closes the square bracket used to define the install options.
  9. } – Closes the package function.

Final Thoughts

I’m still learning Puppet and finding my way around the different methods and code options so this is very much a first working attempt. There are community modules out there to do it but for me, I prefer to learn by doing !

Tested On

This piece of puppet code has been tested installing PVS Server 1912 CU1 LTSR on the following:

  • Windows Server 2019

Automating My Home Lab Part 1

ESXi, Puppet Bolt, and the OVFTool

In a moment of quiet I started to think about how to improve my home lab VM deployment strategy although strategy is a strong word for it ! Currently I use basic server build ESXi virtual machines for 2K12 R2, 2K16, and 2K19 that have been sysprep’d and perform an autologon to set the machine name, IP details, and join the Domain. The Powershell script I use pulls variables from the vmx file or prompts me to set the details if I forget to add them. Not the most elegant of solutions but it did mean I could deploy a new VM in about 15 minutes albeit with a lot of manual intevention.

Continue reading Automating My Home Lab Part 1