XenDesktop 7.15 delivery controller module

Introduction

The xd7deliverycontroller has been designed to install Citrix XenDesktop 7.X delivery controllers and to configure the XenDesktop site using Puppet and Powershell DSC. Citrix XenDesktop site configuration includes :

  • Databases creation and configuration
  • Databases high availability
  • XenDesktop site initialization
  • First Citrix Administrator creation

The role parameter defines the configuration actions done by the Puppet module. :

  • A primary delivery controller is the first delivery controller of the XenDesktop site. This role integrates Citrix XenDesktop site initialization.
  • A secondary delivery controller is joined to an existing XenDesktop site.

Once the site has been created, the master role can be transfered to any Delivery Controller as the additionnal checks in this module will check the settings of the XenDesktop site which are stored in the central database.This capability will be useful in case of master controller failure : the controller will have to be reinstalled using the slave role to avoid errors when trying to recrete the databases and the site.

Download and install xd7deliverycontroller module

The xd7delivery controller module can be automatically downloaded from Puppet Forge and installed on a Puppet Server using the following commands :

  • Download virtualdesktop/dsc dependancy : puppet module install virtualdesktopdevops-dsc –version 1.5.0
  • Download puppetlabs/reboot dependancy : puppet module install puppetlabs-reboot –version 1.2.1
  • Download the module : puppet module install virtualdesktopdevops-xd7deliverycontroller –version 2.0.0

Puppet >= 4.0 is required to use this module

The minimum Windows Management Framework (PowerShell) version required is 5.0 or higher, which ships with Windows 10 or Windows Server 2016, but can also be installed on Windows 7 SP1, Windows 8.1, Windows Server 2008 R2 SP1, Windows Server 2012 and Windows Server 2012 R2.

This module requires SQLServer powershell module v21.0.17199. The module will install this dependancy :

  • From Powershell Gallery if sqlservermodulesource parameter is set to internet
  • From an enterprise location if sqlservermodulesource parameter is set to offline. In this case, the ZIP file containing the SQLServer v21.0.17199 (_sqlserver_powershell_21.0.17199.zip_) has to be manually downloaded from Powershell Gallery using the `Save-Module -Name SqlServer -Path -RequiredVersion 21.0.17199` powershell command.

This module requires a custom version of the puppetlabs-dsc module compiled with XenDesktop Powershell DSC Resource as a dependency. Ready to use virtualdesktopdevops/dsc v1.5.0 puppet module provided on Puppet Forge.

xd7deliverycontroller module integration

The following options are available for a production-grade installation :

  • Fault tolerance : AlwaysOn database membership activation for Citrix databases created by the package
  • Security : SSL configuration to secure communications with the Citrix XML service

The Citrix databases are installed in the default MSSQLSERVER SQL Server instance. This module does not provide the capability to install the databases in another SQL intance. The database failover mecanism integrated in this module is SQL Server AlwaysOn.

The SSL certificate provided needs to be a password protected p12/pfx certificate including the private key.

The module can be installed on a Standard, Datacenter version of Windows 2012R2 or Windows 2016. Windows Server Core is not supported by Citrix for delivery Controller installation.

Module usage

setup_svc_username : (string) Privileged account used by Puppet for installing the software and the Xendesktop Site (cred_ssp server and client, SQL server write access, local administrator privilèges needed)

setup_svc_password : (string) Password of the privileged account. Should be encrypted with hiera-eyaml.

sitename : (string) Name of the Xendesktop site

databaseserver : (string) FQDN of the SQL server used for citrix database hosting. If using a AlwaysOn SQL cluster, use the Listener FQDN.

licenceserver : (string) FQDN of the Citrix Licence server.

sitedatabasename : (string) Name of the citrix site database to be created

loggingdatabasename : (string) Name of the citrix logging database to be created

monitordatabasename : (string) Name of the citrix monitor database to be created

