Web Interface

Citrix Storefront – Performance and Tuning – Part 2 – PNA Traffic simulation

2017-05-30
/ /
in Blog
/

In part 1 I created a script to simulate users going through their web browser, logging in to Storefront, and launching an application.

In this post I’m going to simulate “PNA traffic”.  “PNA” is the icons delivered to your desktop or start menu via Citrix Receiver.

When connecting to Storefront or Web Interface the following can occur:

  1. This is your first connection and you need to download/cache the icons from the server
  2. This is a subsequent connection and you only need to validate you have all the icons
  3. You connect and PNA discovers you are missing an icon or have a new application assigned and proceeds to download any missing/different icons

All connections from PNA to Storefront/Web Interface start with “config.xml” .  From there, it queries for icons and downloads them.  This is what each of the 3 scenarios described look like:

 

The first time you connect via PNA

 

Subsequent connections after icons have been cached.

 

2 new applications published to the user

 

The first connection “config.xml” returns an xml file detailing the properties of the store.  Show icons on desktop/start menu? What are the URL’s for resource enumeration, reconnection, change password, etc.?  What logon methods are available?

All these questions and more are answered by the config.xml.

The second connection “enum.aspx” with a body size of 175 bytes is a POST request for the PRELAUNCH stage of PNA.  Are there any applications configured for PRELAUNCH?  POST request looks like this:

If you don’t have any applications configured for PRELAUNCH you receive a response like this:

The next enum.aspx request is a POST request that asks for all the icons:

And the response is a rather large one (1,758,490 bytes in my example) with application properties and details.  Part of the reason it’s so large is the icon data is stored as ASCII.  Here’s a small snippet of just 2 applications:

The subsequent POST request for icons (most roughly ~21,000 bytes in size) look like this:

With the response being:

Lastly, application launches over PNA are a POST request that look like this:

The content of that POST request looks like this:

And the response is a ICA file that Receiver executes.


With each of these requests we can see that PNA sends your username/password/domain to the server to get the relevant information.  This means we can script these requests using WCAT as the data being POST’ed is actually static.

Using the wcat scenario creator, download the WCATScenarioGenerator.dll and save it to: “C:\Program Files (x86)\Fiddler2\Scripts”

 

Open Fiddler.  Capture PNA operation by closing Citrix Receiver and reopening it.  Logon (if necessary) and launch an application.  If you want a more intensive logon, ensure your icon cache is cleared so that it forces new icons to be downloaded.  This will be the ‘scenario’ that we will be executing against.  Clean up any requests that don’t go to your web interface/storefront.  My Fiddler looks like this:

Select your items and in the black bar enter “wcat addtrans” and hit enter.

In the same bar enter “wcat save” and hit enter.

 

This will create a file called “fiddler.wcat” in your “C:\Program Files (x86)\Fiddler2” folder.

This file will actually require some cleanup as the WCAT scenario generator captures things literally and the scenario file requires escaping of double-quotes.

So in the wcat file, lines like this:

 

Need to be modified to look like this:

 

To execute our script, install wcat and launch the controller via the command line like so:

What each of these settings means:

-t = scenario file to use
-f = settings file to use (just using default)
-s = server to target
-p = port to connect
-c = clients that need to connect (this is the number of wcclient.exe’s that will connect to the controller)
-v = number of virtual clients that will connect
-w = warmup time (clients and virtual clients will connect in the amount they have / warmup time)
-u = duration for full load (all clients should be connected)
-n = cooldown, clients start disconnecting (opposite of warmup)

For my example, if I use my parameters for the controller then I need to start 10 clients be executing:

(Win7.bottheory.local is running the controller).

This command can be executed 10 times on the same box, even the same one as the controller, or on some random combination of 1-10 different boxes as long as you match the number of “clients” to the controller “client” excepted number of connections.


Lastly, here is a powershell script to measure the performance of each action of the PNA request.  You will need to modify it for your domain/(webinterface/storefront URL)/username/password.  This script will measure the amount of time each stage takes and the total, overall time and saves it as a CSV.

Here’s an example of the CSV output:

Some example commands:

Examples of “stress component” output:

And the script:

 

 

Read More

Citrix Storefront – Adventures in customization – Dynamically configure workspace control based on group membership

2017-05-07
/ /
in Blog
/

