Sep 242021


This guide is geared around explaining how Zoom and Citrix work together, and it will show you the Architecture and provide information for what is needed on the clients. There is information added in the document for education purposes as well. At the time of writing this blog, I tested everything on an older version. However, I updated some screenshots to reflect a new version. I did keep the old screenshots to help show the details as well. The same principle applies, though. 

Zoom VDI information 

  1. Zoom requires both the “Zoom Media Plugin” + “Zoom Client for VDI” to match exactly from version 2.1.5 documented at –
  1. The Citrix Team handles the “Zoom Client for VDI” installations on all VDI machines. The information here Is strictly for informational purpose
  1. For your company managed device, You can use SCCM to push out the “Zoom Media Plugin” to corporate devices
  1. Personal devices that are being used to connect to Citrix VDI/Published will need the “Zoom Media Plugin” installed on their personal device. We provided a URL for the employee to go and download this.  Remember Its important to make sure the Plugin need to match on the Client and VDI side

The current VDI installer is 

Zoom VDI installer


The Clients need to have this version

Zoom Plugin for Clients 


VDI downloads and backward compatibility Chart

  1. This is a link to show you the backward compatibility for Citrix and how to get the downloads

Remember when upgrading the plugins, The VDA VDI installer but be at the same version or newer than the Plugin on the clients. If the client has a newer plugin installed than the backend VDA VDI install. It will not work the way it is supposed to, and the offloading process will NOT occur. I always find it safe to upgrade the VDI installer first (Citrix VDA), as it will be greater than the Zoom HDX Plugin on the clients. It seems to work well this way. In your case, just test things before you deploy. 

“To be compatible, the plugin version must be equal or less than the Zoom VDI application version. Installing a plugin with a version greater than the Zoom VDI application is not supported. Zoom always recommends updating the Zoom Plugin after updating the Zoom VDI application as many new features require an updated plugin. “

Zoom VDI Plugins for Clients URL


VDI Release Version 5.7.6 – Zoom Help Center

The VDI plugin on the left goes on the VDA (Arrow Red)

The Zoom HDX Plugin (Arrow in Blue) is the installer for the Client.

They both are needed to work together to offload the audio and Video to the client.

High Level Architecture of Zoom in Citrix 

*I didn’t create this as I referenced it in this blog. Context is at the bottom on the blog.*

How to install the “Zoom Media Plugin” for a personal device

Open an internet browser of the user’s choice.

Put this URL in the search bar

Download the required Zoom Media Plugin for the operating system that is needed

In this example, I have a Windows Operating System. I downloaded Windows x86 or x64: 5.4.59208.1207. Once it downloads, the Zoom Media Plugin. The typical area of download will be store in the Downloads folder. 

Double click on the  ZoomCitrixHDXMediaPlugin.msi. It will now open up and start the process.

Click next

Click next 

Click Next

Once its starts intalling, It will ask you if you want to allow the software to make changes to your device. Click yes

If you receive this error, you have to close out of the Citrix session, and Exit Citrix workspace

Before exiting the Citrix workspace, please save all your work, and properly exit the application that is running.

Once you complete this, proceed to exit from Citrix Workspace.

Go to the task tray in the right hand corner, Hit the up arrow, and click “sign out”

If you get this, click sign out.

Give it 30 seconds, and proceed to Exit Workspace.

Go to the task tray in the right hand corner, Hit the up arrow, and click “sign out”

Now go back to the zoom install, and click retry

You will then see this 

You can verify this shows in the control panel, under programs and features

You have completed the Zoom Media Plugin on the client device you are using. Now you go log back into the Citrix Virtual desktop and resume your work.

Testing Cam and Audio

VDA session

Open up the Zoom setting on the VDA and look at the statistics to see what is doing.

Picked my Mic up just fine

Rolling out and removing users installs with WEM

  1. When I needed to start rolling this out, I found that Zoom makes a user install as well. Just like teams. So, I found an uninstaller CMD, and deployed it with Citrix WEM.
  2. When I user goes to connect to a meeting this will come up.
  1. It appears though if you have the Zoom VDI client in first it will not install this either.
  2. I Created a WEM external Task, that will run this.  %appdata%\Zoom\uninstall\Installer.exe /uninstall /silent
  1. I plan on appmasking this location, I just need to make sure I don’t break Zoom and understand the details first
  2. Ideally, I would app mask this location C:\Users\%username%\AppData\Roaming\Zoom
  3. Add Zoom.exe into the CPU optimization area


  1. Citrix Virtual Desktops – Zoom – Microphone and video not working in ICA session
  3. Download and install the Zoom Citrix Media Plugin found in the link below install the client of the VDA and the Plugin on the endpoint:
  1. Note: Plugin version must be the same on the VDA and endpoint
  1. Additional resources:

Zooms Troubleshooting Resource

VDI Client Registry Settings

Group Policy Settings

Getting Started with VDI

Getting started with VDI – Zoom Help Center


How to deliver optimized Zoom meetings with Citrix | Citrix Blogs

I run zoom in a published Desktop as well, but I do not run it as a seamless application such as a published application. Zoom has a statement around this as well.

“Note: Running Zoom as a published app is currently not supported. “

This concludes the operations on making Zoom work in a Citrix VDI setup.

Oct 212020


The Citrix WAN optimization policy (or “low bandwidth” policy) aims to compress and reduce the bandwidth used by the ICA protocol by lowering the visual quality for users with slow and unreliable connections. This article will benchmark the best possible configuration for the low bandwidth policy in a Citrix 7.15 LTSR CU3 environment.

Testing Protocol

In order to determine the most efficient WAN optimization policy in the Citrix environment (7.15 LTSR CU3), a benchmark tool will be used to execute a predefined set of actions for accurate data collection across the different tests run. The tool used for this documentation is PCMARK10 on Windows 2016. The test is composed with two specific configurations:

Web (Browsing + Multimedia): automated testing of HTML5 content rendered in a web browser, including video playback and rich media web browsing.

Office (Writing + Spreadsheets): automated testing of documents writing, with text typing simulation, images and text blocks pasting, pages scrolling, spreadsheets generation with large number of cells and graphics.

Web Browsing and Office tests are executed separately to measure the encoder performance in each context (multimedia or text).

Default configuration baseline

The ICA protocol configuration baseline for remote access by default is set to medium quality.

Specific settings excluded from configuration

Enable Extra Color Compression:
This setting will add extra picture compression at the expense of visually degraded quality. The measurements during the benchmark showed that this option added an interesting gain in term of bandwidth reduction, but the visual impact, especially on text, was not negligible. As you can see on the picture below, some text outputs are blurry and difficult to read.

The test is blurry beyond user acceptance when using Extra Color Compression

This option will be removed from the scope of the low bandwidth policy.

Target Minimum Frame Rate
The “Target minimum Frame Rate” setting is associated with the legacy mode (Adaptive Display or Progressive display configuration) but still referenced in 7.15 LTSR when using the compatibility mode. It is not clear how this setting is influencing the bandwidth compression when reaching low FPS and will not be included in the benchmark. The default value of 10 fps is used in all configurations.

Testing parameters

Different parameters are tested for a total number of six “Low Quality” tests (LQ1 to LQ6).

Test results

LQ5 is the most efficient configuration in this benchmark, with 65% gain in multimedia and web browsing testing and 47% gain in office and text testing, compared to the standard medium quality (MQ), and without noticeable compression artefacts and pixelisation. The use of selective H.264 encoding (LQ1 to LQ4) is slightly more efficient for web and multimedia activities, but will give less gain in office and text editing activities, and will add noticeable compression artefacts. For office and text editing, the “Compatibility mode” in LQ5, which use a traditional JPEG compression, is more stable (less artefacts) and more efficient for compression in this scenario. The 8-bit mode is interesting for office and text bandwidth compression but offers poor performances with web browsing and multimedia, and will substantially degrade the user experience in this mode.

WAN optimization user policy settings

The settings used in the policy are detailed below:

Desktop UI



Visual Display

Multimedia (redirection)

Low Bandwidth Policy Diagram

Jul 292019

Update: Added cli functionality.
Update: Added 2nd pass of defrag to fix the profile ballooning issue that sometimes occurs.
Update: Added ability to target profiles over “X” size for compacting
Update 3/31/2020: Fixed a bug that didn’t allow the new tool to run as a scheduled task. Fixed in version 2003.1
Update 4/21/2020: Fixed bug that didn’t assign drive letters to vhd(x) files when running via CLI. Which breaks the defrag, and in turn doesn’t free up any space for diskpart to shrink. Fixed version is 2004.1.
Update 4/23/2020: Added the ability to sort profiles in the GUI. Clicking the stop button should dismount vhd(x) files automatically. Uses optimize-volume instead of defrag – should be MUCH faster. Also does not need drive letters anymore. Version 2004.2
Update 4/27/2020: Tool now detects RW disks and will not attempt to compact multi session profile disks if in use. Version 2004.4
Update 4/29/2020: Tool will find hidden .vhd(x) files. Version 2004.5
Update 5/26/2020: Fixed the optimize-volumes to use “retrim” after defraging the volume. This will increase processing time, but shrink the vhd(x) files much more. Version 2005.1