sourcepath : (string) Path of a folder containing the Xendesktop 7.x installer (unarchive the ISO image in this folder).

xd7administrator : (string) ActiveDirectory user or group which will be granted Citrix Administrator rights.

sqlalwayson : (boolean) : true or false. Activate database AlwaysOn availability group membership ? Default is false. Needs to be true for a production grade environment

sqlavailabilitygroup : (string) (optionnal if sqlalwayson = false) : Name of the SQL AlwaysOn availability group.

sqldbbackuppath : (string) (optionnal if sqlalwayson = false) : UNC path of a writable network folder to backup/restore databases during AlwaysOn availability group membership configuration. needs to be writable from the sql server nodes.

https : (boolean) : true or false. Deploy SSL certificate and activate SSL access to Citrix XML service ? Default : false

sslCertificateSourcePath : (string) Location of the SSL certificate (p12 / PFX format with private key). Can be local folder, UNC path, HTTP URL)

sslCertificatePassword : (string) Password protecting the p12/pfx SSL certificate file.

sslCertificateThumbprint : (string) Thumbprint of the SSL certificate (available in the SSL certificate).

Configuration example

Sample Puppet node configuration for configuration of a first XenDesktop 7 controller and XD7TestSite création :

node 'CXDC01' {
	class{'xd7deliverycontroller':
		setup_svc_username       => 'TESTLAB\svc-puppet',
		setup_svc_password       => 'P@ssw0rd',
		sourcepath               => '\\\\fileserver\xendesktop715',
		sitename                 => 'XD7TestSite',
		role                     => 'primary'
		databaseserver           => 'CLSDB01LI.TESTLAB.COM',
		licenceserver            => 'LICENCE.TESTLAB.COM',
		xd7administrator         => 'TESTLAB\Domain Admins',
		sitedatabasename         => 'SITE_DB',
		loggingdatabasename      => 'LOG_DB',
		monitordatabasename      => 'MONITOR_DB',
		sqlalwayson              => true,
		sqlavailabilitygroup     => 'CLSDB01',
		sqldbbackuppath          => '\\\\fileserver\backup\sql',
		https                    => true,
		sslCertificateSourcePath => '\\\\fileserver\ssl\cxdc.pfx',
		sslCertificatePassword   => 'P@ssw0rd',
		sslCertificateThumbprint => '44cce73845feef4da4d369a37386c862eb3bd4e1'  
	}
}

node 'CXDC02' {
	class{'xd7deliverycontroller':
		setup_svc_username       => 'TESTLAB\svc-puppet',
		setup_svc_password       => 'P@ssw0rd',
		sourcepath               => '\\\\fileserver\xendesktop715',
		sitename                 => 'XD7TestSite',
		role                     => 'secondary',
		site_primarycontroller   => 'CXDC01',
		https                    => true,
		sslCertificateSourcePath => '\\\\fileserver\ssl\cxdc.pfx',
		sslCertificatePassword   => 'P@ssw0rd',
		sslCertificateThumbprint => '44cce73845feef4da4d369a37386c862eb3bd4e1'  
	}
}

Xd7mastercontroller module structure

install.pp : installs prerequities and citrix software

The module makes sure that IIS web server is not installed on the system to avoid conflicts with the Citrix Broker Service. The check is performed using the WindowsFeature DSC resource called using the puppetlabs/dsc module.

  #Ensure IIS is not installed on the system to avoid conflicts with Broker Service
	dsc_windowsfeature{'iis':
	 dsc_ensure => 'Absent',
	 dsc_name   => 'Web-Server',
	}
  }