I’ve been exploring the customization capabilities of Citrix Storefront and have some exciting ideas on simplifying our deployment.  What I’d really like is to reduce our store count down to a as few stores as possible.  In our Web Interface we have multiple stores based on the non-configurable settings.  They are:

  • Workspace Control Enabled with Explicit Logon
  • Workspace Control Disabled with Explicit Logon
  • Workspace Control Enabled with Domain Passthrough authentication
  • Workspace Control Disabled with Domain Passthrough authentication
  • Anonymous site

We can’t mix and match authenticated sites and anonymous sites (right?… ?) but Citrix does offer the ability to configure Authentication methods AND Workspace Control options via their ‘Receiver Extension API’s’.

These are the API’s in question:

There isn’t really a whole lot of documentation on them and how to use them.  Richard Hayton has created the Citrix Customization Cookbook which details some examples of some of the API’s.  He has several blog articles on the Citrix website that have varying degrees of applicability.  Unfortunately, he hasn’t blogged in over a year on this topic as it feels like the situation has changed a bit with the Citrix Store API’s available as well (note: these are different!).

My target is to make it so these options can be set dynamically based on the users group membership.  If you’re a member of the group ‘workspaceControlEnabled’ you get all the settings set to true, if you’re a member of ‘workspaceControlDisabled’ you get all the settings set to false.

Seems like a pretty straightforward goal?

So I thought I’d start with something pretty simple.  I have a store with Workspace Control Enabled, with show ‘Connect and Disconnect’ buttons selected:

If I log into the site:

I see everything (as I should).

So let’s start with a simple customization.  Let’s try using the API to disable these options.  I created a totally blank script.js file and added the following lines:

Now what does our menu look like?

Awesome!  Workspace Control was disabled by script!

So I said I want to disable Workspace Control if you are a member of a specific group.  Richard Hayton actually wrote a pretty good article on creating a service to facilitate grabbing your group membership with Storefront.  Unfortunately, the download link is dead.  So I wrote another PowerShell HTTP listener that takes an input and queries AD for that user and their membership, and returns a positive value if workspace control should be enabled, or a negative value if it should be disabled.  To get it to query though, it needs a value.  The best value for this, I thought, would be the user name.

Citrix provides a function to get the username and I can then pass it to my webservice, test for group membership and return whether Workspace Control (WSC) should be enabled or disabled.

I wrote my first bit of code and it crashed immediately.  I simply entered it straight into my script.js.

In order to trace the error, you simply enter “#-tr” to the end of your store URL:

and allow pop-ups.  A new tab will open allowing you to follow the ‘flow’ of Storefront as it executes its commands.  Mine crashed at:

“get username data:”

And it makes sense why it crashed there.  I haven’t even logged in yet so it has no idea who or how to get the username so it looks like Storefront just returns the login page.  We need to call our functions after logging in.

Citrix provides the following event-based functions we can hook into:

Notifications of progress

preInitialize(callback)
postInitialize(callback)
postConfigurationLoaded()
postAppListLoaded()

Note that during these calls, the UI may be hidden in native Receivers, so it is not safe to show UI
For APIs passing a callback, you MUST call the callback function, though you may delay calling it until code of your own has run.

beforeLogon(callback)

Web browsers only. Called prior to displaying any logon dialogs. You may call ‘showMessage’ here, or add your own UI.

beforeDisplayHomeScreen(callback)

All clients, called prior to displaying the main UI. This is the ideal place to add custom startup UI.
Note that for native clients, the user may not have logged in at this stage, as some clients allow offline access to the UI.

afterDisplayHomeScreen()

All clients, called once the UI is loaded and displayed. The ideal place to call APIs to adjust the initial UI, for example to start in a different tab.

So the question becomes, when does each of these get called?  We are only interested in the ones after you login.  To determine this, I hooked into each one and just did a simple trace command and then refreshed my browser to the login screen.

This is where I stopped:

And trace tab results:

These 4 stages are called before the user logs on so they are of no use to me:

preInitialize
postInitialize
postConfigurationLoaded
beforeLogon

The order of the other 3 after logon:

beforeDisplayHomeScreen
postAppListLoaded
afterDisplayHomeScreenStage

Before adding my code to the post-logon event functions I just added it back -plain jane- and rerun with a trace:

What I found is these extensions appear to have a fixed entry order point.  The workspace control extensions cannot be called after “beforeDisplayHomeScreen” stage.  If you do not call the workspace control extensions before the callback on the ‘beforeDisplayHomeScreen’ function you will be unable to control the setting.  The trace log in my screenshot for these extensions will always occur at this point in time regardless if you actually set it in ‘preInitialize, postInitialize, postConfigurationLoaded, or beforeLogon’.  And if you attempt to set it in either of the two later functions it will not log anything and your code has no effect.  So the only point in time where I can take the username and set these values are in the event function beforeDisplayHomeScreen.

<Digress>

During the course of my testing this feature I had thought about adding a button that would allow you to toggle this feature ‘enabled or disabled’ on your own whim.  But it appears once you call the Extension it’s a one and done.  I also discovered that it appears you must set the workspace control feature early in the process.  If I set it in postAppListLoaded or afterDisplayHomeScreen nothing happened.  To be fair, I do not know how to reinitialize the menu, maybe that would allow it to kick in dynamically…?  I guess that’s for further exploration on another day…

</Digress>

Ok, so we’ve found the one and only functional place we can execute our code.  So I added it.

 

The result?  Nothing.  Nothing happened.

Well, that’s not entirely true.

I’ve highlighted in yellow/orange my “getUsername” function.  We can see on line 35 we get into the function.  And on line 67 it is successfully finding and returning my name.  But the problem is that it’s getting that information after the point in time that we can set the WSC features (highlighted in blue — line 60-62).

I found that using ajax for this command and attempting to use async was causing my failure.  I understand it’s bad practice to do synchronous commands, especially in javascript as they will lock the UI while executing, but, thus far it’s the only way I know to ensure it gets completed in the proper order.  I am really not a web developer so I don’t know what’s the proper technique here to send a couple ajax requests that only blocks at the specific point in time that WSC kicks in…  Or find a way to redraw the menu?  But for the purposes of getting this working, this is the solution I’ve chosen to go with.  I’m wide open to better suggestions.  The real big extension that would be an issue is the ‘webReconnectAtStartup’.  This feature will reconnect any existing sessions you have and the way that Citrix currently implements it, they want it run as soon as the UI is displayed.  This makes some sense as that’s the whole point.  You don’t want to wait around after logging in some indeterminate or random amount of seconds for your session to reconnect…  But, this issue can be alleviated.  Citrix actually offers a way to implement this feature yourself via the Store API so we could implement our own custom version of this function that would get all your sessions and reconnect them…

Which could just leave building the menu as something that could be moved back to async if I can figure out how to rebuild it or build it dynamically…

Anyway, that maybe for another day.  For today, the following works for my purpose.

This is my custom/script.js file that I finished from this blog post:

 

Here is the LDAP_HttpListener.psm1

Lastly, the scheduled task to call the listener:

 

 

 

 

Read More

Citrix Storefront – Pass URI parameters to an application

2017-05-01
/ /
in Blog
/

In my previous post, I was exploring taking URI parameters and passing them to an application.

The main issue we are facing is that Storefront launches the ica file via an iframe src.  When launching the ica via this method the iframe does a simple ‘GET’ without passing any HEADER parameters — which is the only (documented) way to pass data to Storefront.

What can I do? I think what I need to do is create my own *custom* launchica command.  Because this will be against an unauthenticated store we should be able remove the authentication portions AND any unique identifiers (eg, csrf data).  Really, we just need the two options — the application to launch and the parameter to pass into it.  I am NOT a web developer, I do not know what would be the best solution to this problem, but here is something I came up with.

My first thought is this needs to be a URL that must be queried and that URL must return a specific content-type.  I know Powershell has lots of control over specifying things like this and I have some familiarity with Powershell so I’ve chosen that as my tool of choice to solve this problem.

In order to start I need to create or find something that will get data from a URL to powershell.  Fortunately, a brilliant person by the name of Steve Lee solved this first problem for me.

What he created is a Powershell module that creates a HTTP listener than waits for a request. We can take this listener and modify it so it listens for our two variables (CTX_Application and NFuseAppCommandLine) and then returns a ICA file.  Since this is an unauthenticated URL I had to remove the authentication feature of the script and I added a function to query the real Storefront services to generate the ICA file.

