I see all sorts of Environment Manager configurations at different clients. Some are put together really well - others make basic mistakes that contribute to the configuration being ineffective, slow or bloated. I've already covered the workflow of a good Environment Manager configuration in a previous post. What this article is more concerned with is some general hints and tips on how to use Actions and Conditions, rather than the structure of the configuration itself.
Node Groups are possibly the most little-known feature in AppSense Environment Manager (I think, if I remember correctly, that they first appeared in version 8.1). We've already covered the basics of node groups in this previous post, but it is worth mentioning their usage again here. When AppSense was single-threaded in version 7, it was quite easy to prognosticate the execution order, because everything ran more or less in the order they were laid out in the console. Of course, this naturally had a trade-off in a longer processing time. In version 8, the multi-threaded model allowed for faster execution, but setting up dependencies became a little trickier between nodes.
The answer to this trickiness is to use a node group, which means that any Reusable Nodes set up in the node group run before any child nodes can run.
Reusable nodes/conditions
Reusable Nodes (and Reusable Conditions) follow on nice and logically from Node Groups because once you start setting up Node Groups you will need to populate them with Reusable Nodes! Again, we've already done some coverage of Reusable Nodes/Conditions here, so we won't bother to reinvent the wheel too heavily. The beauty of Reusable Nodes/Conditions is that if you have the same Condition, Action or group of Conditions and Actions used multiple times within the same configuration, if you then need to modify that task, you only need to do it in one place to update all the instances of it within the configuration. Reusable Nodes also reduce the amount of data within the configuration which has the added bonus of reducing the memory footprint of the session.
Environment variables
Anyone familiar with any sort of scripting will recognize the value of a variable being set. For instance, if all your users imported some files in from \\SERVER1\Public\SharedStuff\AppSense\SharedFiles\General in twenty different Actions throughout the configuration, why not use an environment variable called %LocalShare% instead of the full path?
Setting environment variables within the root section of the triggers (Startup, Shutdown, Logon or Logoff) rather than in individual sub-nodes is also more logical, because then the variables are available to all of the sub-nodes in the triggers.
Descriptions
Do I have to mention this again? I think it must be a plague particular to IT staff, this problem, because an awful lot of places I go to (and this is not confined by any means to AppSense configurations - Active Directory groups and OUs are equally as bad for it) have no comments in the Description field. Just to reiterate, it is really important just to add a small description - something that will take you no more than ten seconds - to the tasks you create, especially Lockdown items. The amount of time, money and heartache that can be saved by doing this is immense. And while I'm on the subject, would it hurt anyone to put in a proper description when they save a change to the configuration? The amount of descriptions I see for configuration changes that are simply the default of "Other" beggars belief.
Computer Startup Actions
I've also seen quite a lot of people trying to do things such as network file copies in the Computer Startup node. I'm not a big fan of using the Computer Startup trigger - especially in PVS or other non-persistent environments - but if you need or want to do so, if there is anything you need to do that requires network connectivity, then the network may not be initalized when the Computer Startup trigger fires. It may be better to use a Computer Process Started trigger of some type to run the Action when the network is ready.
Active Directory lookups
Something you can usually guarantee will be referenced quite a lot in any AppSense configuration is an Active Directory group lookup. When a user logs on, it doesn't make a lot of sense to send every Active Directory lookup to a domain controller - this will drag out the logon time as well as making it impossible to provide any offline support. To make sure these problems don't occur, make sure that every Active Directory lookup uses the local security token instead - identified by the "LSA Supported" suffix shown next to the relevant Condition.
Stop if fails
The Stop If Fails checkbox (you can see it in the image above) ensures that sub-nodes won't run if a Condition is not met. If you structure your configuration intelligently enough, you can use Stop If Fails to ensure that the configuration runs in the minimum possible amount of time for the majority of your users.
Folder Redirection folder creation
A lot of people have a Folder Action running prior to Folder Redirection to create the redirected folder if it doesn't exist. This isn't necessary - the Folder Redirection Action will create the folder if it doesn't exist.
Group Policy and Registry action groupings
This is something I also try to recommend when dealing with standard Group Policy Objects. From a troubleshooting standpoint, it is always simpler to have a rule of "one Action, one setting". With both Group Policy Actions and Registry Actions you can lump together lots of different settings into one Action. Whilst this may seem desirable to save time, when it comes to diagnosing issues with these Actions, it is much easier for support teams to undo specific settings without impacting others when the settings are divided on a one-to-one basis into individual Actions. Specifically for the Group Policy Actions, there is also a performance impact from putting too many settings into a single Action.
Too many Group Policy settings in a single Action |
The bcdedit myth
I've seen this pop up in AppSense configurations at more than a few clients and I am sure it was a rumour spread in various forums across the Internet (it's not specifically an AppSense thing - I've seen it done at a multitude of places). Apparently some people think by disabling Data Execution Prevention there is a performance gain on XenApp platforms. If your configuration contains a bcdedit command designed to disable DEP permanently, I wouldn't bother with it. I've brought this up with various people, amongst them a CTP who verified it with a XenApp product architect, and there is no performance gain to be had from implementing this tweak on a XenApp system.
Executing command scripts
Using the "Do not create window (console-based applications)" option is handy for ensuring that your users aren't disturbed by command prompt windows when Execute Actions run.
Group Policy Actions as a Reusable Node
Any Group Policy Action which contains both User and Computer Configuration settings should not be set as a Reusable Node, as it is impossible to determine which one should be applied.
Scripted Actions
AppSense themselves recommend, for support and troubleshooting purposes, to keep the amount of Custom scripted Actions to a minimum (which is kind of ironic when you see the heavy scripting in some of AppSense's own configurations, but maybe those are special cases). Certainly, if there is another way of doing it natively through the console, it's not a good idea to script it. I once saw a Custom Action that called a VBScript to launch Internet Explorer - why that couldn't have been done through a standard Execute Action, I may never know.
Computer Group Conditions
If you need to use Computer Group Conditions, be aware that these can't be used on offline devices. If you do need to do this on offline devices, use the Computer Group Condition to set an environment variable to achieve it.
Printer mappings
Be careful if you are using the "Unmap at logoff" feature with AppSense-delivered printer mappings. If a configuration is deployed mid-session, the user's printers will be unmapped if this option is selected. Another option (although a little convoluted) would be to create explicit printer unmap actions in the Logoff trigger if this issue became badly apparent in your environment.
AppSense are working on fixing the "mid-session deployment" issues - I believe there is a fix for one of them in EM8 FR4 SP1 already, so this point may become redundant eventually.
AppSense are working on fixing the "mid-session deployment" issues - I believe there is a fix for one of them in EM8 FR4 SP1 already, so this point may become redundant eventually.
Active Directory Group Condition in Query mode
Imagine you have a node full of ten or twenty Actions that all have a different AD group lookup associated with them. How could you prevent a user that isn't in any of these groups from running through all ten or twenty of the lookups?
Well, if the AD groups being looked up all had a common link - maybe, just for an example, they all begin with ENG - then you could use an Active Directory Group Condition Query to filter off users that don't match the common part, saving users who don't match the initial query the time of ten or twenty AD group lookups. You implement this with the normal Condition | User | User Group, but change the Condition to Query as below
Summary
So, I think that just about covers all the tips that I can think of offhand with regard to streamlining your Environment Manager configuration. But let's be clear, there's really no substitute for good planning, testing and verifying. You should always be looking to try and make your Environment Manager configuration more effective, because it controls some of the primary areas - such as logon and application launch time - that your end-users will use to gauge the performance of their systems.
Thanks to Richard Thompson for introducing me to more than a few of the performance tweaks I've covered here.