It then installs the Citrix Delivery Controller using virtualengine/XenDesktop7 DSC module. The setup is straightforward ! The source path has to be an unarchived XenDesktop ISO which can be located on a remote file share (recommanded as this path will be used for all Citrix nodes setup). Puppet handles orchestration, dependancies checks and DSC modules automatic deployment ont the node avoiding manual managment of those resources in DSC scripts. The DSC script is generated by Puppet and run locally on the DSC Local Configuration Manager of the node.

  dsc_xd7features { 'XD7DeliveryController':
	  dsc_issingleinstance => 'Yes',
	  dsc_role => [Studio, Controller],
	  dsc_sourcepath => $sourcepath,
	  dsc_ensure => 'present',
	  require => Dsc_windowsfeature['iis'],
	  notify => Reboot['after_run']
  }

It finally copies and unzip the SQL_server powershell module on the node, which is required by xSQLServer DSC module to remotely configure AlwaysOn features on Citrix databases created during XenDesktop site initialization :

  #SQLSERVER powershell module deployment.
  #Required for database high awailability setup (always on citrix databases membership)
  file{ "C:\\Program Files\\WindowsPowerShell\\Modules\\sqlserver_powershell_21.0.17199.zip":
      source => 'puppet:///modules/xd7mastercontroller/sqlserver_powershell_21.0.17199.zip',
      source_permissions => ignore,
  }
  
  #Function provided by the reidmv-unzip
  unzip{'UnzipSqlserverModule':
	  source  => 'C:\\Program Files\WindowsPowerShell\Modules\sqlserver_powershell_21.0.17199.zip',
	  destination => 'C:\\Program Files\WindowsPowerShell\Modules',
	  creates => 'C:\\Program Files\WindowsPowerShell\Modules\SqlServer',
	  require => File["C:\\Program Files\\WindowsPowerShell\\Modules\\sqlserver_powershell_21.0.17199.zip"]
  }

siteconfig.pp : initialize the XenDesktop site

The first step of XenDesktop site initialization is database creation. Three databases are created during this process : site database, logging database, and monitor database. These databases will be shared among all the Delivery Controllers of the site. The user defined in the dsc_psdscrunascredential setting has to have login and database creation permissions on the SQL Server.

The dsc_databaseserver setting has to be the SQL Server Availability Group listener IP address and not the local IP address of one of the SQL server nodes.

    #Databases creation
	dsc_xd7database{ 'XD7SiteDatabase':
	  dsc_sitename => $sitename,
	  dsc_databaseserver => $databaseserver,
	  dsc_databasename => $sitedatabasename,
	  dsc_datastore => 'Site',
	  dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
	  #require => Dsc_xd7features['XD7DeliveryController']
	}
	
	dsc_xd7database{ 'XD7SiteLoggingDatabase':
	  dsc_sitename => $sitename,
	  dsc_databaseserver => $databaseserver,
	  dsc_databasename => $loggingdatabasename,
	  dsc_datastore => 'Logging',
	  dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
	  #require => Dsc_xd7features['XD7DeliveryController']
	}
	
	dsc_xd7database{ 'XD7SiteMonitorDatabase':
	  dsc_sitename => $sitename,
	  dsc_databaseserver => $databaseserver,
	  dsc_databasename => $monitordatabasename,
	  dsc_datastore => 'Monitor',
	  dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
	  #require => Dsc_xd7features['XD7DeliveryController'] 
	}

The XenDesktop site is created just after database creation. At this step, the site is not directly usable as it’s missing license server and a first Citrix administrator.

	#XD7 site creation      
	dsc_xd7site{ 'XD7Site':
	  dsc_sitename => $sitename,
	  dsc_databaseserver => $databaseserver,
	  dsc_sitedatabasename => $sitedatabasename,
	  dsc_loggingdatabasename => $loggingdatabasename,
	  dsc_monitordatabasename => $monitordatabasename,
	  dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
	  require => [Dsc_xd7database['XD7SiteDatabase'], Dsc_xd7database['XD7SiteMonitorDatabase'], Dsc_xd7database['XD7SiteLoggingDatabase'] ]
	}