So what I’m envisioning is replacing the “LaunchIca” command with my custom one.

 

This is my modification of Steve’s script:

And the command to start the HTTP listener:

Eventually, this will need to be converted to a scheduled task or a service.  When running the listener manually, it looks like this:

 

I originally planned to use the ‘WebAPI’ and create a custom StoreFront, but I really, really want to use the new Storefront UI.  In addition, I do NOT want to have to copy a file around to each Storefront server to enable this feature.  So I started to wonder if it would be possible to modify Storefront via the extensible customization API’s it provides.  This involves adding javascript to the “C:\inetpub\wwwroot\Citrix\StoreWeb\custom\script.js” and modifying the “C:\inetpub\wwwroot\Citrix\StoreWeb\custom\style.css” files.  To start, my goal is to mimic our existing functionality and UI to an extent that makes sense.

The Web Interface 5.4 version of this web launcher looked like this:

When you browse to the URL in Web Interface 5.4 the application is automatically launched.  If it doesn’t launch, “click to connect” will launch it for you manually.  This is the function and features I want.

Storefront, without any modifications, looks like this with an authenticated store:

So, I need to make a few modifications.

  1. I need to hide all applications that are NOT my target application
  2. I need to add the additional messaging “If your application does not appear within a few seconds, click to connect.” with the underlined as a URL to our launcher.
  3. I want to minimize the interface by hiding the toolbar.  Since only one application will be displayed we do not need to see “All | Categories   Search All Apps”
  4. I want to hide the ‘All Apps’ text
  5. I want to hide “Details”, we’re going to keep this UI minimal.

The beauty of Storefront, in its current incarnation, is most of this is CSS modifications.  I made the following modifications to the CSS to get my UI minimalized:

This resulted in a UI that looked like this:

So now I want to remove all apps except my targeted application that should come in a query string.

I was curious if the ‘script.js’ would recognize the URI parameter passed to Storefront.  I modified my ‘script.js’ with the following:

Going to my URL and checking the ‘Console’ in Chrome revealed:

Yes, indeed, we are getting the URI parameters!

Great!  So can we filter our application list to only display the app in the URI?

Citrix offers a bunch of ‘extensions’.  Can one of them work for our purpose?  This one sounds interesting:

Can we do a simple check that if the application does not equal “CTX_Application” to exclude it?

The function looks like this:

Did it work?

Yes!  Perfectly!  Can we append a message to the application?  Looking at Citrix’s extensions this one looks promising:

Ok.  That warning sucks.  My whole post is based on StoreFront 3.9 so I cannot guarantee these modifications will work in future versions or previous versions.  Your Mileage May Vary.

So what elements could we manipulate to add our text?

Could we add another “p class=storeapp-name” (this is just text) for our messaging?  The onAppHTMLGeneration function says it is returned when the HTML is generated for an app, so what does this look like?

I added the following to script.js:

And this was the result in the Chrome Console:

So this is returning an DomHTMLElement.  DOMHTMLElements have numerous methods to add/create/append/modify data to them.  Perfect.  Doing some research (I’m not a web developer) I found that you can modify the content of an element by this style command:

This results in the following:

We have text!

Great.

My preference is to have the text match the application name’s format.  I also wanted to test if I could add a link to the text.  So I modified my css line:

The result?

Oh man.  This is looking good.  My ‘click to connect’ link isn’t working at this point, it just goes to google, but at least I know I can add a URL and have it work!  Now I just need to generate a URL and set that to replace ‘click to connect’.

When I made my HTTPListener I purposefully made it with the following:

The reason why I had it set to share the url of the Citrix Store is the launchurl generated by Storefront is:

The full path for the URL is actually:

So the request actually starts at the storename.  And if I want this to work with a URL re-write service like Netscaler I suspect I need to keep to relative paths.  So to reach my custom ica_launcher I can just put this in my script.js file:

and then I can replace my ‘click to connect’ link with:

The result?

The url on the “click to connect” goes to my launcher!  And it works!  Excellent!

Now I have one last thing I need to get working.  If I click the ‘Notepad 2016 – PLB’ icon I get the regular Storefront ica file, so I don’t get my LongCommandLine added into it.  Can I change where it’s trying to launch from?

Citrix appears to offer one extension that may allow this:

Huh.  Well.  That’s not much documentation at all.

Fortunately, a Citrix blog post came to rescue with some more information:

Hook APIs That Allow Delays / Cancellations

doLaunch
doSubscribe
doRemove
doInstall

On each of these the customization might show a dialog, perform some checks (etc) but ultimately should call ‘action’ if (and only if) they want the operation to proceed.

This extension is taking an object (app).  What properties does this object have?  I did a simple console.log and examined the object:

Well, look that that.  There is a property called ‘launchurl’.  Can we modify this property and have it point to our custom launcher?

I modified my function as such:

The result?

A modified launchurl!!!!

Excellent!

And launching it does return the ica file from my custom ica_launcher!

Lastly, I want to autolaunch my program.  It turns out, this is pretty simple.  Just add the following the script.js file:

Beautiful.  My full script.js file looks like so:

And that’s it.  We are able to accomplish this with a Powershell script, and two customization files.  I think this has a better chance of ‘working’ across Storefront versions then the SDK attempt I did earlier, or creating my own custom Storefront front end.

Read More

Citrix StoreFront – Experiences with Storefront Customization SDK and Web API

2017-04-24
/ /
in Blog
/

Our organization has been exploring upgrading our Citrix environment from 6.5 to 7.X.  The biggest road blocks we’ve been experiencing?  Various nuanced features in Citrix XenApp 6.5 don’t work or are not supported in 7.X.

This brings me to this post and an example of the difficulties we are facing, my exploration of solutions to this problem, and our potential solution.

In Citrix Web Interface 5.1+ you can create a URI with a set of application launch parameters and those parameters would be passed to the application.  This is detailed in this Citrix article here (CTX123998).  For us, these launches occur with a Site (WI5.4 terminology) or Store (Storefront terminology) that allows anonymous (or unauthenticated) users.

By following that guide and modifying your Web Interface you can change one of your sites so that it accepts launch parameters.  You simply enter a specific URI in your browser, and the application would launch with said parameters.  An example:

http://bottheory.local/Citrix/XenApp/site/launcher.aspx?CTX_Application=Citrix.MPS.App.XenApp.Notepad&LaunchId=1263894298505&NFuse_AppCommandLine=C:\Windows\WindowsUpdate.log

This allows you to send links around to other people and they can click to automatically launch an application with the parameters specified.  If you are really unlucky, your org might document this as an official way to launch a hosted application and this actually gets coded into certain applications.  So now you may have tens of local apps utilizing this as an acceptable method to launch a hosted application.  For an organization, this may be an acceptable way to launch certain hosted applications since around ~2008 so this “feature”, unfortunately, has built up quite a bit of inertia.

We can’t let this feature break when we move to StoreFront.  We track the number of launches from these hosted applications and it’s in the hundreds/thousands per day.  This is a critical and well used feature.

So how does this work in Web Interface and what actually happens?

URI substitution and launch process

The modifications that you apply add a new ‘query’ to the URI that is picked up.  This ‘query’ is “NFuse_AppCommandLine” and the value it is equal to (“C:\Windows\WindowsUpdate.log” in my example) is passed into the ICA file.

The ICA file, when launched, will pass the parameter to a special string “%**” the is set on the command line of the published application.  This token “%**” gets replaced by the parameter specified in the ICA which then generates the launch string.  This string is executed and the result is the program launches.

Can we do this with Storefront?  Well, first things first, is this even possible with XenApp/XenDesktop 7.X?  In order to test this I created an application and specified the special token.

I then generated an ICA file and manually modified the LongCommandLine to add my parameter.  I then launched it:

 

Did it work?

Yes, it worked.

Success!  So XenApp/XenDesktop 7.X will substitute the tokens with the LongCommandLine in the ICA file.  Excellent.  So now we just need Storefront to take the URI and add it to the LongCommandLine.  Storefront does not do this out of the box.

However, Citrix offers a couple of possible solutions to this problem (that I explored).

StoreFront WebAPI
StoreFront Store Customization SDK

What are these and how do they work?

StoreFront Web API

This API is billed as:

“Write a new Web UI or integrate StoreFront into your own Web portal”

We are going to need to either modify Storefront or write our own in order to take and parameters in the URI.  I decided to write our own.  Using the ApiExample.html in the WebAPI I added the following:

