So I'm getting the dreaded “An error occurred while making the requested connection” while trying to launch some applications from our Citrix Web Interface. It started happening suddenly but I'm tasked with figuring out why. First thing I did was go to the Web Interface and check the event logs. I found the following:
This wasn't much help, but I was able to narrow down that this was happening on one set of our servers that are split across two DC's. One set of servers at BDC was fine, the other set of servers at ADC had a subset of servers that were not. Doing a qfarm /load showed the problematic servers had no users on them at all, and no load evaluators were applied that would be causing our issue.
Logging into the server it was deteremined that it's DNS was registered to the wrong NIC (it was a PVS server that was multi-homed) and even worse for some of the servers, the NIC IP address was an old address and the new address wasn't even resolving!
For some reason it now appears our Windows 2008 servers are not registering their DNS on startup. To resolve this issue for us we added a startup script with the simple command "ipconfig /registerdns" and within a few seconds the IP address is registered within DNS correctly and with the correct NIC. We suspect that something is misconfigured at ADC as BDC does not have this issue nor does it need this tweak, but this is our work around until that is resolved.
Monday, July 22, 2013
Wednesday, July 17, 2013
Powershell script to compare Citrix Webinterface files
I've created a powershell script that will compare Citrix Webinterface files then export them out to a csv file.
#***************************************************************************************************************
#* Created by: Trentent Tye
#* Intel Server Team
#* IBM Canada Ltd.
#*
#* Creation Date: Jul 17, 2013
#*
#* File Name: parse-webinterfaceconf.ps1
#*
#* Description: This script will generate a CSV file of all the webinterface.conf files that you copy into
#* the same folder as this script. For the purposes of our uses I have renamed the .conf files
#* to %URL%.conf. This script will take the file name of the conf files to use as the CSV
#* headers then go through that file and compare if the uncommented values exist as compared
#* to the master "values.txt" file. The "Values.txt" file was generated by taking the numerous
#* WebInterface files and deleting all lines that start with "#" and then removing duplicates
#* of all the values that were left. For the 3 .confs I started with there are 160 values
#* amoung all three that have had a value set.
#*
#*
#***************************************************************************************************************
$dirlist = Get-ChildItem -filter *.conf | Select-Object -ExpandProperty Name
#header value in powershell "Import-CSV" must be an array, a text variable parses as one header item
$header = @()
$header += "Value"
foreach ($item in $dirlist) {
$header += $item
}
#import csv with our header
$values = import-csv Values.txt -Header $header
#do a foreach item in Values append the matching value in the other .conf files
foreach ($item in $values) {
#check to see if the "Value" matches an item in the $dirlist and add that property in that file
foreach ($diritem in $dirlist) {
#get the webinterface.conf file
get-content $diritem | Foreach-Object {
#check to see if one of the values in the "Value" file matches one of the values in the file that is NOT commented out
if ($_.StartsWith($item.Value)) {
#get the value to the right of the equal sign
$pos = $_.IndexOf("=")
$rightPart = $_.Substring($pos+1)
#set the value to the appropriate column in the CSV
$item.$diritem = $rightPart
}
}
}
}
$values | Export-CSV complete.csv -NoTypeInformation -force
#***************************************************************************************************************
#* Created by: Trentent Tye
#* Intel Server Team
#* IBM Canada Ltd.
#*
#* Creation Date: Jul 17, 2013
#*
#* File Name: parse-webinterfaceconf.ps1
#*
#* Description: This script will generate a CSV file of all the webinterface.conf files that you copy into
#* the same folder as this script. For the purposes of our uses I have renamed the .conf files
#* to %URL%.conf. This script will take the file name of the conf files to use as the CSV
#* headers then go through that file and compare if the uncommented values exist as compared
#* to the master "values.txt" file. The "Values.txt" file was generated by taking the numerous
#* WebInterface files and deleting all lines that start with "#" and then removing duplicates
#* of all the values that were left. For the 3 .confs I started with there are 160 values
#* amoung all three that have had a value set.
#*
#*
#***************************************************************************************************************
$dirlist = Get-ChildItem -filter *.conf | Select-Object -ExpandProperty Name
#header value in powershell "Import-CSV" must be an array, a text variable parses as one header item
$header = @()
$header += "Value"
foreach ($item in $dirlist) {
$header += $item
}
#import csv with our header
$values = import-csv Values.txt -Header $header
#do a foreach item in Values append the matching value in the other .conf files
foreach ($item in $values) {
#check to see if the "Value" matches an item in the $dirlist and add that property in that file
foreach ($diritem in $dirlist) {
#get the webinterface.conf file
get-content $diritem | Foreach-Object {
#check to see if one of the values in the "Value" file matches one of the values in the file that is NOT commented out
if ($_.StartsWith($item.Value)) {
#get the value to the right of the equal sign
$pos = $_.IndexOf("=")
$rightPart = $_.Substring($pos+1)
#set the value to the appropriate column in the CSV
$item.$diritem = $rightPart
}
}
}
}
$values | Export-CSV complete.csv -NoTypeInformation -force
Import-Csv -header $variable
I ran into an issue with Import-CSV where I was trying to pass a variable to the -header and it was failing pretty horribly, creating a single field instead of multiple fields.
I created a script to generate a CSV from Citrix WebInterface .conf files to compare the various web interfaces we have so that when we migrate users from the older interface to the newer interfaces we can properly communicate to them the changes they will experience. In the course of developing this script I wanted to do a "dir *.conf" command and use that output as the header in the CSV. Here is what I did originally:
$dirlist = Get-ChildItem -filter *.conf | Select-Object -ExpandProperty Name
#header value in powershell "Import-CSV" must be an array, a text variable parses as one header item
$header = "Value"
foreach ($item in $dirlist) {
$header += $item
}
#import csv with our header
$values = import-csv Values.txt -Header $header
This failed. Our $header variable became a single header in the CSV. The help for "Import-CSV" says the -header should have a string value. I tried $header.ToString() but it didn't work either. I found you need to do the following:
$dirlist = Get-ChildItem -filter *.conf | Select-Object -ExpandProperty Name
#header value in powershell "Import-CSV" must be an array, a text variable parses as one header item
$header = @()
$header += "Value"
foreach ($item in $dirlist) {
$header += $item
}
#import csv with our header
$values = import-csv Values.txt -Header $header
This makes an array then adds the appropriate values to the $header variable and the import-csv now has multiple columns.
Hurray!
I created a script to generate a CSV from Citrix WebInterface .conf files to compare the various web interfaces we have so that when we migrate users from the older interface to the newer interfaces we can properly communicate to them the changes they will experience. In the course of developing this script I wanted to do a "dir *.conf" command and use that output as the header in the CSV. Here is what I did originally:
$dirlist = Get-ChildItem -filter *.conf | Select-Object -ExpandProperty Name
#header value in powershell "Import-CSV" must be an array, a text variable parses as one header item
$header = "Value"
foreach ($item in $dirlist) {
$header += $item
}
#import csv with our header
$values = import-csv Values.txt -Header $header
This failed. Our $header variable became a single header in the CSV. The help for "Import-CSV" says the -header should have a string value. I tried $header.ToString() but it didn't work either. I found you need to do the following:
$dirlist = Get-ChildItem -filter *.conf | Select-Object -ExpandProperty Name
#header value in powershell "Import-CSV" must be an array, a text variable parses as one header item
$header = @()
$header += "Value"
foreach ($item in $dirlist) {
$header += $item
}
#import csv with our header
$values = import-csv Values.txt -Header $header
This makes an array then adds the appropriate values to the $header variable and the import-csv now has multiple columns.
Hurray!
Tuesday, July 16, 2013
Utilizing MCLI.exe to comment the newest version of a vDisk on Citrix Provisioning Services (PVS)
I've written this script to utilize MCLI.exe to add a comment to the newest version of a vDisk and have marked which fields correspond to what.
"C:\Program Files\Citrix\Provisioning Services\MCLI.exe" get diskversion -p disklocatorname=XenApp65Tn03 sitename=SHW storename=XenApp | FINDSTR /i /C:"version" > %TEMP%\diskver.txt
FOR /F "tokens=1-2 delims=: " %%A IN ('type %TEMP%\diskver.txt') DO set VERSIONN=%%B
"C:\Program Files\Citrix\Provisioning Services\MCLI.exe" set diskversion -p version=%VERSIONN% disklocatorname=XenApp65Tn03 sitename=SHW storename=XenApp -r description="Test"
This script can now be added to the "PVS Automatic" update feature to automatically comment the latest vDisk when it is updated.
"C:\Program Files\Citrix\Provisioning Services\MCLI.exe" get diskversion -p disklocatorname=XenApp65Tn03 sitename=SHW storename=XenApp | FINDSTR /i /C:"version" > %TEMP%\diskver.txt
FOR /F "tokens=1-2 delims=: " %%A IN ('type %TEMP%\diskver.txt') DO set VERSIONN=%%B
"C:\Program Files\Citrix\Provisioning Services\MCLI.exe" set diskversion -p version=%VERSIONN% disklocatorname=XenApp65Tn03 sitename=SHW storename=XenApp -r description="Test"
This script can now be added to the "PVS Automatic" update feature to automatically comment the latest vDisk when it is updated.
Thursday, July 11, 2013
Wednesday, July 10, 2013
Troubleshooting Audio issues in Citrix XenApp
We recently ran across an issue with XenApp 6.5 where we were publishing an application that required the "Beep" but it wasn't working. The following is the troubleshooting steps I did to enable audio to work on that application.
First we created a Citrix policy to enable audio. This policy looked like so:
We filtered on a user security group to enable the client audio redirection and added that filter group to the application. From the original appearance of things, this should have been sufficient to enable client redirection. But it did not. So I wanted to verify that the policy was actually applying to the user account. To do that, you login to the system with a user account and check in Regedit for the value "AllowAudioRedirection". If it's set to 0x1 then the Citrix group policy has evaluated that client redirection should be enabled for your session.
Unfortunately, I still did not have audio redirection working...
Citrix advises that you can use dbgview.exe to further troubleshoot the Citrix Receiver to assist. I launched dbgview.exe and started the trace and launched the application from the Webinterface.
"00000043 0.60113800 [7752] CAMSetAudioSecurity: Wd_FindVdByName failed"
CAM is a virtual channel (Virtual Channel Priority for Audio) and we can see it's failing. I then used the Citrix ICA creator and launched the application using that. The dbgview for that output looks like so:
00000013 0.44386363 [4496] CAMSetAudioSecurity: success
We can see that the audio virtual channel was able to successfully latch and I confirmed I had audio in the application.
From here the issue appeared to be when I launched the application from the webinterface or desktop shortcut. I then compared the two ICA files, the one from the web interface and the one I created separately to see what was different. The difference was glaringly obvious. The working ICA file had "ClientAudio=On" and the broken one had "ClientAudio=Off".
Curious, I launched AppCenter and clicked through the applications settings and saw the following:
"Enable legacy audio" was unchecked. I checked it and then logged off and logged back on the web interface and when I downloaded the ICA file, "ClientAudio=On" and I had audio. I then unchecked that setting and confirmed it manipulated the ICA file as with it unchecked the ICA file generated had "ClientAudio=Off"
Who knows why it's called "legacy audio". May as well just call that option "Enable audio" as that would be more accurate. The Citrix documents on this setting says the following:
http://support.citrix.com/proddocs/topic/xenapp6-w2k8-admin/ps-sessions-en-dis-aud-pubapp-v2.html
To enable or disable audio for published applications
First we created a Citrix policy to enable audio. This policy looked like so:
We filtered on a user security group to enable the client audio redirection and added that filter group to the application. From the original appearance of things, this should have been sufficient to enable client redirection. But it did not. So I wanted to verify that the policy was actually applying to the user account. To do that, you login to the system with a user account and check in Regedit for the value "AllowAudioRedirection". If it's set to 0x1 then the Citrix group policy has evaluated that client redirection should be enabled for your session.
Unfortunately, I still did not have audio redirection working...
Citrix advises that you can use dbgview.exe to further troubleshoot the Citrix Receiver to assist. I launched dbgview.exe and started the trace and launched the application from the Webinterface.
"00000043 0.60113800 [7752] CAMSetAudioSecurity: Wd_FindVdByName failed"
CAM is a virtual channel (Virtual Channel Priority for Audio) and we can see it's failing. I then used the Citrix ICA creator and launched the application using that. The dbgview for that output looks like so:
00000013 0.44386363 [4496] CAMSetAudioSecurity: success
We can see that the audio virtual channel was able to successfully latch and I confirmed I had audio in the application.
From here the issue appeared to be when I launched the application from the webinterface or desktop shortcut. I then compared the two ICA files, the one from the web interface and the one I created separately to see what was different. The difference was glaringly obvious. The working ICA file had "ClientAudio=On" and the broken one had "ClientAudio=Off".
Curious, I launched AppCenter and clicked through the applications settings and saw the following:
"Enable legacy audio" was unchecked. I checked it and then logged off and logged back on the web interface and when I downloaded the ICA file, "ClientAudio=On" and I had audio. I then unchecked that setting and confirmed it manipulated the ICA file as with it unchecked the ICA file generated had "ClientAudio=Off"
Who knows why it's called "legacy audio". May as well just call that option "Enable audio" as that would be more accurate. The Citrix documents on this setting says the following:
http://support.citrix.com/proddocs/topic/xenapp6-w2k8-admin/ps-sessions-en-dis-aud-pubapp-v2.html
To enable or disable audio for published applications
If you disable audio for a published application, audio is not available within the application under any condition. If you enable audio for an application, you can use policy settings and filters to further define under what conditions audio is available within the application.
Emphasis is mine.
Anyways, and now we have our applications with working audio and everything seems to be good again :)
To summarize the enable audio for a XenApp application you must:
1) Enable "legacy" audio
2) Enable a Citrix policy to configure audio redirection
3) Done.
- In the Delivery Services Console, select the published application for which you want to enable or disable audio, and select Action > Application properties.
- In the Application Properties dialog box, click Advanced > Client options. Select or clear the Enable legacy audio check box.
Emphasis is mine.
Anyways, and now we have our applications with working audio and everything seems to be good again :)
To summarize the enable audio for a XenApp application you must:
1) Enable "legacy" audio
2) Enable a Citrix policy to configure audio redirection
3) Done.
Monday, July 08, 2013
Powershell script to manipulate "Register this connection's addresses in DNS"
We run a multihome NIC setup with our Citrix PVS servers and the "Provisioning" Network is a seperate VLAN that is only used by the PVS servers and goes no where. Unfortunately, however, the "Provision" NIC can register itself in the DNS, causing devices outside of the Provisioning network (everyone) to resolve to the incorrect address. To resolve this I ran this script across all my vDisks to remove the ability of the provision network to register itself as available in DNS.:
$provNic=Get-WmiObject Win32_NetworkAdapter -filter 'netconnectionid ="Provision"'
$prodNic=Get-WmiObject Win32_NetworkAdapter -filter 'netconnectionid ="Production"'
$adapters=Get-WmiObject Win32_NetworkAdapterConfiguration -filter 'IPEnabled=TRUE'
foreach($adapter in $adapters) {
if ($prodNIC.name -eq $adapter.Description) {
$adapter.SetDynamicDNSRegistration($true,$false)
}
if ($provNIC.name -eq $adapter.Description) {
$adapter.SetDynamicDNSRegistration($false,$false)
}
}
As you can see above, we have two NICs, "Provision" and "Production". We do not want "Provision" registerted so it gets the $false,$false set, whereas "Production" gets $true,$false.
$provNic=Get-WmiObject Win32_NetworkAdapter -filter 'netconnectionid ="Provision"'
$prodNic=Get-WmiObject Win32_NetworkAdapter -filter 'netconnectionid ="Production"'
$adapters=Get-WmiObject Win32_NetworkAdapterConfiguration -filter 'IPEnabled=TRUE'
foreach($adapter in $adapters) {
if ($prodNIC.name -eq $adapter.Description) {
$adapter.SetDynamicDNSRegistration($true,$false)
}
if ($provNIC.name -eq $adapter.Description) {
$adapter.SetDynamicDNSRegistration($false,$false)
}
}
As you can see above, we have two NICs, "Provision" and "Production". We do not want "Provision" registerted so it gets the $false,$false set, whereas "Production" gets $true,$false.