Citrix license server and first administrator are finally linked to the site.

	#Linking with Citrix License server
	dsc_xd7sitelicense{ 'XD7SiteLicense':
	  dsc_licenseserver => $licenceserver,
	  dsc_licenseedition => 'PLT',
	  dsc_licensemodel => 'UserDevice',
	  dsc_trustlicenseservercertificate => false,
	  dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
	  require => Dsc_xd7site['XD7Site'] 
	}
	
	#Site admin roles for users
	#Administrator has to be created before beeing affected a role
	dsc_xd7administrator{ 'CitrixAdmin':
	    dsc_name => $xd7administrator,
	    dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
	    require => Dsc_xd7site['XD7Site'] 
	}
	
	dsc_xd7role{ 'CitrixAdminFullAdministratorRole':
	    dsc_name => 'Full Administrator',
	    dsc_members => $xd7administrator,
	    dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
	    require => [ Dsc_xd7site['XD7Site'] , Dsc_xd7administrator['CitrixAdmin'] ]
	}
	
	#Site admin roles for Puppet service account
	#Administrator has to be created before beeing affected a role
	dsc_xd7administrator{ 'PuppetServiceAccountCitrixAdmin':
      dsc_name => $svc_username,
      dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
      require => Dsc_xd7site['XD7Site'] 
  }
  
  dsc_xd7role{ 'PuppetServiceAccountFullAdministratorRole':
      dsc_name => 'Full Administrator',
      dsc_members => $svc_username,
      dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
      require => [ Dsc_xd7site['XD7Site'] , Dsc_xd7administrator['PuppetServiceAccountCitrixAdmin'] ]
  }

The Citrix XLM service is finally configured to trust incoming requests. This setup is required for domain-passthrough or smartcard authentication as described on http://www.carlstalhood.com/storefront-3-5-basic-configuration/#authconfig

  #Trust requests sent to XML service
  dsc_xd7siteconfig{'XD7GlobalSiteSetting':
	dsc_issingleinstance => 'Yes',
	dsc_trustrequestssenttothexmlserviceport => true,
	dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
	require => Dsc_xd7site['XD7Site']
  }

databasehighavailability.pp : configure Always On high availability on Citrix databases

Recovery mode is configured as “Full” on each database before adding it to the SQL Server Availability group previosuly created using the sqlserveralwayson Puppet module. Configuration is only applied if the sqlalwayson setting is set to true in the Puppet node configuration.

The dsc_sqlserver setting has to be the SQL Server Availability Group listener IP address and not the local IP address of one of the SQL server nodes.