This looks into the URI and allows you to get the value of either query string.  In my example I am grabbing the values for “CTX_Application” and “NFuse_AppCommandLine”.

I then removed a bunch of the authentication portions from the ApiExample.html (I’ll be using an unauthenticated store).  In order to automatically select the specified application I added some javascript to check the resource list and get the launch URL:

There is a function within the ApiExample.html file that pulls the ICA file.  Could we take this and modify it before returning it with the LongCommandLine addition?  We have the NFuse_AppCommandLine now.

It turns out, you can. You can capture the ICA file as a variable and then using javascripts ‘.replace’ method you can modify the line so that it contains your string.  But how do you pass the ICA file to the system to launch?

This is how Citrix launches the ICA file in the ApiExample.html:

It generates a URL then sets it as the src in the iframe.  The actual result looks like this:

The ICA file is returned in this line:

When we capture the ICA file as a variable the only way that I’ve found you can reference it is via a blob.  What does the src path look like when do that?

Ok, this looks great!  I can create an ICA file than modify it all through WebAPI and return the ICA file to the browser for execution.  Does it work?

Yes and no. 🙁

It works in Chrome and Firefox, but IE doesn’t auto-launch.  It prompts to ‘save’ a file.  Why?  IE doesn’t support opening ‘non-standard’ blobs.  MS offers a method called “msSaveOrOpenBlob” which you can use instead, and this method then prompts for opening the blob.  This will work for opening the ICA file but now the end user requires an extra step.  So this won’t work.  It needs to be automatic like its supposed to be for a good experience.

So WebAPI appears to offer part of the solution.  We can capture the nFuse_AppCommandLine but we need to get it to LongCommandLine.

At this point I decided to look at the StoreFront Store Customization SDK.  It states it has this ability:

Post-Launch ICA file—use this to modify the generated ICA file. For example, use this to change ICA virtual channel parameters and prevent users from accessing their clipboard.

That sounds perfect!

StoreFront Store Customization SDK

The StoreFront store customization SDK bills one of its features as:

The Store Customization SDK allows you to apply custom logic to the process of displaying resources to users and to adjust launch parameters. For example, you can use the SDK to control which apps and desktops are displayed to users, to change ICA virtual channel parameters, or to modify access conditions through XenApp and XenDesktop policy selection.

I underlined the part that is important to me.  That’s what I want, exactly!  I want to adjust launch parameters.

To start, one of the tasks that I need is to take my nFuse_AppCommandLine and get it passed to the SDK.  The only way I’ve found to make this happen is to enable ‘forwardedHeaders‘ in your web.config file.

With this, you need to set your POST/GET Header on your request to Storefront to get this parameter passed to the SDK.  Here is how I setup my SDK:

Install the “Microsoft Visual Studio Community Edition” on a test StoreFront server.

 

Download the StoreCustomizationSDK and open the ‘Customization_Launch’ project file:

 

Right-click ‘Customization_Launch’ and select ‘Properties’.

 

Modify the Outpath in Build to the “%site%\bin” location.  This is NOT the %site%Web, but just the %site%.

Open the LaunchResultModifer.cs

 

Set a breakpoint somewhere in the file.

Build > Build ‘Customization_Launch’

Ensure the build was successful:

If you get an error message:

Just ignore it.  We’re compiling a library and not an executable and that’s why you get this message.

Now we connect to the debugger to the ‘Citrix Delivery Services Resources’.  Select ‘Attach to Process…’

Select the w3wp.exe process whose user name is ‘Citrix Delivery Services Resources’.  You may need to select ‘Show processes from all users’ and click ‘ Attach.

Click ‘Attach’.

Browse to your website and click to launch an icon:

Your debugger should pause at the breakpoint:

And you can inspect the values.

At this point I wasn’t interested in trying to re-write the ApiExample.html to get this testing underway, I instead used PowerShell to submit my POST’s and GET’s.  Remember, I’m using an unauthenticated store so I could cut down on the requests sent to StoreFront to get my apps.  I found a script from Ryan Butler and made some modifications to it.  I modified it to remove the parameters since I’m doing testing via hardcoding 🙂

Executing the powershell script and examining a custom variable with breakpoint shows us that our header was successfully passed into the file:

