At this point, we’ve created the parameter block for the get-zdc function.  It’s set up to accept pipeline data, and it is a mandatory parameter.

The next step is to initialize a few variables that we will be using.  Most powershell variables don’t require initialization, but for my own purposes, I frequently find it easier to have it initialized first.

	$Namespace = "root\Citrix"
	$FarmCanBeReached = $false # This is used for Ping & WMI tests
	$FarmIsAvailable = $false

As an option, all powershell functions have 3 major blocks that are processed

	BEGIN { #code }
	PROCESS { #code }
	END { #code }

The Begin block is processed once, the Process block is repeated with a loop, and the End block is processed once. These 3 lines could be placed inside the BEGIN block if desired. It’s not required per-se, for long scripts it is an option for organization.

The first line shows the namespace for WMI we’ll be using. Virtually all the scripts I’ve seen for ‘training’ purposes, or ‘how to’ scripts always use Root\CIMV2. But, as you can see, Citrix has it’s own provider. This is one of the reasons that WMI Explorer is so useful (see the first post). The 2nd and 3rd lines ore just establishing that we have not validated that we can reach a farm or not.

Next, we start a loop to process all of the objects being passed into the function. (This entire section of the loop could be embedded in the PROCESS section as mentioned above).

	foreach ($Computer in $ComputerName) {
	If ($FarmCanBeReached) {
		Continue
	} else {

The lines are pretty straight forward – We’re processing each individual computer from the ComputerName string that was passed to us, either by the pipeline, or by specifying the data on the command line. This could also be done using a ForEach-Object { loop. Using the foreach is actually slightly faster than ForEach-Object. The ForEach-Object loop uses the pipeline for each of the objects, and that pipelining adds some overhead. However, without a large number of objects (tens of thousands and above), you are likely to not notice a difference between the two, unless you are using measure-object.

So, for each of the objects in the computername list, we check to see if the $FarmCanBeReached variable is true. Since it is a boolean variable, and it starts out initialized as $false. If it is $true, then we use the Continue command. This command allows you to skip the remaining code in the loop, and move on to the next object. This is a Powershell V3 command. It can be done with V2, with a slightly different structure. (To use the alternate construction, you label your loop, and use a break statement. Your foreach loop becomes :LabelName foreach ($Computer in $ComputerName){ and our Continue becomes break LabelName. And obviously, our reason for this is if it is $true, we’ve established contact with the farm, and we don’t need to continue to try.

Next we do a ping check to validate that the computer is online. Obviously, you must either have the Windows firewall disabled, or allow ping access.

	$PingResult = Test-Connection -ComputerName $Computer -Count 1 -TimeToLive 5 -Quiet
	If ($PingResult) {

The Test-Connection command does a WMI ping. The interesting part is the -Quiet switch. This switch does not appear in the help for Test-Connection. The switch converts the output of the command to a boolean $true or $false depending on what happens. I’m storing it in a variable to provide an easier method of checking the data again later in the script.

We then start the If check to find out if the server can be pinged. If the ping succeeds, we start testing WMI. If pings are not allowed, the If ($PingResult) test could be removed. This next segment of code was designed to verify that WMI connectivity can be established. My coworker wrote the segment, and I don’t fully understand how it works, but it does. The gist of it is that it first attempts to bind to the specified WMI namespace (Recall that we set this to Root\Citrix) and tries to access the __Provider class, which is a required default for any WMI provider. It uses this to check for an Access Denied condition, and if that fails, it changes to Packet Privacy for the WMI calls, instead of plain text.

	try { Get-WmiObject -ComputerName $Computer -Namespace $Namespace -Class "__Provider" -ErrorAction Stop }
	catch [System.Management.ManagementException] { $Error[0].Exception.ErrorCode }
	catch { $Error[0] }
	)
	$Authentication = $(
		if ($AccessTestErrorCode -eq [System.Management.ManagementStatus]::AccessDenied) {
			[System.Management.AuthenticationLevel]::PacketPrivacy
		} else {
			[System.Management.AuthenticationLevel]::Default
		}
		)

Next we attempt to pull the Citrix_Product class from the provider. If it fails, it will not return anything, and if it does, we don’t care what it is, just that it exists.

$ProductWmi = Get-WmiObject -ComputerName $Computer -Authentication $Authentication -Namespace $Namespace -Class Citrix_Product -ErrorAction SilentlyContinue
	if ($ProductWMI -eq $null) {
		#WMI test failed
		$WMIResult = $false
	} else {
		$WMIResult = $true
	} #End of If ProductWMI is null test

You’ll notice, I tend to tag the end of my blocks of code by adding a comment (i.e. #End of If ProductWMI…. It makes it much easier to keep track of keeping all the blocks properly closed. (It is very difficult to track down a code block that is not properly closed (as in does not have the closing symbol such as a ) or }.

One possible optimization I have not tried to make yet with this script function, would be to embed the WMI code inside of the pingresult block. If you can’t ping the server, there is a good chance that you can’t connect to it by WMI and the WMI timeout is pretty long. Currently, that could be an issue where a machine could be pinged by not connected to by WMI.

But, we verify the combination of tests, and if they work, then we set the $FarmCanBeReached to $true. This lets the main loop skip over the other machines once we have succesfully connected.

If ($PingResult -and -$WMIResult) {
	$FarmCanBeReached = $true
	Continue
} #End of Ping & WMI result tests

In the next block, once we have established the fact that we have a machine in the farm that we can connect to, we start enumerating the Zones through WMI. If you notice the Select-Object -first 1 line, we’re selecting the first zone that populates. Since we only want a ZDC for the farm, we really don’t care which zone appears first. We do this first because the Zone Data Collector is a property of a Zone. I put a check in there in case the WMI call to get the zones were to fail, but in theory, it should not happen, since Citrix zones *always* have a ZDC, even if there is only one server, and/or all of them are set to Not Preferred, etc.

if ($FarmCanBeReached) {
	$ZoneWmi = Get-WmiObject -ComputerName $ComputerName -Authentication $Authentication -Namespace $Namespace -Class Citrix_Zone -ErrorAction SilentlyContinue | Select-Object -First 1
	#Test the WMI
if ($ZoneWmi -eq $null) {
	Continue
}

This is one of the most important lines of code here. It actually gets the name of the Zone Data Collector from the Zone itself.

	$MyZDC = ([System.Management.ManagementObject]$ZoneWMI.DataCollector).ServerName
} else {
	$MyZDC = $null
} #End of If FarmIsAvailable block

The construction of the line is important. Using the normal order of operations, the items inside of the parenthesis are processed first. So, we declare the type [System.Management.ManagementObject]. Just like most things in Powershell, using the square brackets indicates that the item is a .Net item (property, method, etc.). Declaring this is not strictly necessary, but it definitely helps decipher what is supposed to be happening in the code. And we are pulling the property with the ZDC ($ZoneWMI.DataCollector). However, if you look at it in WMI Explorer, this is a full WMI Path that is returned by default. This can be parsed directly, but if the path ever changes, the script will break, and since it is all object based, we just pull it directly. We do that by adding the property .ServerName at the end of ($ZoneWMI.DataCollector). And we deliberately set $MyZDC to null if we don’t find anything (for legibility/comprehension), even though it should never be possible. (It is actually possible, if you don’t provide *any* servers that are in the farm, are not contactable by ping and WMI, or possibly even a corrupt WMI stack on all the provided machines.)

And finally, we just wrap up the function and return the results.

 return $MyZDC 

I’ve attached the full script here. The full script has comment based help, and also has a lot of write-verbose statements to show what it is doing as it processes. The script also includes a function I had found online to make it easier to identify what line a script is at during execution, especially when combined with the write-verbose. The short version of this is that the by default, the MyInvocation is going to pull information about the execution of the script itself. By burying it in a function, it pulls the information about the execution of the function.

# ==============================================================================================
# 
# Microsoft PowerShell Source File -- Created with SAPIEN Technologies PrimalScript 2012
# 
# NAME: Get-ZDC.ps1 
# 
# AUTHOR: David Figueroa
# DATE  : 6/11/2014
# 
# COMMENT: This script is used to get the Zone Data Collector when given a Citrix server name
# 			or multiple Citrix server names
# 
# ==============================================================================================

function Get-CurrentLineNumber
{
	$MyInvocation.ScriptLineNumber
}
New-Alias -Name __LINE__ -Value Get-CurrentLineNumber –Description 'Returns the current line number in a PowerShell script file.'

Function Get-ZDC {

<#
	.SYNOPSIS
	Takes a computer name and get the Citrix Zone data collector through WMI calls
	
	.DESCRIPTION
	The function accepts a series of servernames within a single farm.  (If the servers
	span multiple farms, then any farms after the first successful one are ignored).
	The script does a ping test against each of them, and a WMI test for Citrix.  
	If both tests succeed, then the function queries the zone and gets the ZDC as of that moment.
		
	.PARAMETER ComputerName
	This is the name of the computer(s) for the initial query.   Multiple computer names can be sent
	in order to try and guarantee that the ZDC is found. 
	
	.EXAMPLE
	PS C:\> Get-ZDC -ComputerName server01
	serverzdc01
	PS C:\>
	
	.EXAMPLE
	PS C:\>Get-ZDC -ComputerName server01,server02
	serverzdc01
	PS C:\>
#>

	
	[CmdletBinding()]
	
	Param(
		[Parameter(mandatory=$true, valuefrompipeline=$true)]
		[Alias("CN")]
		[string[]]$ComputerName
		)
		
		write-verbose "$(__LINE__)`tEntering PROCESS block of Get-ZDC"
		#Get the list of servers from the ComputeName list and
		#parse them looking for ones that can be pinged & reached with WMI
	
		$Namespace = "Root\Citrix"
		write-verbose "$(__LINE__)`t`$NameSpace is $NameSpace"
		
		$FarmCanBeReached = $false # This is used for Ping & WMI tests
		write-verbose "$(__LINE__)`t`$FarmCanBeReached is $FarmCanBeReached"
			
		write-verbose "$(__LINE__)`tEntering ForEach Computer block"
		foreach ($Computer in $ComputerName)
		{
		write-verbose "$(__LINE__)`t`t`$Computer is $computer"
			If ($FarmCanBeReached) {
			write-verbose "$(__LINE__)`t`t`$FarmCanBeReached is True, Skip to the next server"
			Continue
			}
			else
			{
			write-verbose "$(__LINE__)`t`t`$FarmCanBeReached is False"
			write-verbose "$(__LINE__)`t`t#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
			write-verbose "$(__LINE__)`t`t# Connectivity tests, ping & WMI "
			write-verbose "$(__LINE__)`t`t#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
			write-verbose "$(__LINE__)`t`tPinging $Computer"
			$PingResult = Test-Connection -ComputerName $Computer -Count 1 -TimeToLive 5 -Quiet
				write-verbose "$(__LINE__)`t`tPing result is $PingResult"
			If ($PingResult)
			{
				write-verbose "$(__LINE__)`t`t#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
				write-verbose "$(__LINE__)`t`t# WMI"
				write-verbose "$(__LINE__)`t`t#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
				write-verbose "$(__LINE__)`t`tBeginning WMI test"
				write-verbose "$(__LINE__)`t`tGet WMI Citrix_Product class from '$Namespace' namespace..."
				$AccessTestErrorCode = $(
			try { Get-WmiObject -ComputerName $Computer -Namespace $Namespace -Class "__Provider" -ErrorAction Stop }
				catch [System.Management.ManagementException] { $Error[0].Exception.ErrorCode }
				catch { $Error[0] }
			)
				write-verbose "$(__LINE__)`t`t`$AccessTestErrorCode = $AccessTestErrorCode"
				$Authentication = $(
				if ($AccessTestErrorCode -eq [System.Management.ManagementStatus]::AccessDenied)
				{
					[System.Management.AuthenticationLevel]::PacketPrivacy
				}
				else
				{
					[System.Management.AuthenticationLevel]::Default
				}
				)
			$ProductWmi = Get-WmiObject -ComputerName $Computer -Authentication $Authentication -Namespace $Namespace -Class Citrix_Product -ErrorAction SilentlyContinue
			if ($ProductWMI -eq $null)
				{
					#WMI test failed
					$WMIResult = $false
					write-verbose "$(__LINE__)`t`t`$WMIResult is failed, `$ProductWMI is null"
				}
				else
				{
					$WMIResult = $true
					write-verbose "$(__LINE__)`t`t`WMIResult is good.  `$Product is not null"
				} #End of If ProductWMI is null test
				
				write-verbose "$(__LINE__)`t`t#++++++++++++++++++++++++++++++++++++++++++++++++++"
				write-verbose "$(__LINE__)`t`t# End of WMI test"
				write-verbose "$(__LINE__)`t`t#++++++++++++++++++++++++++++++++++++++++++++++++++"
			} #end of $PingResult block
			
			#Now that connectivity tests are done..
			#Validate that they are both good to receive the name of the ZDC
			If ($PingResult -and -$WMIResult) {
					write-verbose "$(__LINE__)`tPing & WMI results are good, FarmCanBeReached set to true"
				$FarmCanBeReached = $true 
					write-verbose "$(__LINE__)`tFound a good machine, using Continue to skip to the next computer"
				Continue
			} #End of Ping & WMI result tests
				write-verbose "$(__LINE__)`tEnd of if FarmCanBeReached block"
		} #End of If FarmCanBeReached test

		write-verbose "$(__LINE__) End of ForEach computer block"
		} #End of ForEach $computer block

		#Test if the farm is available and proceed from there.
		if ($FarmCanBeReached) {
			write-verbose "$(__LINE__)`tGetting WMI for Zones collection"
				$ZoneWmi = Get-WmiObject -ComputerName $ComputerName -Authentication $Authentication -Namespace $Namespace -Class Citrix_Zone -ErrorAction SilentlyContinue | Select-Object -First 1
			
			#Test the WMI
			if ($ZoneWmi -eq $null) {
				Continue
			}
				$MyZDC = ([System.Management.ManagementObject]$ZoneWMI.DataCollector).ServerName
				write-verbose "$(__LINE__)`t`$MyZDC is $MyZDC"
		} else {
		
				#If we get this far, no successful ZDC was found, return $null
				write-verbose "$(__LINE__)`tCould not locate ZDC.  Please investigate and rerun.  A likely cause is no valid servers are in the config file"
				$MyZDC = $null 
		
		} #End of If FarmIsAvailable block
	
		Write-Verbose -Message "Returning `$MyZDC ($MyZDC)"
		return $MyZDC 

} #End of Get-ZDC function

I was one of countless Citrix consultants that has seen the Citrix WMI service, and kind of ignored it.  In one of my past jobs, I had found a specific use for the WMI service, but that was the only use I’d ever found for it.  (For the curious, when you use the Citrix Service Provider licensing, it requires the WMI service to be active on your servers.  It is used to to query the license for some critical information.  I had started to set up the CSP environment, and it was reporting the incorrect license type, and the IMA service would not start.  I had to start the WMI service, and then the license began to report correctly, and the IMA started).

But, I digress :-)  In the new job, I needed to work on some scripting for our various farms (we have a mix of 4.5, 6.0, & 6.5 farms).  I had done some previous documentation type things with MFCOM in 4.5 farms, but I’d never done anything for 6.0/6.5.  I knew there were powershell cmdlets to perform a number of functions, so, that was a possibility, but I really needed to interact with all of the farms.  A coworker has a very very extensive script used to document server inventories.  I took a peek out of it out of straight curiosity, and he was using WMI calls (as expected) for everything, but to my surprise, he was using WMI calls to get Citrix data out of all 3 farms, with the same lines of code.  That definitely got my attention.

First, my coworker recommended I get Microsoft’s WMI explorer.  http://www.microsoft.com/en-us/download/details.aspx?id=24045.  This is a fantastic tool, and easily lets you connect to your local WMI providers, or remote WMI providers, and fully browse everything about them.  I’ve seen other WMI browsers, and the Microsoft one was just easier to use.  Having used this to help build my scripts, I’d strongly recommend you download it.

In my particular case, I need to query the Zone Data Collector for some information.  Generally, most environments have a dedicated machine or two to be the ZDC’s (and we are no exception).  As I was considering the design for my script, it occurred to me – what if one of those two is not going to be the ZDC at the moment my script ran?  It would fail.  It isn’t a critical function per-se, but I liked to plan to make sure my scripts will always run correctly (if at all possible).  So, I needed a way to discover the current zdc at any given moment. In theory, I could have tried to do a qfarm commend and then parsed the text, but that’s not elegant, and to run it remotely, I have to tie in something like psexec.exe or run it on one of my Citrix servers. But, I didn’t want those restrictions, so I created this powershell function script) to handle that discovery process.

The first step of course is define the function:

function get-zdc {

Because we are defining a function, and we want Powershell to automatically generate help, and support some of the common parameters, we turn on cmdlet binding.  This enables the script to act like a built-in cmdlet.  To do that, we use [CmdletBinding()].  This also has it’s own options that were not using here.

Next, we’re going to define a parameter for the function.  We need to tell it what machine to connect to in order to find the ZDC.  Because I’m dealing with lists of servers, I wanted to make sure it can handle multiple input names.  I want the function to take my list of servers and just find it.

Param(
[Parameter(mandatory=$true, valuefrompipeline=$true)]
[Alias("CN")]
[string[]]$ComputerName
)

The Param ( statement starts a list of parameters, and you only have 1 parameter block for each function.  This is required when the function is written this way.  It is possible to do an alternate structure that doesn’t use a Param block structure, but to me, that is more difficult to read.

The second line starts the definition of *a* parameter.  We’re telling it that the parameter is mandatory, and the script will throw an error if it is not provided, then we are telling it to get the value from the pipeline.  Pretty straight forward stuff, if we pipe the data into the function, it will accept it and use it.  Notice that these options are comma delimited, and are contained inside of parenthesis.   And the entire block is contained inside of brackets [ ]. (Just like the Param ()block itself, it’s not truly *required*, but it makes it easier to read.

The 3rd line defines an alias for the parameter.  This will provide a shorter/easier name to use on the command line.  Aliases are not required, but they are a nice option.  And while I didn’t use it here, you can string multiple aliases together, or you can have multiple alias blocks.  To do multiple aliases within one block, you just provide them as a comma delimited list.  I.e. [Alias("Alias1", "Alias2")] (And there is not any appreciable limit to the number of aliases you can have that I’m aware of).

Lastly, we are defining the type-cast of the data we will be inputting, along with the variable name. But,this line needs a little more explanation. As I mentioned, by using the brackets, we’re defining the type of data (a string), but the important part to this is that we’re using an extra set of brackets (shown in bold) to tell the system we will accept data from the pipeline. [string[]]. Then we are giving the input parameter a name ($ComputerName). Be careful in choosing your parameter names. Many functions have ‘standardized’ parameter names for a specific reason — by using these ‘standard’ names, you can pipe input in and out of the function and the following/preceding function will accept that data in those specific parameters. (That is an entire discussion in and of itself, and as always, there are alternate techniques that can be used with it or instead of it, but it is still a best practice.

As a side note you can also add a default to a parameter just by adding an equals sign and a value. If you do that, then your function will use the default value if one is not provided. This is a great idea for a mandatory parameter, if you have something that would be appropriate. As a quick example, if I need an integer number, and I’d like the default to be the answer to life, the universe, and everything, I would use [int]$Number=42.
Also note, that within a parameter block, you can use commas to separate multiple parameters.

Param (
[parameter(mandatory=$false,valuefrompipeline=$false)]
[Alias("P1")]
[Int]$Number=42,


[parameter(mandatory=$false,valuefrompipeline=$true)]
[Alias("P2")]
[string[]]$String='Some string'
)

Notice the comma in the example after the first parameter, and the fact that the second parameter does not have that comma. (Also, be aware, there are a lot of options that can be used on the parameter statement line, or you can skip them all depending on your needs.

Next time I’ll dig into the real meat of the function.

David Figueroa

I don’t have a lot of time for another post right now, but I found this one particularly interesting.

I was finding a lot of warning errors on my PVS servers.  There were numerous errors, but this was the most common.
The Citrix Broker Service failed to contact virtual machine ‘<machinename>’ (IP address ).
Check that the virtual machine can be contacted from the controller and that any firewall on the virtual machine allows connections from the controller. See Citrix Knowledge Base article CTX126992.
Error details:
Exception ‘Client is unable to finish the security negotiation within the configured timeout (00:00:05). The current negotiation leg is 1 (00:00:05). ‘ of type ‘System.TimeoutException’.

There were several articles on the subject, most of them talking about the VM’s registering, and deregistering, etc. but I didn’t have that problem. I ran down the articles, and none of the problems fit my situation.  Since I wasn’t really having a problem, I dropped the subject for a while.  I had some time recently to start looking back into the subject.

I had followed the best practices for the VM’s (or thought I had).  I ended up calling Citrix support, and went through everything.  We were going through all the same articles again, and not finding anything.  But, the Citrix tech noticed one thing.. I had the firewall turned off for the domain profile, but not for the private or public profiles.  We began discussing the subject, and why it was set that way.  Best practices say that the firewall be turned off for the PVS machines.  Since the machines already belonged to the domain, I turned off the domain profile by GPO.  (To me, this is a pretty typical security view – only enable/disable what you have to, and lock the rest).

It turns out that even though PVS is booting from the network, and that network connection is the very first thing established, as that streamed copy of Windows boots up, it does not recognize the network connection profile as the domain profile until well after the machine is up, and it has already tried to register.   Once it gets up far enough, the GPO takes effect, and the firewall comes down, the re-register works, and everything is good.   I turned around and adjusted the GPO to have the the firewall always off.  Success!  90%+ errors of the errors were gone.  I still get the occasional warning errors, but now they are unusual.

So, the next step will be to check the actual firewall configurations, and forcibly allow all the ports through the firewall in all profiles.

David F.

4.1 Wrinkle.. Quick update

Posted: March 21, 2014 in Citrix

Just to let everyone know — on my situation with the resolution & DPI scaling issue.  Citrix has escalated my case and they will be working with development to address it.

David F.

I haven’t had any time to work on this yet, but I still have the call open with Citrix.  However, my coworker who found the issue also found a way to get the full resolution he was looking for.  He went into the Display Settings and set the slider for “Change the size of all items” down to Smaller.  Obviously, this peaked my interest..  (And for reference, here is a link that discusses these settings http://www.eightforums.com/tutorials/28310-dpi-scaling-size-change-displays-windows-8-1-a.html.)  I immediately started thinking that it might be tinkering with the dots per inch (DPI) settings (http://en.wikipedia.org/wiki/Dpi).   As most long term Citrix admins will know, by default the ICA sessions are going to run at 96 DPI; this has been the standard display setting for years.  However, many of today’s high resolution monitors run at higher DPI settings to keep the fonts etc. from becoming microscopic.

So, on to some testing.  I booted up my Win 8.1 system I’m testing with and connected in.  As before, i got my 1536×864 resolution.  I jumped back to the local machine and checked that “Change the size…” setting, and it was set to the middle of the slider.  So, I logged out of my Citrix session, set the slider to the smallest setting, and logged back into my desktop.  Eureka.. full resolution. I sent an email to my engineer at Citrix with what I had found, and used some numbers that sounded good in my head.  (As it turns out, it was a fantastic guess.. the numbers were exactly correct).  What I found was this –

Normal View 96 DPI Scaled View 120 DPI Ratio (96/120)*100 = 80
1920 1536 80%
1080 864 80%

There’s the resolution I was getting.. So, I jumped in and went through the whole sequence again to test the next level. And came up with similar results.

Normal View 96 DPI Scaled View 144 DPI Ratio (96/144)*100 = 67
1920 1280 80%
1080 720 80%

It came out exactly as I had guessed it would based on 2 seconds of math.  I have since sent these results to Citrix, and it is completely reproducible.

So my working theory is that when the Receiver connects from a high DPI system, it cannot properly negotiate the resolution if the scaling is turned on.  I also believe that Windows 8.1 starts with the scaling enabled, whereas Windows 8.0 does not.  And when 8.0 is upgraded to 8.1, the DPI settings are left alone as a user preference.  It’s a good theory, and all the evidence bears it out.

David F.

A coworker of mine mentioned something to me that I found very interesting.  He had loaded up Windows 8.1 on his laptop, and he noticed that when he connected to Citrix, his screen looked ‘off’.   He dug in and found that the resolution was substantially lower than it should have been.  His laptop runs a 1920×1080 resolution.  He was running RDP through that ICA connection, and he was getting a 1536×864 resolution.  That was definitely odd..

I checked to see what he had one, and he had downloaded the 4.1 Receiver from Citrix’ website, and hadn’t used my install script.  But, that’s not a big deal.  He has 2 hard drives, and the 2nd one has Windows 7 installed on it.  He had put the same copy of the Receiver on that install, and when he had connected on the Windows 7 system, he was getting his full resolution.  He swapped the drives back and got the exact same results. 

With that, I started to dig into it to see what was happening.  Since I am working on another project with Windows 8.1, I was able to go and try it.  I tried it with the “regular” 4.1 client and the brand new 4.1.3.2 client.  (This new version is due to be released any day, it contains a number of fixes).  I called Citrix to see if this was a known issue, and it was not.  The tech on the line started digging into it, and he was able to reproduce the situation on his lab machine.  I ran through a series of connectivity tests with both my XenDesktop 5.6 farm and XenApp 6.5 farm.

Both connectivity sets got the same results..

  • With Web Interface 5.4 set on Fullscreen – the published desktop would take the full screen, but the resolution was the 1536×864.
  • With Web Interface set on 100% of screensize – the published desktop showed up filling up the available space other than the Windows 8.1 taskbar in a window
  • With Web Interface set on Seamless – as listed above, the screen would show up at that resolution, but with a titlebar, without sidebars, and with the Windows 8.1 taskbar.
  • With Web Interface set on Custom with 1920×1080, I got 2 different results.
    • XenDesktop – the session launched at 1920×1080, but filled up the screen room other than the Windows 8.1 taskbar.  But it was a windowed session with scrollbars.  You could view the entire screen by scrolling around the screen.
    • XenApp – the session launched in a window with the Windows 8.1 taskbar with scrollbars. It then promptly resized itself to the available screen real estate, again with the Windows 8.1 taskbar, and the resolution back at the 1536×864.   

The interesting part was seeing the multiple launches with different physical resolutions, still showed with the same resolution in the Citrix server. The graphics were not clear.. they definitely looked a little on the fuzzy side.  I did the same tests with different hardware (same graphical resolution) and got the exact same results.  

I’ve turned this information over to Citrix, and I expect to hear back next week on this.  But, as of now.. that combination of Windows 8.1 and Receiver 4.1 does not seem to want to connect at the correct resolution.  I’ll post more when I have updates. 

 

David 

Adventures with Receiver 4.1

Posted: February 19, 2014 in Citrix

I’m currently preparing to rollout Receiver 4.1 in our environment.  The primary driver has been the need for some of the fixes that have not been backdated to the 3.4 Receiver, and the fact that Citrix is pushing all the development on this new version.  Since we are migrating to XenDesktop 7.1, this is an important step in laying out that ground work.

I have spent weeks and weeks with the installation working on automating as much of user process as possible.  We’re working with our terminals joined to the domain (needed for the biometric authentication). The users log in to their terminals with the domain accounts.  Currently with the 3.4 version, the Receiver connects and populates shortcuts on the desktop and the start menu.  I am working on duplicating as much that same functionality with the 4.1 Receiver.

Out of the box, there are a number of features that are not installed by default, and it requires a command line installation to get them installed properly. (I suspect that last part is not entirely true, but I’ll discuss that later).  When you install the Receiver, by default, it does not install the pieces to do pass through authentication, and likely does not necessarily install the USB pieces, the Flash redirection, etc.  Well, our goal is to have people automatically logged in, and not add a 2nd login for this.  Overall, this is really a step backward.. you cannot control the passthrough login feature from the StoreFront server like you could in Web Interface.  So, on to Citrix eDocs (as you will recognize from my previous post.. not my favorite place have to go).  I looked up the directions and they are remarkably similar to Receiver 3.4.  That was definitely helpful.. I already had working scripts for that.

The 2 sets of directions are here: http://support.citrix.com/proddocs/topic/receiver-windows-enterprise-3x/ica-configure-command-line.html for the 3.4 Receiver, and http://support.citrix.com/proddocs/topic/receiver-windows-40/receiver-windows-cfg-command-line-40.html for the 4.x Receiver.   I’ll cover the various switches for the 4.x installation here and what they mean.

/silent and /noreboot are pretty self-explanatory; they make the installation completely silent, and tell it to not reboot the system.  The /noreboot is important in that if you use it, the 4.x Receiver is not fully usable until the system has been rebooted.  This is not terrible in and of itself, but it’s good to know.

/includeSSON – this tells the Receiver to install the single signon.  This is *not* the same as Citrix Single Sign-on (the old Password Manager which is being dropped).  This is the piece that does the passthrough authentication for the Receiver.  If you are not using other options in the installations this is supposed to be enough to get it working according to Citrix technical support.  (I have not verified this).  A key point to this is that it installs the ssonsvr.exe.  This process is what does the credential passthrough to the client.  (I’ll be discussing this more later).

There are several other options that can be used.  These are the same between 3.4 and 4.x. I believe these are used to pass to the internal MSI file, and they probably have to be capitalized because of it.

  • INSTALLDIR – tell it where to install the client to.  I’ve never seen it installed to an alternate location, but it is good to know that it is available.  By default, it installs to (x64 systems) c:\program files (x86)\Citrix\ICA Client and to (x86) c:\program files\Citrix\ICA Client.
  • CLIENT_NAME – this allows you to override the CLIENTNAME used by the XenApp server or by the VDA.  It overrides the default of %computername%.   I’m not sure why someone would want to do this, but again, it’s a nice to have option.
  • ENABLE_DYNAMIC_CLIENT_NAME – this tells it to allow the client name to be set dynamically.  This is the default.. it sets that name on the fly.  But to use the manual override from CLIENT_NAME, then you have to use this option and set it to No.  I’m not sure why you’d have to have multiple options to do the same thing, but you do.  My thought would be if you have CLIENT_NAME set, then it would automatically eliminate the dynamic clientname.
  • ADDLOCAL – this lets you customize the pieces that will be installed.   Again, we have several suboptions to this that are the same between them.
    • ReceiverInside – this is the piece that causes the plugins to appear inside of the Receiver. Currently, there still are not many actual plugins to handle, but they do exist.
    • ICA_Client – this is of course the ICA Client. It is a plugin, and is obviously necessary to do anything useful. I’m not sure this should even be an option?
    • SSON – this is the passthrough authentication piece. If you specify components, you need to add this for it to work. In my experience, even if you use the /includeSSON, you must still use SSON here.
    • USB – this enables the USB redirection capability. This obviously depends on your needs.
    • Flash – this enables Flash redirection. Currently, I don’t use this option since we are using terminals. With the terminals,the Flash movie is downloaded to the temp directory and executes from there (assuming flash is installed on the client). With the terminals, the temp directory is on a RAM drive and is limited to 100MB by default. With even a couple of flash items, or a semi-large video it will run out of space and crash. Therefore, I leave it out. If we had more PC’s in the environment, I’d probably mix the two installations.
    • DesktopViewer – this is piece that provides the Connection Bar inside of desktop sessions. Supposedly, if you connect to a published app with this enabled, it can cause issues. I use this option regularly, and I haven’t run into this.
    • Vd3d – this enables HDX 3d Pro. We don’t use any 3d apps, so this isn’t needed for our environment
  • ENABLE_SSON – this is needed to activate the Single Sign On. Again, I’m not sure why this would be needed if you already have the option installed, and another flag already set? But, it’s still required per Citrix.

This is where the similarities stop.  Here are the options for Receiver 4.x (I’m not covering the Receiver 3.4 in this article).

  • ADDLOCAL
    • AM – Authentication Manager. This is necessary to work with SSON to get the passthrough working. According to Citrix, it must be listed before the SSON item.
    • SelfService – this is the portion that supports the portion where the user can subscribe to applications
  • ALLOWADDSTORE – this setting controls whether the user is allow to add a store not predefined by the administrator
  • ALLOWSAVEPWD – this setting controls whether the user can save their password in the Receiver. I’m not sure how this would work if combined with stores from multiple domains. My guess would be that it would be saved on a per-account basis, but I have not had the chance to look into this.
  • AM_CERTIFICATESELECTIONMODE – This is used to configure SmartCard options.
  • AM_SMARTCARDPINENTRY – This sets the usage of the PIN option of the SmartCard
  • ENABLE_KERBEROS – this controls the use of Kerberos for pass through authentication
  • LEGACYFTAICONS – this is used exclusively for XenApp and is the equivalent of the old file-type association icons generated through the XA farm. It allows the Receiver to configure local icons to use the published applications.
  • ENABLEPRELAUNCH – this is used exclusively for XenApp on the backend of the Store. It allows the receiver to cause a user session to launch when the receiver logs in, without an application being launched
  • STARTMENUDIR – this allows you to place the icons generated under the specified subfolder in the Start Menu. It may work with XenDesktop? I haven’t tested it.
  • STORE0..STORE9 – this allows you to predefine up to 10 stores for the clients. Each STORE# entry is a separate Store (account)
  • ALLOW_CLIENTHOSTEDAPPSURL – this is for the new XenDesktop 7.x capability. It allows applications on the local system to be projected into an ICA connected desktop and appear as part of that desktop. It is the reverse of Seamless Applications. I plan to use this in my XD 7.x environment. This is a really exciting capability.

Based on that, I went through several iterations of the client install trying to reach my goal. In the end, I ended up with this command line:

CitrixReceiver.exe /silent /includeSSON ADDLOCAL="ReceiverInside,ICA_Client,SSON,USB,DesktopViewer,AM,SELFSERVICE" ALLOWADDSTORE=S ALLOWSAVEPWD=S ENABLE_SSON=Yes STORE0="StoreName;https://storefront.domain.com/Citrix/StoreName/discovery;On;Published Desktops" ALLOW_CLIENTHOSTEDAPPSURL=1

Most of this is fairly obvious. but some of the things that came out during my call with Citrix:

  • That the StoreName has to match the actual name in the interface in the StoreFront console.  It is also case-sensitive (again, per Citrix).
  • The AM needs to precede the SSON in the ADDLOCAL option.
  • The On in the Store description determines whether the account is activated within the console itself.  The eDocs says that it is to determine if you are delivering disabled stores, but that does not seem to be quite the case.  It seems to deliver all the stores, but then it leaves the ones marked as Off to be included, but the check mark within the Receiver not marked.   This could just be confusing wording in the eDocs..
  • In the Store definition on the command line the name provided must match the name in the StoreFront console (including case-sensitivity).  I really don’t understand why you need to put the name of the store when you are already providing the full URL to the store itself, and much of the information comes from the discovery sub-path. 
  • The 4.x Receivers do not create desktop icons.  (This is old news from Receiver 3.4 (non-Enterprise) but I still wanted to confirm it here for anyone reading.

So, now I have a stable script that installs the Receiver.  But on the first test, the passthrough piece didn’t work correctly.  I had my StoreFront configured correctly to add the passthrough authentication, but it still didn’t work.  I uninstalled it and reinstalled it multiple times, and a couple of times, the passthrough worked, but on most of them it didn’t.  That made no sense.. back to the phones with Citrix.  It turns out one of the “troubleshooting” steps is to change the Network Provider order and move the Citrix Single Signon service to the top of the stack.  That made me take a step back.. I hadn’t had to deal with the Network Provider order since the last time I had to integrate Citrix with Novell, years ago.  Because we’ll be imaging the terminals this won’t be much of an issue, but if it is really needed, then to me, Citrix should automate that as part of the install. It is handled by a simple registry value.  HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order\ProviderOrder = REG_SZ.  I will likely create a script to help automate that process as part of a wrapper for the install.

Now, I have my passthrough working.  At this point, this represents a lot of work.. uninstalling, reinstalling, playing with options, etc. But, another wrinkle came up today as I am finalizing the process for rolling this out.  I discovered an article last weekend that even the Citrix Receiver Team did not know about.  This article is http://support.citrix.com/article/CTX140244 It specifically addresses the icon refresh for the Receiver.  I noticed that the initial build of the icons is substantially slower in 4.1 compared to 3.4.  I figured I would test this out.  I deleted my shortcuts from the start menu, I set the registry entries according to the article, rebooted and logged back in.  Bang.. no icons.  I waited.. restarted the Receiver a few times, rebooted again.. no dice.  I simply had no shortcuts to the published desktops.  Yet another call to Citrix to understand what was happening.

It turns out, those registry entries only apply to Stores connecting to XenApp, and even then, only to the XenApp connection.  (I am currently planning on a store that talks to both XenDesktop & XenApp, although I am reconsidering that scenario).  It turns out that the problem has to do with how the Receiver handles its functionality.  When it connects to XenApp, it creates shortcuts in the Start menu directory (by default, this is %appdata%\microsoft\windows\start menu\programs).  These registry entries tell the Receiver to initially create the shortcuts in a substantially faster time than the default. However.. when it connects to XenDesktop, the process is completely different. It actually creates small executables for each of the “subscribed” desktops in %appdata%\Citrix\SelfService.  It then creates shortcuts to these executables in the Start Menu directory above.  These executables actually initiate the connection to the desktops.  And, to top it off.. these executables are encrypted with Citrix’ built in encryption routines.  So, they are *not* portable between users.  (I have not tested if they are portable between systems for the same users, but the fact that they use %appdata% instead of %localappdata% says that they probably are system portable.).  Right now, the Receiver Team at Citrix is recommending that users use the 3.4 Receiver if they can.  That team was not aware of this functionality.. they had to go talk to some people while I was on hold to find out.  The other downside of this is that these executables cannot be recreated!  The only way to get them back is to either uninstall the Receiver and clean it up with the utility, or to reset the profile completely.  I’m sure there is a somewhat easier answer, but no one knows what that is at this point.

Through my own digging around, it also turns out that Citrix is creating .net config files for these executables.  Each of the .exe’s will have a .config file with it that contains an XML entry to disable CRL checking.  That tells me that Citrix is fully aware of how slow these would be if they were doing the checking! (this is the default any .Net executables).  The code looks like this:
<?xml version=”1.0″ encoding=”utf-8″?>
<configuration>
<runtime>
<generatePublisherEvidence enabled=”false”/>
</runtime>
</configuration>

Currently, the initial login to the Receiver by the user is slow.. taking up to 30 seconds to login.. I am really hoping that Citrix will address these issues in Receiver 4.2, and go back to the actual shortcut architecture used by Receiver 3.4.

David F.

It’s  been a rough few weeks dealing with Citrix eDocs as I configure my storefront setup.  I’ve been working with Citrix since the WinFrame days when the knowledgebase was a Lotus Notes database.  In those days, it was not overly difficult to find information in the database.  These days however, it is difficult to find information, and occasionally when you do, it is just wrong.   While you can start with the builtin engine; these days I find it much easier to use a major search engine like Google or Bing to locate the information I need.

In my first example, I’m looking at the eDocs to configure a command line install for Receiver 3.4 Enterprise (CU3 version in specific).  The page link is http://support.citrix.com/proddocs/topic/receiver-windows-enterprise-3x/ica-configure-command-line.html.  If you try to locate it through the builtin feature, it’s difficult to locate. If you start with a seemingly straightforward set of words.. ‘receiver 3.4 enterprise command line switches’ You’d think this would turn up something easily.  But if you look at the screenshot, it’s not even on the first page?

Citrix Search Engine Results

But, when you look at the Google results, it’s actually the number 2 result with the same set of search terms (literally a copy & paste).

I found my article, and started testing out my scripts.  Seemed easy enough to start with.. But, I started digging in and creating my install script, and it seemed to work, but none of the shortcuts appeared in the start menu.   I ended up on the phone with Citrix trying to diagnose what had happened?  They had me uninstall the Receiver and reinstall it multiple times, using the Receiver Cleanup utility in between each round (Cleanup Utility – http://support.citrix.com/article/CTX137494).  It turns out that the eDocs were in fact, wrong.  The offending section is here:

According to the eDocs, the store requires a URL using the subdirectory of /resources/v1.  The actual URL required actually ends in /pnagent/config.xml.  I have not really spent any time with StoreFront 1.x, so it’s possible that it used to be the correct path?  If that was the case, then it should actually refer to which version the URL is for.  However, this is presented as the current documentation.  And if *that* is the case, then it should include both the v1.x and v2.x URL’s and indicate that information.  However, it does not.  The Citrix technician agreed with me, and has submitted an internal item to try and get that changed.

My second big issue (recent) had to do with a reference to the PvD disk size when used with PVS.  This one might be wrong?   I am fairly unfamiliar with PvD beyond the concepts & theory.  However, there is a specific reference in the eDocs (http://support.citrix.com/proddocs/topic/personal-vdisk-7x/pvd-best-practices-wrapper.html) saying that “The PvD size should always be larger than the PVS write cache disk (otherwise PVS might erroneously pick the PvD disk for use as its write cache).”  Ummm.. what??  That made *no* sense to me. I reasoned this out, and I believe this one to be wrong.  My reasoning is pretty straightforward — when you use PVS (assuming you are cache on device’s hard drive), my understanding is that it chooses the largest available free space on a locally attached drive to create the disk cache.  So.. if you have a larger PVD drive, then I would think that PVS would deliberately choose that drive, which in theory could lead to a quicker crash on the VM.  If your PvD drive is smaller, then there is a very good chance the free space will be a lot smaller. I mentioned it to Citrix with my previous issue as an “out of curiosity” item.. and they believed I was probably correct.  I can’t imagine any scenario where that statement makes sense?

These are just 2 examples of the staggering flaws I have found with eDocs.  No matter how much the Citrix field SE’s try to sell me on this reference, I firmly believe that the eDocs need a complete teardown and rebuild.  I haven’t even touched on the Table of Contents/Navigation tree ;-)  Don’t get me wrong, I love Citrix’ technology (despite the fact that they seem to be working more and more like older Microsoft – shove it out the door and fix it later).  I firmly believe Citrix can get this fixed.. and like the Nike commercials.. they need to ‘Just do it’.

As many of my coworkers and former coworkers know, I have a strange, unintended ability to locate bugs in software.  Today’s bug was the first serious bug of the year.

Over the course of the past several months, I had been working with Citrix Escalation on a different bug.  Apparently we were one of the 5 companies in the world to experience this particular bug.  (Null pointer dereference in the audio module vdcamn.dll that would seemingly randomly disconnect ICA sessions.  But, I had some private fix files, and those files became part of Receiver 3.4 Enterprise CU3).

This holiday weekend was our normal patch weekend, and I had a long string of items to patch, including upgrading my PVS 6.1 to Hotfix#19.  As some will know, HF19 is a complete reinstall, including the old fun task of reverse imaging your vdisks to replace the target software etc.  During the course of this imaging, I had a different problem that I was working on (at least I thought it was.  I ended up restarting the imaging process, because I was sure I had broken *something*.  During the course of a VDA uninstall, I kept getting strange errors about personal vDisk not being able to be installed in the XenDesktop setup log (%temp%\Citrix\XenDesktop Installer\XenDesktop installation.log) with an error 1603.  I completely redid my reverse image on the broken disk, and started again.

As I hammered away at this process, I had the issue creep up again.  Since it seemed very odd that the same error would reappear, when I was following the process correctly, I started digging in deeper.  When I started looking around the file systems, I noticed on the one disk image that there were leftovers for personal vDisk in c:\program files\citrix, and in c:\program files (x86)\Citrix, so I suspected I might have found my issue.  I cleaned them up and tried the installation again, and……   same error.

I poked around ye ole’ internet again, and found a very helpful article – http://blogs.msdn.com/b/astebner/archive/2005/08/01/446328.aspx.  It mentioned getting more information in the MSI logs.  However, it also mentioned that many products won’t produce MSI logs even using his listed methods.  It was still worth a look.  Fortunately, Citrix provides the MSI logs in a subdirectory – %temp%\Citrix\XenDesktop Installer\MSI Log Files\).  There I found read errors when accessing my iso file in VMWare.

All of my standalone machines registered correctly, but none of my PVS machines would register.  That was odd..  It’d been a very long day so I just called Citrix, since I was already on my well to a nice brain-fry.  We started digging around looking at the basics.. I explained my various steps, and what was occuring.  So, we pulled out my trusty copy of XDPing (http://support.citrix.com/article/ctx123278) and it was showing failures in the DDC registration, like it could not find the DDCs.  We jumped immediately into the registry (although the Citrix tech started at the top of the tree to search, I pulled up the article listing the value (http://support.citrix.com/article/ctx133384).  The registry value for ListOfDDCs was missing.  I inserted the appropriate value in place, restarted the Citrix Desktop Service, and within 3 seconds it was registered.

With that information in hand, I let Citrix go while I worked on reinstalling my vDisks.  I rebuilt them all, however, they all had issues uninstalling the VDA – all the errors pointed to references of the personal vDisk installer on the iso image.  (At this point, I still do not know if I have a VMWare problem, or a corrupted iso image).  I installed the 5.5 VDA and set the registry value.  I upgraded the VDA with the hotfix (XD560VDAWX64400 – http://support.citrix.com/article/CTX138550. (The 32bit version is http://support.citrix.com/article/CTX138551). I didn’t bother with the sealing steps, this was just a quick test.  I brought the image back online, and it would not register.   Back to the registry, and the ListOfDDCs value was gone. I put the image back in private mode, reinserted the ListOfDDCs, put it back in standard, and retested again; success!.

I emailed a few people at Citrix, and I was told this is normal behavior when upgrading the 5.5 VDA.  I let them know what it happened with the 5.6 VDA also.  So, it’s a bug.   But, I have no idea why they would deliberately strip out the ListOfDDCs?

David F.

StoreFront & 1030 Errors

Posted: January 13, 2014 in Applications, Citrix

I’m in the process of building my StoreFront environment in preparation to migrate to XenDesktop 7. However, during some initial testing, we had several issues trying to launch applications, most of them resulting in 1030 errors. There are several links & pages around 1030 errors when trying to launch an application through StoreFront. Well, during my testing, these all ended up being relatively useless.

The layout:
2 Web Interface 5.4 servers, load balanced through a Netscaler
2 StoreFront 2.1 servers, not load balanced yet.
1 XD 5.6 farm
1 XA 6.5 farm

The internal clients currently use the WI VIP (virtual ip address) to launch published XD desktops, and the desktops launch some published apps from the XA farm. The Netscaler is also an Access Gateway used for external access.

During the initial SF build, we configured and tested the Receiver for Web on the server, configured the needed VIP for the SF (not in use yet), and generally got the environment prepared for more testing. Other projects reared their heads temporarily, but I picked the testing back up. I modified the URL for my Receiver 3.4 CU2 Enterprise to point at the SF for testing. The SF icons would not appear, and nothing was working. A quick call to Citrix, and I found out that you need to put in a full path to a URL that does not exist directly in the IIS path on the SF server. It turns out that enabling Legacy support creates a virtual path that is embedded in the compiled code for all of the stores. By taking the store path, and tacking on /pnagent/config.xml will provide the needed configuration file.

Now, the icons appeared, but the apps simply would not launch. The connections kept failing with 1030 errors. I ran through several testing scenarios, and a very long call with Citrix. I came up with some important facts.

1. Receiver 4.1 would not launch the applications correctly from StoreFront, but launched perfectly from Web Interface.
2. Receiver 3.4 would not launch the applications correctly from StoreFront, but launched perfectly from Web Interface.
3. Receiver 3.4 Enterprise would not launch the applications correctly from StoreFront, but launched perfectly from Web Interface.

Ultimately, we turned on ICA logging* (see below) and compared the ICA files being generated. At first glance, the ICA files were identical except for items that should be different (like Session keys, session reference ID’s etc.) — all of the “key” items were correct. We ran the tests multiple times, but on a line by line comparison, one thing really stood out. There was a reference to the Proxy server being set to Automatic with the Receiver 4.1. That flagged a major note for me.. We have an authenticated proxy that in our WI environment requires us to set it for proxy as Client-defined, instead of the default automatic. I mentioned this to the folks at Citrix, and it turns out there is *not* a GUI entry for the proxy settings in SF 2.1 (and prior). Citrix was able to turn up an article () that specifically mentions setting the proxy in the default.ica file in a SF 1.2 server for a completely unrelated situation. However, on a guess, we tried setting it, and there it was… the applications launched correctly from SF with the 3.4 Receiver Enterprise. I will not be surprised if Citrix generates another article based on this.

Settings:
The default.ica file lives in c:\inetpub\wwwroot\citrix\{storename}\app_data\ directory.
The line you would add is ProxyType=None in both the [WFClient] and [Application] sections. (Also, be aware, there are also directories for c:\inetpub\wwwroot\citrix\{storenameweb}\. There is no default.ica directory in the location, and there should not be.

*For ICA logging, there are a couple of registry entries to set:

(x86)
HKLM\SOFTWARE\Citrix\ICA Client\Engine\Configuration\Advanced\Modules\Logging
(x64)
HKLM\SOFTWARE\Wow6432Node\Citrix\ICA Client\Engine\Configuration\Advanced\Modules\Logging
LogFile=c:\temp\ica.log
LogICAFile=true

Be sure to precreate the directory for the log path. No reboot it is required.. the logging takes effect immediately.

David F.