if $sqlalwayson {
		#Recovery mode configuration
		dsc_xsqlserverdatabaserecoverymodel{'SiteDatabaseRecoveryModel':
			dsc_name => $sitedatabasename,
			dsc_recoverymodel => 'Full',
			dsc_sqlserver => $databaseserver,
			dsc_sqlinstancename => 'MSSQLSERVER',
			dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
			require => Dsc_xd7site['XD7Site']
		}
		
		dsc_xsqlserverdatabaserecoverymodel{'LoggingDatabaseRecoveryModel':
			dsc_name => $loggingdatabasename,
			dsc_recoverymodel => 'Full',
			dsc_sqlserver => $databaseserver,
			dsc_sqlinstancename => 'MSSQLSERVER',
			dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
			require => Dsc_xd7site['XD7Site']
		}
		
		dsc_xsqlserverdatabaserecoverymodel{'MonitorDatabaseRecoveryModel':
			dsc_name => $monitordatabasename,
			dsc_recoverymodel => 'Full',
			dsc_sqlserver => $databaseserver,
			dsc_sqlinstancename => 'MSSQLSERVER',
			dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
			require => Dsc_xd7site['XD7Site']
		} 
		
		#AlwaysOn cluster databases membership activation
		dsc_xsqlserveralwaysonavailabilitygroupdatabasemembership{'SiteDatabaseAlwaysOn':
			dsc_databasename => $sitedatabasename,
			dsc_availabilitygroupname => $sqlavailabilitygroup,
			dsc_sqlserver => $databaseserver,
			dsc_sqlinstancename => 'MSSQLSERVER',
			dsc_backuppath => $sqldbbackuppath,
			dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
			#require => Dsc_xsqlserverdatabaserecoverymodel['SiteDatabaseRecoveryModel']
		}
		
		dsc_xsqlserveralwaysonavailabilitygroupdatabasemembership{'LoggingDatabaseAlwaysOn':
			dsc_databasename => $loggingdatabasename,
			dsc_availabilitygroupname => $sqlavailabilitygroup,
			dsc_sqlserver => $databaseserver,
			dsc_sqlinstancename => 'MSSQLSERVER',
			dsc_backuppath => $sqldbbackuppath,
			dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
			#require => Dsc_xsqlserverdatabaserecoverymodel['LoggingDatabaseRecoveryModel']
		}
		
    dsc_xsqlserveralwaysonavailabilitygroupdatabasemembership{'MonitorDatabaseAlwaysOn':
			dsc_databasename => $monitordatabasename,
			dsc_availabilitygroupname => $sqlavailabilitygroup,
			dsc_sqlserver => $databaseserver,
			dsc_sqlinstancename => 'MSSQLSERVER',
			dsc_backuppath => $sqldbbackuppath,
			dsc_psdscrunascredential => {'user' => $svc_username, 'password' => $svc_password},
			#require => Dsc_xsqlserverdatabaserecoverymodel['MonitorDatabaseRecoveryModel']
		}
	  
	}  

sslconfig.pp : secure the Citrix XML service

This manifest donwloads and installs the webserver’s SSL certificate on the server’s personal certificate store (local machine, not current user !). TheNETSH method is then used to bind the downloaded certificate to the Citrix Broker Service as described on https://support.citrix.com/article/CTX200415.

   if $https {
		reboot { 'after_sslconfig':
		  apply => finished,
		  when => refreshed
		} 

		#Download SSL certificate
		dsc_file{ 'SSLCert':
		  dsc_sourcepath => $sslCertificateSourcePath,
		  dsc_destinationpath => 'c:\SSL\cert.pfx',
		  dsc_type => 'File'
		}->

		#Load SSL certificate in Local Computer personal certificate store
		dsc_xpfximport{ 'ImportSSLCert':
		  dsc_thumbprint => $sslCertificateThumbprint,
		  dsc_path => 'c:\SSL\cert.pfx',
		  dsc_location => 'LocalMachine',
		  dsc_store => 'My',
		  dsc_credential => {'user' => 'cert', 'password' => $sslCertificatePassword },
		  require => Dsc_file['SSLCert']
		}->

		#Map SSL certificate to Citrix Broker Service using netsh method
		#netsh http add sslcert ipport=0.0.0.0:443 certhash= appid={}
		dsc_script{ 'CitrixBrokerServiceSSL':
		  dsc_getscript => 'Return @{ Result = [string]$(netsh http show sslcert) }',
		  dsc_testscript => 'If ((netsh http show sslcert | Select-String  "Application ID") -like "*Application*") {
                  Return $true
                } Else {
                   Return $false
                }',
			dsc_setscript => "\$brokerservice = get-wmiobject -class Win32_Product | Where-Object {\$_.name -Like \"*Broker Service*\"}
			   \$guid = \$brokerservice.IdentifyingNumber
			   netsh http add sslcert ipport=0.0.0.0:443 certhash=${$sslCertificateThumbprint} appid=\$guid",
			notify => Reboot['after_sslconfig']
    }
  
		#Make sure Citrix XML Service SSL port is 443
		registry_value { 'HKLM\SOFTWARE\Citrix\DesktopServer\XmlServicesSslPort':
		  ensure => present,
		  type   => 'dword',
		  data   => '443',
		  require => Dsc_xd7features ['XD7DeliveryController']
		}
  }