Awesome!  So can we do something with this?  Citrix has provided a function that does a find/replace of the value you want to modify.  To enable it, we need to add it the ICAFile.cs:

Browse to ICAFile.cs

 

At this point we can use the helper methods within the IcaFile.cs.  To do so, just add “using Examples.Helpers;” to the top of the file:

I cleaned out the HDXRouting out of the file, grabbed the nFuseAppCMDLine header, and then returned the result:

The result?

Success!  We’ve used the WebAPI and the StoreFront Customization SDK to supply a header, modify the ICA file, and return it with the value needed!  The ICA file returned works perfectly!  Ok, so I’m thinking this looks pretty good right?!  We just need to get the iframe to supply a custom header when the src gets updated.

Except I don’t think it’s possible to tag a custom header when you update a src in an iframe.   So then I started thinking maybe I can use a cookie!  If I can pass a cookie into the Storefront Customization SDK I could use that instead of the header.  Unfortunately, I do not see anyway to query a custom cookie or pass a custom cookie into the SDK.  Citrix appears to have (rightfully!) locked down Storefront that this doesn’t seem possible.  No custom cookies are passed into the httpcontext (that I can see).

So all this work appears to be for naught (outside of an exercise on how one could setup and customize Storefront).

 

But what about the Storefront feature “add shortcuts to websites“?

Although doing that will allow to launch an app via a URL, it doesn’t offer any method to pass values into the URL.  So it’s a non-starter as well.

Next will be a workaround/solution that appears to work…

Read More

Citrix Netscaler – Load balancing options with XML brokers

2016-06-17
/ /
in Blog
/

We were encountering ‘slowness’ with our Citrix Web Interface that logging into it and displaying the applications would take a significant amount of time ( > 10 seconds).  I have spent considerable amount of time investigating what our performance should be in our environment.  With this information we were still seeing these long logins.  It was consistently at 200 or greater concurrent connections on our web interface servers that we saw our login times spike.  I know at ~200 or so connections our response time is around 5,000ms for our XML brokers.  I then used my PowerShell script to measure the response times of our XML broker’s we are using in load balancing.  We had two servers WI01 and WI02 that I monitored and as our web interface servers were becoming loaded I noticed something odd.

Only one of our XML brokers was being hit, the other was sitting idle.  Since we use a VIP that is supposed to have load balancing I brought our network team who support the Netscalers to help me take a look.
I configured two loads:
1) Direct connections to the XML broker/VIP. This request simulates what the web interface sends to the XML broker on behalf of the user. The traffic POST’ed is an XML request for a list of all applications available to the user. This is the hardest request the web interface can send an XML broker because the XML broker needs to filter out applications the user does not have access to before it can send a response.
2) Through the web interface. This request simulates going through the HTML pages to get your list of applications available on the web AND a PNA query for all applications available to the user.

To establish a baseline I ‘loaded’ a XML server directly (WSCTXAPP301T)

image003

The burgundy line is 200 connections to the server posting a XML request for the list of all applications. When loading a single server the response time goes up to 5000ms.

I then loaded the VIP with 200 connections with the XML request.

image004

From this we can see the ‘load’ switch servers between the WSCTXZDC301T and WSCTXAPP301T. This is NOT load balancing, but the Netscaler failing over when *it* does not receive a reply from the XML monitor within 5000ms. The performance with PERSISTENCE set to SOURCEIP is no better than a single server for servicing requests.

Loading the Webinterface with requests:

image005

We see the exact same situation when going through the web interface.

PERSISTENCE: NONE

After setting the PERSISTENCE to NONE I directed traffic directly to the VIP:

image006

What we are seeing is for the exact same load (200 connections) our response time is 50% better with PERSISTENCE set to NONE. We are getting responses back in ~2300-3000ms.

Load testing the Web Interface with PERSISTENCE set to NONE sees the same results:

image007

What’s the impact on the end user by setting PERSISTENCE to NONE? There is no impact. During load testing I made several ‘real’ connections using Citrix Receiver via PNA and through the Web Interface and both continued to operate without issue enumerating applications. With this testing and information we need to change our PERSISTENCE value to NONE.

 

Read More

Optimizing Citrix Web Interface 5.4

2014-11-27
/ / /

