Friday, 13 December 2013

Folder Actions in AppSense DesktopNow Environment Manager - Copy, Mirror and Synchronize

Environment Manager can do all sorts of useful things. However if, like me, you've worked with the software for a long time, sometimes you tend to forget about useful new features that have been added in during the 8.x years. One of these I tend to overlook is the capability to Synchronize and Mirror Folders.

The uses cases for Synchronize and Mirror are fairly broad. They can be used for manipulating files and folders for certain applications, for assisting with migrations, for copying existing user data into Personalization Server, for doing on-demand backups to removable drives - the uses of these Actions are only limited by what you can think of, to be fair.

One situation I always thought would be a good use of these Conditions would be for simple Offline Files functionality (thanks to Ben Whitmore for originally putting the idea in my head). Now, I know that this could be construed as a bit pointless, because AppSense have a product - DataNow - which does precisely this for you. However, I am going to persist with this idea as a demonstration for a few reasons - 1) to see if it can be done in this fashion, so that you can do (admittedly very simple) offline sync'ing without ponying up for the DataNow license, and 2) to give a quick overview of using these Actions, even if you use them for something completely different.

On a sidenote, I've been meaning to do a post on using DataNow for folder synchronization for some time - as soon as I get my home lab sorted out I will, because all of the people I work for seem more keen on ShareFile for some reason, probably because they get it with their Citrix licenses.

Differences between Folder Actions

A quick bit of background. Essentially, what's the difference between Copy, Synchronize and Mirror as defined in AppSense Environment Manager?

Copying a folder simply copies the contents of a folder from one destination to another, regardless of the other files or folders present in the destination. This Action has an "Only copy new or changed files" checkbox, which allows you to restrict the scope of the copy to files modified since the last time it was run. Note that this applies to source and destination - if a change is found in a source file or a destination file, a copy from source to destination will be initiated.

You also have a lot of other configurable options available such as File/Folder Conditions (see below), File Extension Exclusions and Path Exclusions.


The Mirror Action creates an exact copy of a folder or folder structure and all the files in it at the destination folder. The main difference in using Mirror is that files already existing in the destination are overwritten from the source, and any supplementary files in the destination are deleted. This makes the Mirror Action most useful for the type of functionality we are demonstrating, as it handles deletions in the way that we want.

The Mirror Action doesn't have any of the associated Conditions and Exclusions that the Copy Action does, as you'd expect.


The Synchronize Action examines the specified folders and combines the contents of both to produce a file and folder structure which is identical in both locations. If two files the same are encountered, the most recently modified one is copied to both locations.

Worth noting here is the Delete behaviour. If a folder or file is removed from either source or destination, it will be copied back next time the Synchronize occurs. Regardless of the source folder, the file will always be synchronized, never deleted.

The method we will use in our example will be the Mirror Action, as this gives us the capability to effectively reflect a file or folder being deleted.


The main problem with this is how to trigger the Action. To efficiently replicate the functionality of something like Offline Files, there would need to be a new Trigger, one for File/Folder Contents Changed. This sort of trigger is the way DropBox, ShareFile, Google Drive, SkyDrive and all the other third-party apps out there function (at least I presume it is). You could possibly replicate this with some fancy manipulation of Scheduled Tasks - but this seems to be unwieldy, especially for a small demonstration like this. Add to this that I don't know how efficiently EM handles file and folder conflicts, and the fact that AppSense actually have a separate product handling this functionality - DataNow - and you can tell that it's unlikely that a File/Folder Contents Changed trigger will ever materialize.

But let's not forget we're just trying to do some very basic file sync'ing here, not put up a serious challenge to technologies like DataNow and DropBox :-) So we will opt to trigger this at Logon, Logoff and additionally, at Session Locked/Unlocked. Sometimes people wonder what the Session Locked/Unlocked triggers are good for - and this is one of those situations. Usually, people lock their sessions because they are about to take a break and won't be interacting with the desktop for a while - and this is a perfect time to do things that might take time or resources, like Mirror Actions. Aaron Parker wrote a blog post on caching App-V packages at Session Locked - another good use of the Trigger.

Initial setup

Let's quickly put down some markers as to our (hypothetical) use case to ensure we don't get out of scope.

We are going to imagine we have some users who log on to laptops (remotely and locally) and also maybe use a workstation or thin client when in the office. The idea is, if they are on their laptop they will have their home folder available locally to the device (so that they can access it when they are off the corporate network), and it will synchronize with the remote location when connected to the corporate network. Also, if they log in to a workstation, they will access the remote networked copy of their home drive. Folder Redirection Actions will be used to define the home folder on a per-device basis (see below).

Note - the laptop chassis type is identified using the method specified in this previous post.

The reason I called the folder MyDocs as opposed to something like "Documents" is because of my limited PowerShell skills, I needed to give it a name that users were unlikely to apply to another folder. Anyone who's any good at PowerShell can probably get around this by binning my code and using their own :-)