Update 6/24/2020: Added defrag back – which seems to do a lot better at freeing up space. Instead of giving a drive letter it sets the drive up as a mount point in the TEMP directory of the user running it (random named folder that will start with “_FSL”). With this I have updated the command line so you can process more than one vhd(x) at a time. TAKE NOTE OF THE NEW COMMAND LINE OPTIONS AS THEY HAVE CHANGED! Version 2006.1
UPDATE 6/25/2020: Bug fix – the 2006.1 version would leave the last vhd(x) attached when using the -tasks # switch. No, popups in cli to stop processing if it doesn’t find any vhd(x), and instead of “N/A” it will show the file size if the file is locked in the after column. Fixed in version 2006.3.
Edit: Version 2006.4 now – last bug fix for the day hopefully. Forgot to add the check for RW.VHD(X) files.

Do not use this tool if you are doing any differencing disks!
Diff disks, no problem!

This post is an updated version of my original profile compacting script ( I wrote it using Powershell Studio and converted it into an executable. This version does not require the Hyper-V powershell module as it diskpart to perform the shrink function.


  1. Administrative rights on the machine running the tool, and read/write to the profiles.
  2. .Net 4.5
  3. Recommend not running from a machine which has any .vhd(x) attached

Instructions/How it works:

  1. The program will remember the last directory selected (via an .ini file – if it exists), or you can click the “…” button at the top left to browse to the root directory of your profile share.
  2. Once a directory is selected it will list all .vhd and .vhdx files along with their current size and their current locked status in descending order by size. (this can take a little while depending on how many vhd(x) files are present – be patient)
  3. Select the profile(s) you wish to compact (you can select multiple using ctrl and shift+click)
  4. Click the compact button, and the program will process each profile selected one at a time
    1. Checks one more time to make sure the file is not locked
      1. If it is, it will skip on to the next one
    2. Gets the current size again before processing
    3. Attaches the vhd(x) in R/W mode
    4. Creates a random named folder in the user’s temp directory starting with “_FSL”
    5. Mounts the vhd(x) to that folder
    6. defrags the volume
    7. Detaches and re-attaches as read only
    8. Uses diskpart to compact the vhd(x)
    9. Gets the size of the file post processing
    10. Updates the results pane
  5. After it has run through all the selected profiles it will display the total reduction in MB at the bottom.
  6. Update: To run via CLI simply run from command prompt with the following options
    -path \\servername\share (path to the root vhd(x) share)
    -size 4096 (minimum size to touch in MB – will skip any vhd(x) smaller)
    -tasks # (number of concurrent vhd(x) files to compact – there is no limit, so be careful not to overload the machine you’re running this on)

    Run against all vhd(x) files one at a time
    ShrinkFSL.exe -path \\servername\share\

    Run against all vhd(x) files 2 at a time
    ShrinkFSL.exe -path \\servername\share -tasks 2

    Run against all vhd(x) files over 5GB
    ShrinkFSL.exe -path \\servername\share -size 5120

    Run against all vhd(x) files over 5GB AND process 2 at a time
    ShrinkFSL.exe -path \\servername\share -size 5120 -tasks 2
    1. A log file in csv format will be generated in the same directory that ShrinkFSL is run from. Shrink_MMddyyy_HHmmss.log
    2. If you stop the process make sure you disconnect any vhd(x) file that may be lingering, and delete _FSL folders in the temp directory!

You can keep track of the .vhd(x) attaching/detaching via diskmgmt.msc if you want. If for some reason the program hangs up you can click the stop button. It will detect if there is a vhd(x) attached, and detach it.

Always test new tools in Development/UAT environments prior to running in production! If you have any questions/comments please post here, and I will respond as soon as I can.

Here is a link to the tool (Updated 6/25/2020)

Oct 022018

According to this article, they say ” SAML with Microsoft Azure is only supported if you are using AD FS”. We are not using ADFS in our environment. We are simply using Azure AD Connect to do Password Synchronization into Azure AD from our on-premises Active Directory Domain Services. I figured out a way to make this work without using ADFS.

Log into your Azure instance, click on “Azure Active Directory” and select “Enterprise Applications”. Click “New Application” and select “Non-gallery application”

Call it something and hit “Add”

While this is configuring, log into your ConnectWise Manage server and go to the URL (https://{site}/v4_6_release/auth/{companyId}/metadata) This will download a metadata file. Save it somewhere.

Back in the Azure portal, your Enterprise Application should now be up. Click on “Users and Groups” and add a group that you would like and hit “Select”, then “Assign”. I am going to select a group with all of our Active Directory users her. (Remember: Our environment is setup using Azure AD Connect with password sync)

Next, click on “Single sign-on” and select “SAML”

I’m using the “New Experience” here. You can switch to and from it with the following button at the top.

Click edit on “Basic SAML Configuration”. Then click “Upload metadata file” at the top and upload the metadata file you downloaded above. It will add the top two lines. I have added the “Sign on URL” manually by just adding the base URL. After you are done with all of this, click “Save”

Next, download the Base64 cert (Under “SAML Signing Certificate”) and save it somewhere.

Under #4, copy both the “Login URL” and the “Azure AD Identifier” into notepad somewhere.

Next, select the “old experience” using the button at the top.  Set “User Identifier” to “user.employeeid” and click “Save” at the top.

You can switch back to the “New Experience” now. You should see your change here:

Log into Manage and go to “System” and “Setup Tables” then “SSO Configuration”. Click “+” to add a new one.

Enter a description and put in “SSO Type” of “SAML” (You may want to set this to inactive while you are screwing with it). Select the location in the top right.

Enter “Login URL” in the “Login URL” field

Enter “Azure AD Identifier” in the “Identity Provider ID” Field

Upload the Base64 certificate from above.

Click “Save”

When you are ready to test it, uncheck the “Inactive” button, and save the configuration.   The login will look like this now:

One last tidbit.  If somehow you DO lock yourself out of your environment, you can change your SSO configuration directly in the database. Just find dbo.SSO_Configuration, and set your “Inactive_Flag” to True.  Not that I did that or anything.  🙂 🙂

Sep 272017

Tick tock, tick tock. June 30th, 2018 is fast approaching and will be here before we know it. If you are anything like me, you still have plenty of old 2008R2 XenApp 6.5 farms lying around. I’m sure you have seen all the articles like this, this, this, and this. These are great resources on how to migrate your XenApp 6.5 farm information into a 7.x site collection. However, everything I have read is missing a critical piece of information that I needed in my environment. How do I get my existing session hosts migrated into this 7.x site collection? I have seen this Citrix article that states the basic premise, however most things I have read/heard state that you should always install a clean VDA and reinstall your applications.  For my environment, this just is not feasible.  I have hundreds of applications across dozens of customers and Active Directory forests. Many of these applications were difficult to install on XenApp in the first place. Some of them required software vendor coordination to install. There is the issue of license key transfer, etc. etc. Too many issues arise for this to work in any sane amount of hours. For my needs, I needed to figure out a consistent way to move my workers from 6.5 to 7.x. I needed to upgrade my hosts, plain and simple. If you have ever tried to uninstall XenApp 6.5, it does not do a very good job, sadly.  It leaves a lot of remnants that the 7.x installation detects and then fails to install the VDA.  A LOT.

I developed a process that does the following:

  • Uninstalls XenApp 6.5 (For real)
  • Upgrades 2008R2 to 2012R2
  • Installs the VDA

I will be sharing with you the uninstallation of XenApp 6.5.  I spend countless hours (less than my estimate of fresh install, exponentially, of course) on this process figuring out what pieces 7.x detects and going back to the uninstallation to add the removal of that piece to the script.  A lot of the things I found needed to be uninstalled in a specific order, or other pieces would fail.

The first part of this script uninstalls all 7 Rollup Packs, in reverse order.

start-process -ea 0 -Filepath "msiexec" -Argumentlist "/uninstall {D23001A2-7FF8-EAFD-7E32-58B3A003F5B5} /package {1471A89F-8CAB-4C46-89AB-942432D1DD3D} /passive REBOOT=ReallySuppress" -wait
start-process -ea 0 -Filepath "msiexec" -Argumentlist "/uninstall {6534B232-8426-2242-316E-D9B1F5A46E1A} /package {1471A89F-8CAB-4C46-89AB-942432D1DD3D} /passive REBOOT=ReallySuppress" -wait
start-process -ea 0 -Filepath "msiexec" -Argumentlist "/uninstall {ED7485F0-8579-F605-3326-9D058656F2B0} /package {1471A89F-8CAB-4C46-89AB-942432D1DD3D} /passive REBOOT=ReallySuppress" -wait
start-process -ea 0 -Filepath "msiexec" -Argumentlist "/uninstall {D511345D-32F8-8940-8B55-398DBDE50F66} /package {1471A89F-8CAB-4C46-89AB-942432D1DD3D} /passive REBOOT=ReallySuppress" -wait
start-process -ea 0 -Filepath "msiexec" -Argumentlist "/uninstall {38D5B4B1-08DD-E8BA-3D9C-AEE979D52A7C} /package {1471A89F-8CAB-4C46-89AB-942432D1DD3D} /passive REBOOT=ReallySuppress" -wait
start-process -ea 0 -Filepath "msiexec" -Argumentlist "/uninstall {B1CF9796-DC5D-2498-CA8D-E03BF20DDD70} /package {1471A89F-8CAB-4C46-89AB-942432D1DD3D} /passive REBOOT=ReallySuppress" -wait
start-process -ea 0 -Filepath "msiexec" -Argumentlist "/uninstall {B4A6E274-BC1D-D17F-17AE-B7BB94FE8493} /package {1471A89F-8CAB-4C46-89AB-942432D1DD3D} /passive REBOOT=ReallySuppress" -wait
start-process -ea 0 -Filepath "msiexec" -Argumentlist "/uninstall {343BE097-0B21-F62C-9D0A-886C9D142DBF} /package {1471A89F-8CAB-4C46-89AB-942432D1DD3D} /passive REBOOT=ReallySuppress" -wait

The next part of the script does the uninstallation of on XenApp 6.5.

start-process -ea 0 -Filepath "msiexec" -Argumentlist "/x {1471A89F-8CAB-4C46-89AB-942432D1DD3D} /L*v c:\output.log CTX_MF_FORCE_SUBSYSTEM_UNINSTALL=Yes /passive REBOOT=ReallySuppress" -wait

The next part of the script does uninstallation of all of the crap that is left after this uninstall.

start-process -ea 0 -Filepath "msiexec" -Argumentlist "/x {68376322-B36A-47CE-A637-37943D56476A} /passive REBOOT=ReallySuppress" -wait
start-process -ea 0 -Filepath "msiexec" -Argumentlist "/x {C4567AFA-6577-46C6-9153-457509317506} /passive REBOOT=ReallySuppress" -wait
blah blah blah A ton more uninstallation crap here

During testing I ran through this uninstallation at least 50 times. I took a snapshot of the XenApp 6.5 system, tested the uninstall, reverted to the snapshot and tested again. The insane thing is that I would get different results, and different failures, randomly throughout my testing. What is the definition of insanity? “Doing the same thing over and over again expecting different results” Well, I guess I’m officially insane. Due to this, I added 2 more XenApp 6.5 servers to my testing in order to see what other failures this process may uncover. This was a smart idea, because I found many more things that needed to be scripted in an attempt to catch them all. So many orphaned services, registry keys and files left, randomly after each uninstall. Frustrating! Most were only found until after the 2012R2 upgrade and trying to install the VDA and digging into the logs for specific failures. VERY frustrating! I was tempted to hit the bottle many times at work during this process.

This next part was annoying and odd, and may not be necessary in your environment. I had a bitch of a time getting some of the C++ redistributables uninstalled. These are a critical component of XenApp 6.5 AND 7.x. If these are not removed cleanly, the VDA installation process fails miserably. I was not able to uninstall mine as they kept pointing to the original installation directory that did not exist anymore. I ended up downloading the installation files to a directory on the C: and changing the registry to point the installation to that location. Sigh.

This portion uses the PowerShell module Expand-ZIPFile to extract the installation files to the C:. I have attached everything at the end of the article. You can use whatever method you would like to extract the files. Please note the .reg file sets the install (uninstall) directory to C:\.

Expand-ZIPFile –File "C:\" –Destination "C:\"
REG IMPORT C:\fixme.reg

After these files are in place, I am able to successfully uninstall these C++ components.

start-process -ea 0 -Filepath "msiexec" -Argumentlist "/x {1D8E6291-B0D5-35EC-8441-6616F567A0F7} /passive REBOOT=ReallySuppress" -wait
start-process -ea 0 -Filepath "msiexec" -Argumentlist "/x {F0C3E5D1-1ADE-321E-8167-68EF0DE699A5} /passive REBOOT=ReallySuppress" -wait
start-process -ea 0 -Filepath "msiexec" -Argumentlist "/x {743C9F75-F327-4D1C-9016-6C573930ADC1} /passive REBOOT=ReallySuppress" -wait

After this portion. Reboot. Finally. This process takes a good half hour, at least, depending on your hardware.

Lastly, there is a cleanup script that removes all the orphaned services, registry keys, and files that I found to be left during multiple uninstall attempts. It also removed the Remote Desktop Services role.

$Ctxmemop = Get-WmiObject -Class Win32_Service -Filter "Name='Citrix 64-bit Virtual Memory Optimization'"
$CtxAudioSvc = Get-WmiObject -Class Win32_Service -Filter "Name='CtxAudioSvc'"
Blah blah remove more crap here
Remove-Item "C:\Program Files (x86)\Citrix" -recurse -force
Remove-Item "C:\Program Files (x86)\Common Files\Citrix" -recurse -force
Blah blah delete more crap here
Import-Module ServerManager
Remove-WindowsFeature Remote-Desktop-Services

Reboot. This part of the script doesn’t take long at all. This should now give you a clean slate (tabula rasa) in which you can upgrade and install the VDA.

The rest of the process is pretty self-explanatory. You do an in-place upgrade of 2008R2 to 2012R2. Then install the VDA. There is a lot more to it, and I can post a write-up if comments demand it.

I have attached the scripts/files to github. Thanks to braynyac (Tim Riegler) for posting them for me.

I hope this has been helpful to some of you. This was very time consuming and I hope I have saved some of you a ton of time who are in the same situation as we are in our XenApp 6.5 environment.

Have fun!

Link to all github with all files.

Aug 252017

(See the new tool Here)

I recently switched from Citrix Profile Management to FSLogix! For those of you who do not know how it works… it mounts a virtual hard drive at the C:\Users\%UserName% folder for each user who connects. A huge advantage to this is that it is not copying the profile in at logon (or out at logoff), which greatly reduces logon times. Depending on how you have things setup you can literally (not figuratively) expect logon times of around 15 seconds reported in director no matter how your users decide to bloat their profiles.

There is one “problem” with dynamic vhd/vhdx profiles… they don’t shrink on their own. For instance, if you were to copy a 4GB file into a dynamic vhd file you would obviously see it grow by about that much. If you delete that 4GB file the vhd stays the same size! This isn’t really that big of a deal to me, but it might be to my storage administrator.

I wrote a script to compact the vhd profiles not in use.

Windows 10 – Powershell v5
Hyper-V module (Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All) – reboot required
Powershell run as Administrator

What this script does:

  1. Checks to make sure the above requirements are met
  2. Loads functions and variables (you will have to edit some of them for your environment – see the script for more info)
  3. Gets a list of all vhd/vhdx files in the root of your profile share
  4. Runs a for each loop
    1. Tests to see if the vhd file is currently locked (in use)
      1. If yes it will display a message on your screen saying it is locked and that it is being skipped (in the report the Success column will be marked with locked)
      2. If no then it will move on
    2. Tries to mount the vhd in read only mode
      1. If it fails it will send you an alert email and end the script as something is not right
      2. If it mounts then the script moves on
    3. Tries to optimize the vhd file (compact)
      1. Gets the original size in MB, size after compact in MB, computes the total reduction in MB, and notes failure/success
    4. Tries to dismount the vhd
      1. If it fails it will send you an alert email and end the script
  5. Once finished it will email you a report like the one below (names, paths, and sids are masked obviously)

Here is the script

Sep 302016


XenApp 7.6

700+ Delivered (published) Applications

60+ Windows servers (2008 R2 and 2012 R2)



Recently I had a request to replicate 100+ applications from PROD to QA, using QA server configured with identical applications and identical application locations/paths. Obviously all paths to EXE files need to be the same in order for this to work 100% (unless I missed a memo and XA can now support publishing of identical applications from various paths.  As far as I know, this was not yet available in 7.6).  If QA server has some of the applications in different paths, not all is lost. You can still use this process and script to migrate large number of applications between delivery groups and then modify paths later in Studio.

While I could add few more lines to my PoSH script to actually replicate each application at a time, amount of time it took me to create this script and ability to duplicate applications in Studio seemed unnecessary.

My goal was to replicate, or proper Citrix term would be duplicate all applications and then assign them to another delivery group. Seems simple enough for Citrix and PoSH guru. But for those who are just getting their feet wet could use following process to speed up their delivery time to less than 5 mins and go look for the end of the Internet, while telling client it took you hours 😉



1 – I will be duplicating all requested applications using ol’ Citix Studio.

2 – I will run script below to change Delivery Group and application folder, as visible by the user (you mileage might vary, depending on your requirements)

This script/process is no rocket science, but might help someone to quickly replicate applications and migrate them to another delivery group, instead of publishing them over again.  Modify script below according to your environment before running it.  (WARNING: It is fairly simple script, so review and try to understand exactly what this script is doing, before executing it.)  Also, I am no expert when it comes to creating powershell scripts, but just another Citrix admin.  So, pardon if you can make it better.  Please do improve and share!  I am all for helping fellow Citrix admins anyway I can.  Even if it’s buying a pint!


Step 1

citrixirc1Create alternative application folder in Studio.  For our scenario I am going to create folder named “QA” inside already created “Europe” folder.

Right-click on all applications that you need to replicate in QA (you can select multiple applications at once).

Click Duplicate Application 

Now select all duplicates and drag them over to QA folder.  In my scenario I will be dragging these to Europe\QA.

Step 2

Below script will prompt for the admin folder name where all the duplicates reside (that’s the new folder you just created.  In my example it’s called Europe\QA).  I repeat- do not select your production applications folder, as script will move all your production apps to new delivery group.  Use newly created QA folder where you moved all duplicate applications to in step 1 above.

It is assumed that new delivery group is already created.

Another item to note; there is an optional line (in yellow) to change client-side folder location of newly created applications.  This is to help users identify whether they are running PROD or QA applications. It also looks cleaner in Storefront or WI.  You can add more commands into Foreach loop.  Things like modifying users who have access, or changing actual name of the application and etc.  My goal was to keep all the same and just deliver from QA server.


asnp Citrix*

$adminfolder = (Get-BrokerApplication -MaxRecordCount 10000).AdminFolderName | sort | select -unique | Out-GridView -Title "Select Admin Folder Name" -OutputMode Single
$applist = Get-Brokerapplication -AdminFolderName $adminfolder
$originalDG = (Get-BrokerDesktopGroup -MaxRecordCount 10000).Name | sort | Out-GridView -Title "Select Original Delivery Group Name" -OutputMode Single
$newDG = (Get-BrokerDesktopGroup -MaxRecordCount 10000).Name | sort | Out-GridView -Title "Select New Delivery Group Name" -OutputMode Single

Write-Host "Migrating all applications in $adminfolder`nFrom $originalDG Delivery Group to $newDG Delivery Group" -ForegroundColor Green

foreach ($app in $applist.ApplicationName){
                Write-host "Migrating $app"
                Get-BrokerApplication -ApplicationName $app | Add-BrokerApplication -DesktopGroup $newDG
                Get-BrokerApplication -ApplicationName $app | Remove-BrokerApplication -DesktopGroup $originalDG
                Get-BrokerApplication -ApplicationName $app | Set-BrokerApplication -ClientFolder "Europe\QA" #optional to show all applications inside QA folder and not in the same folder with production apps


BTW, using similar add-brokerapplication command you can publish, or rather deliver same application from multiple delivery groups.  Just comment out remove-brokerapplication command and it will now launch from servers in prod and qa, or any other DG of your choice.  Comes really handy when you have multiple DGs that host different applications, but some of the applications are identical.  You can spread the load across multiple DGs.  Think of it as a worker groups concept in XA 6.x with server groups.   I had such requirement that was easily achievable in XA 6.x, but not so much in XA 7.x.  I paid for someone’s case of beer when they told me that I can use above mentioned command to deliver same application from multiple DG’s, as it’s not clearly documented by Citrix. There is a surprise…

That’s all folks. My first ever citrixirc blog.  Whoo-hoo!

Over and out.

Feb 242016

Have you ever looked at director and saw a user had a very long login, and wondered how the hell you could find out who that was?  I wrote a script to help you out a bit!

Here is the script

Read it!  There are places you will have to edit to allow it to run in your environment.  Search for ##### to find the spots to pay attention to.

In the end it will output a .htm file to your my documents\logon_logs and open after it finishes.


Note: I have no idea if this works for XA, but I know it works for XD 7.6

Aug 062014

Post credit goes to David62277, a community contributor from #Citrix IRC on Freenode In order to update certain software on a PVS image (hosting platform tools, pvs target device software, etc) it is required to “reverse image” your vdisk back to a normal VM, install your update, and image back to vdisk. This is because the machine is actually booted to network (it is getting its C: drive from a network share essentially), and if you disrupt that connection while the vdisk is in private mode it can (most likely will) ruin your vdisk image. The process of reverse imaging, and re-imaging your vdisk can be very time consuming. There is a better way… update your vDisk without having to reverse image by directly booting to a .VHD from Windows PE.

You will need the Microsoft Windows AIK (I’m using Windows 7 version)


  1. Download and install the Microsoft Windows AIK and install it on your workstation
    1. This is what we will use to create a bootable .iso image
  2. Once installed create your .iso
    1. Start => All Programs => Microsoft Windows AIK => Deployment Tools Command Prompt1-BootVHDwithPE
    2. Run “copype.cmd amd64 c:\winpe” (note: you can use x86 or ia64 depending on your architecture… don’t think it matters though. Also, you can specify a different directory).2-BootVHDwithPE.png
    3. Now we want to add boot support
      1. Imagex /apply c:\winpe\winpe.wim 1 c:\winpe\mount
      2. Copy c:\winpe\iso\bootmgr c:\winpe\mount
      3. Mkdir c:\winpe\mount\boot3-BootVHDwithPE.png
    4. Run the following commands:
      1. Bcdedit /createstore c:\winpe\mount\boot\BCD
      2. Bcdedit /store c:\winpe\mount\boot\BCD -create {bootmgr} /d “Boot Manager”
      3. Bcdedit /store c:\winpe\mount\boot\BCD -set {bootmgr} device boot
      4. Bcdedit /store c:\winpe\mount\boot\BCD -create /d “WINPE” -application osloader4-BootVHDwithPE
    5. Run the following commands using the guid you received from the last command
      1. Bcdedit /store c:\winpe\mount\boot\BCD -set <GUID> osdevice boot
      2. Bcdedit /store c:\winpe\mount\boot\BCD -set <GUID> device boot
      3. Bcdedit /store c:\winpe\mount\boot\BCD -set <GUID> path \windows\system32\winload.exe
      4. Bcdedit /store c:\winpe\mount\boot\BCD -set <GUID> systemroot \windows
      5. Bcdedit /store c:\winpe\mount\boot\BCD -set <GUID> winpe yes
      6. Bcdedit /store c:\winpe\mount\boot\BCD -set <GUID> detecthal yes
      7. Bcdedit /store c:\winpe\mount\boot\BCD -displayorder <GUID> -addlast5-BootVHDwithPE
    6. One last command
      1. Oscdimg -n -m -o -bc:\winpe\ c:\winpe\mount c:\winpe\bootdisk.iso6-BootVHDwithPE
    7. Done with the “hard” part
  3. Copy the .iso file to your ISO storage repository (xenserver, vmware, whatever)
  4. Create a new disk in your hypervisor that is about 2x as large as the size of your vdisk (note: use the size it shows in the PVS console x 2) – this gives you room to play.
  5. Attach that disk to your PVS server
    1. Create a partition, format, etc.
  6. Merge your vdisk to a new merged base (set it as test)7-BootVHDwithPE
  7. Copy the merged .vhd file to the new drive you just attached to the PVS server
  8. Detach the new drive from the pvs server, and attach it to the VM you normally use to update your image (should be the only drive attached), or a VM that matches the virtual hardware of your target devices.
    1. If the vm is a target device in PVS set it to boot from hard disk not vdisk
  9. If using Xenserver set the VM to boot from CD, if using vmware edit settings of the vm to boot into bios so you can change the boot order so CD is first.
  10. Boot the VM and you should see this screen8-BootVHDwithPE
  11. Run the following commands
    1. Diskpart
    2. List disk
      1. Should see disk 0 and only9-BootVHDwithPE
    3. Select disk 0
    4. Select part 1
    5. Active
      1. This makes partition 1 on disk 0 bootable10-BootVHDwithPE
    6. exit
    7. Now I want to rename the .vhd file on disk 0 (C:\), so I can use it over and over again (NOTE: this is CASE SENSITIVE)
    8. C:
    9. Dir
      1. Just so I can see the file name
    10. Ren win8.8.vhd temp.vhd (or whatever you want to name it. NOTE: this is CASE SENSITIVE)11-BootVHDwithPE
    11. X:
    12. Diskpart
    13. Select vdisk file=c:\temp.vhd
    14. Attach vdisk
    15. List vol
  12. Now I can see my vhd is mounted as volume D (yours may be different, but make note of it)
  13. A couple more commands
    1. Exit (to exit diskpart)
    2. Bcdboot d:\windows /s c:
      1. Use whatever volume letter you have for your vdisk13-BootVHDwithPE
    3. Exit
      1. System should now reboot and boot into your vhd (just remember not to hit any key, or just eject the cd image from the vm)
  14. Make the changes that normally would require you to reverse image, and shut down.
  15. Detach the drive from the editing VM and re-attach it to your PVS server.
  16. Copy the .vhd back to the store
  17. Detach the drive (keep it around for next time)
  18. Rename the original vhd (win8.8.vhd for me) to .old, and rename the temp.vhd to whatever the original name was. (NOTE: this is CASE SENSITIVE)
  19. Boot your test devices and make sure everything is working
  20. Once satisfied, shutdown the test devices, delete the .old file, and promote the vdisk to production
  21. Switch the editing VM back to booting from network for when you have your normal updates

From here on out these kinds of edits should be easy.

  1. Attach the virtual disk to pvs
  2. Remove the old temp.vhd file (assuming you didn’t before)
  3. Copy the vhd you wish to edit to it
  4. Rename it to temp.vhd (or whatever you named it to begin with)
  5. Detach the drive from PVS
  6. Change your editing vm target device in PVS to boot to hard drive
  7. Attach the drive to your editing vm
  8. Boot it
  9. Follow steps 14-20 above