My previous post detailed testing the limits of your Citrix Web Interface.  During this testing we discovered there appeared to be a limit on the number of connections the Citrix Web Interface could accommodate.  This discovery masked the true limitation: the Citrix Web Interface is limited by the number of threads its w3wp.exe process can spawn to handle ASPX pages.  The w3wp.exe process spawn threads to handle the number of connections/load and once it exceeded 48 threads then further requests go into the application queue.  This limitation exists when running a ASP.NET application under ASP.NET 2.0 in Classic mode.  In integrated mode this limitation is determined differently and not applicable.  Unfortunately, the Citrix Web Interface runs in Classic mode under ASP.NET 2.0.

This formula is determined by the number of CPU’s you have times an arbitrary number Microsoft decided would be good for dealing with ASPX pages set back in the IIS 5 or IIS 6 days.  It is woefully low and sadly, Citrix does not resolve it when you install the Web Interface application.

But, we can increase the per processor thread count to prevent the queuing.  To do so you must edit the “C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config” and set the processModel with a new set of thread values.

The values are MaxWorkerThreads, MaxIoThreads, MinWorkerThreads and MinIoThreads.  All values are set * the number of processors you have and are *per w3wp.exe process*.  So if you have a XenApp website and services site running on separate application pools each process then has a 1000 thread limit on a 2 processor system.  When we implement these we found we could hammer the web interface and the ASPX pages would consistently respond without issue.  We did find that hammering the web interface with 1000 threads then revealed a new performance limitation.  Though the ASPX pages were being processed so the explicit login page now constantly appeared without issue, we found that logging in and showing the applications was now slow, taking several dozen seconds at times.  By allowing our web interface to process more connections and pass those connections on; some of our dedicated XML brokers were having issues keeping up with the requests.

My next post will detail testing the capabilities of the XML server and seeing if we can determine the best way to optimize XML performance.

Read More

Slow Citrix Web Interface 5.4 on ASPX pages (or how to load test your WI)

2014-11-23
/ / /

We’ve been having issues with our Citrix Web Interface (5.4.2) with it cratering to the point that you cannot even get to the explicit logon page, stuck on SilentDetection.aspx or another aspx page.

One Moment Please…  This screen takes minutes to resolve

So what could be causing this?  More often than not, it’s a broken XML broker that isn’t responding in a reasonable amount of time.  But XML brokers don’t come into play with ‘Explicit Logon’, especially if you can’t even get to the logon page.  In our scenario, we have two production Citrix Web Interface servers which are load-balanced in a round-robin scenario.

So I theorized that what’s happening is we are experiencing a load issue.  That is our server cannot handle the number of connections that we our clients and PNA agents are producing.  How can we prove this out?  How many connections can our web interface accept?

To test out what the maximum number of connections our web interface servers can sustain I came up with a plan.  We need to thoroughly exercise the ASP.NET scripts that Citrix has put together for the web interface.  To do that we need I decided that logging in via explicit logon, skipping client installation (so client detection occurs) and then application enumeration.  This sequence hits the following ASPX pages:

 

The timeline of processing the aspx pages of a unloaded server looks like this:
The initial silentDetection.aspx’s take the majority of the processing time, about 4.3 seconds.  To create the ability to simulate this load, Microsoft has a tool called “WCAT”, or the Web Capacity Analysis Tool.  This tool allows you to setup “scenario’s” which are a sequence of HTTP actions (GET/POST/etc) which simulates each step of the sequence above.  To record this sequence for WCAT, you need to install Fiddler 2 then install the WCAT scenario creator.  There are numerous WCAT scenario creators, but I used this one.  To create the scenario do the following:
1) Launch Fiddler 2 and click ‘Launch’
2) Go through your login sequence on your web server until you hit the page with application enumerations.

 

 

3) Go back to Fiddler 2 and at the bottom of the screen on the left in the black bar, type “wcat reset”
4) Go Edit > Select All.  Then in the black bar, type ‘wcat addtrans’
5) Lastly, type ‘wcat save’.
This will create a fiddler.wcat file in your C:Program Files (x86)Fiddler2 directory.
You can now open this file as a text file to see the scenario you just created.  One of the issues with this WCAT scenario creator you will need to fix up some cookie values.  Some cookie values are captured exactly as described, which has some issues as double quotes need to be escaped in the scenario file.
So, for example, this line:
Won’t work.  You need t