So, when our users log on to their laptops, they will receive a local copy of My Documents, whereas if they use an office desktop machine, they will have a networked copy of My Documents.

The heavy lifting

Now we need to configure things so that a laptop user's local My Documents synchronizes with the remote My Documents when connected to the corporate network. We will configure the Actions and Conditions as a Reusable Node as we will call it several times within our configuration.

First up is a check to see if we are online with the corporate network or not. There are various ways you can achieve this - various Wait For Network scripts are out there (one is detailed in this article), and there's also the check for the netlogon folder that was detailed in this article.

We also need to ensure that the user is running from a laptop, so we will reuse the laptop chassis type Condition described earlier by ANDing it with the corporate network check.

If both of these Conditions are satisfied, we now need to detect which folder - either the remote or the local copy - was updated last. Now, Environment Manager allows you to specify Last Modified Time on the Folder Exists Condition, but sadly it doesn't allow you to compare this with another folder. So to get what we want we will have to do this via PowerShell. We are going to use an If Else Group to hold this (as there will be different Actions dependent on the output of our Condition). Add Condition | Flow Control | If Condition and select Custom from the Conditions available within.

Now, we need to insert the PowerShell code to do the comparison of the two folders. You will have to change the paths to match your environment, obviously.

$username = $env:username
$localsource = $env:userprofile
$localsourcedate = Get-ChildItem -Include MyDocs -Recurse -Path $localsource | Sort-Object LastWriteTime -Descending | Select-Object -First 1 | Get-Date -Format yyyyMMddhhmmssF
$remotesource = "\\FileServer\UserShares\$username"
$remotesourcedate = Get-ChildItem -Include MyDocs -Recurse -Path $remotesource | Sort-Object LastWriteTime -Descending | Select-Object -First 1 | Get-Date -Format yyyyMMddhhmmssF

IF ($localsourcedate -ge $remotesourcedate)
 exit 0
 exit 1

Also note that we have used Get-ChildItem with the -Include MyDocs switch. The reason this is done this (seemingly roundabout) way is because Get-ChildItem does not return the properties of the parent folder. Therefore, our two base variables $localsource and $remotesource actually point to the folder above the one we are enumerating, and the -Include switch makes sure we only work on the one subfolder we are concerned with. As I said earlier, this is a fudge to cover my rudimentary PS skills - you could probably easily get around it using Get-Item in conjunction with Get-ChildItem.

The format we've used is intended to simply give us an easy comparison between the two. The various formats available are covered here.

Finally, as this compares the Last Modified time I'm not sure whether you would need to ensure that the NtfsDisableLastAccessUpdate Registry value is set to 0. I am in a PVS environment where I can't change the vDisks with impunity so apologies for not testing this thoroughly. If you are in doubt, though, change the HKLM\SYSTEM\CurrentControlSet\Control\FileSystem NtfsDisableLastAccessUpdate value to a DWORD of 0. Alternatively, if you don't like messing with the Registry directly, you can use the command

fsutil behavior set disablelastaccess 0

which should do it as well.

The Mirror Folder Actions

Next we simply need to configure the Mirror Actions. If the local copy is the newest, we will Mirror the local copy to the network.

If the local copy is not the newest (and by implication, the remote copy is), we will Mirror the network copy to the local.

This should leave your entire node looking something like this

Finally, you need to link your Reusable Node in the appropriate places. We are going to do it at Logon, Logoff, Session Locked and Session Unlocked.

Now's the time to try it out. Give it a test, and you should find you have some rudimentary file synchronization set up between local and remote! Of course, it's not by any means completely robust - I can easily think of particular situations in which it may fail - but for a cheap and cheerful way to get maybe a small number of laptops running a file sync, it's an interesting option.


Of course there are better ways to do this, you could even do this with things like robocopy. But if you're in the habit of using the likes of robocopy, and you also use AppSense EM, then why have to maintain separate scripts? Leverage the full power of EM and keep everything simpler.

As I said, though, this was just intended to introduce you to the power of Mirroring and Synchronizing from within EM, rather than to demonstrate a use case. At a particular client I have seen the support department using the Mirror Action to do on-demand backups of a problematic locally-installed app onto a removable drive. When the user is finished using the software, and if the local drive is plugged in and available, it copies all of the data onto the removable device. There are lots of ways you can get value-add from these Actions - hopefully this article will encourage you to try and use them a bit more!


  1. Great article James, some great ideas in there. These folder actions built into EM are so powerful but used without careful thought admins can get themselves into a bit of trouble..take for example using the sync folder option for "Recent Items" that you have as a redirected folder on the users homeshare..sounds harmless..I thought so to until users started reporting increased logon times... I hadn't given enough thought that by syncing the folder I was retaining past and present recent items from the time the user first logged on..there were, in some cases, thousands of items trying to sync at user logon..exasperated by the fact that we were using mandatory profiles..every logon would be copying all those recent item shortcuts down from the server. I learned my lesson quickly on that one :)

  2. Check and test, check and test....not that I practice what I preach :-)