You are here: University home > CSD home > SyncProfile > Documentation
 

SyncProfile Documentation

Index:


Basics

Prerequisites

SyncProfile.exe is a self-contained program, with no run-time dependencies. It's 32bit, and runs on 32 and 64bit windows. It runs as the user and so requires no service accounts or special privileges.

It should run on Windows XP and later, but has only been tested on Windows 7 and Windows 10 builds (at time of writing, up to the October 2020 Update (build 19042)). Most functionality is expected to work on later builds as well without code changes, including any Insider builds you might want to try (config changes might be needed). The only known issue is to do with Suffix calculation.

For best results though, it needs running in a particular way:

  • At logon, it should be run before the shell (explorer.exe) starts, and in such a way that the shell won't start until it has completed.
  • At logoff, it should be run after the shell and all other user processes have exitted, but before the session has ended.

This is to ensure that files etc are not in use, and that registry settings have not yet been read by explorer.

At Liverpool, we achieve this via logon/logoff scripts delivered by Group Policy, in combination with the "Run logon scripts synchronously" setting. You also need to ensure that Group Policy processing happens at logon, and is not delayed until later in the session. This is also a convenient point to handle folder redirection if you need to. There are probably other ways of doing this, but the logon script mechanism is the one we use.

For most cases, it should only be run for users who do not have a roaming profile. This is important if you're doing cutover from roaming profiles to SyncProfile - see the section on Migration for more about this.

Also, it's possible to configure SyncProfile to only be concerned with application settings, and not to sync Windows settings at all. If doing that, there is much less need to ensure the sync happens pre-shell at logon, although it does still need to happen before the user launches the application.

An alternative use case is providing something similar to Mandatory profiles, where the aim is to provide a consistent environment every login, rather than preserving the user's settings between sessions as they move to different devices. For this, you would typically only sync at logon.


Return to Index

Installation

SyncProfile doesn't need installing in the sense of running a setup.exe or MSI on every client. Installation is more a case of putting SyncProfile.exe, SyncProfile.ini, and your roots configuration file(s) (typically SyncRoots.cfg) on a network location where all clients can access them, and making changes in your logon and logoff scripts (or equivalents) to invoke SyncProfile as needed. Those scripts can, if desired, copy these files to a temp location locally before running - this helps to ensure that the files on the network are not kept locked, and makes it easier to push changes to the config.

SyncProfile needs a valid configuration before it can be used though. The Configuration section in this document covers much of this, and the Liverpool Configuration section goes into much more detail on our particular uses of it (which may not be exactly what you want to do).


Return to Index

Concepts and Mechanisms

Roots

A root is a definition of something to sync, consisting of a name, a type, a path and a range of other optional settings, including filtering, grouping, per-root overrides of the defaults and whether it needs the suffix, all discussed in more detail below.

It is possible to approximate roaming profiles with just two roots (defined as HKCU and %UserProfile%, with some filtering), but in practice there are good reasons for dividing things up into smaller parts:

  • Keeping application settings separate from Windows settings.
  • Isolating settings for an application such that its settings can be shared between different services. (E.g. sharing Firefox settings between regular Windows desktops and Citrix-style sessions).
  • Improving logon/logoff times by allowing more operations to proceed in parallel.
  • Handling badly-behaved applications. e.g. Apps which place files in Appdata\Local that nevertheless need to move with the user.

At Liverpool, we've ended up with around 20 roots defined. The Liverpool Configuration section goes into more detail on our current configuration.

While this can appear somewhat complicated, SyncProfile is aware that these root definitions may overlap (Root2 may be defined by a path that is a sub-folder of Root1), and automatically ensures that they do not stray into each other's territory.

Roots are represented internally as a single kind of thing, regardless of whether they hold registry data or filesystem data. This means we don't refer to files, folders, keys or values, when talking about what's in a root. Instead a root is considered to have "Containers", which represent folders or keys as appropriate, and "Leaves", which represent registry values or files, as appropriate. This doesn't make a huge difference, but is useful when looking at log files, or constructing filtering rules, such as ExcludeLeafNameExact.


Return to Index

Suffix

When storing profile data on the network, it will go in one of two folders. One folder is as defined by the NetFolder option (see Config section in the ini), the other is based on the NetFolder option, but has a suffix appended to it. This suffix allows roots to be kept separate for each Windows version, or other purposes, depending on how the suffix is defined.

Roots include a setting as to whether they belong in the plain folder on the network, or the suffixed one. i.e. How the suffix is constructed is a global setting, but each root can say whether it belongs in the suffixed folder or the plain one.

The suffix is specified in the SyncProfile.ini file, and we go into more detail there on how it is constructed, but with the default setting it uses the Windows Build and Branch information.

So, if the NetFolder option is set to "SyncWin" (which it is by default), a user might have the following folders where their profile data is stored:

  • SyncWin
  • SyncWin.14393L
  • SyncWin.15063C
  • SyncWin.7601

The first contains all the root data for roots that are not specific to the windows version, while the others contain the roots that use the suffixed folder, kept separately for (in this example), Windows 10 Anniversary LTSB, Windows 10 Creators Current Branch, and Windows 7 Service Pack 1.


Return to Index

Sync Methods

Registry roots have only one method which involves exporting to a text-based format. There is no option to change the sync method for registry roots.

Filesystem roots have a choice of either "As-Is" or "zip" for their sync method. Zip is recommended for the case where a user is moving to a PC that they have not used before (and so has no existing local profile). SyncProfile was designed with this in mind as the typical case.

As-is sync can be faster for the case where a user is moving between a small number of PCs, where they are regularly returning to each, and so have only small changes to sync.

In our testing, we find that it is much faster to zip a large number of files locally and copy the zip to the network than it is to copy the large number of files to the network one by one. At least, this is the case for PCs with an SSD.

Regardless of method, for filesystem roots, an index file (fsindex.txt) is also saved, and this contains all the information that will be used at logon to decide what to sync. i.e. the index file is the authoritative list of what was saved at logoff and contains all the file names, sizes, datestamps, attributes etc.

You can change sync method even if there are existing users with saved data - SyncProfile will check for this and cut things over as needed.

Using Zip as the sync method has a useful side effect compared to roaming profiles and folder redirection in that it greatly reduces the number of files on the user's profile storage. A large number of small files becomes a handful of larger files.

NB, the the contents of the zip are only meaningful to SyncProfile. There is no folder structure inside the zip and the files are numbered rather than having their original names. A utility (UnPackRoot) is provided with SyncProfile that can take a zip and accompanying index file and extract the files and folder structure for diagnostic purposes.

NB2, when syncing As-Is, the folder structure on the network matches what was present locally, but does not preserve attributes or timestamps (because these are always stored in the index).

NB3, In general, you shouldn't tinker with the contents of the network copy of the profile.


Return to Index

SyncProfile Locking

SyncProfile ensures that only one SyncProfile operation is in progress at any one time. Logging into or out of more than one PC at once is handled so that each SyncProfile operation in turn is allowed to complete before any others are started.

The basis of this is a file, SyncProfile.Lock, which is created when SyncProfile starts (see the config section later on - it goes in the folder defined by the NetProfile setting). SyncProfile keeps a write lock on this file while syncing and deletes the file once done. Any other SyncProfile operations which try to start while that is running will fail to get the lock and will retry, eventually either succeeding (if the first operation finishes) or giving up (if it runs out of retries).

In the event of a crash that leaves the lock file behind, the server end will eventually time out the write lock (typically 15 minutes). Subsequent SyncProfile runs will then be able to delete it and proceed as normal.

NB, this mechanism just ensures that only one SyncProfile operation is in progress at a time. It is not a queue, and if multiple SyncProfile operations are waiting to get the lock there is no control over the order in which they do so. In general, the best solution to problems arising from logging off more than one machine at once is "don't do that", if you can.

If using SyncProfile to provide Mandatory profile functionality, the lock mechanism may be less useful. If all you're doing is syncing at logon, all your clients are doing read activity and there is less need to isolate them and ensure they don't overlap. For this specific case, the locking mechanism can be disabled by a command line option - see later.

NB, if doing this, the case where you need to update the central copy of the profile is not protected against file locking issues - a client with a read lock will prevent attempts to update the profile data. You'll therefore need to ensure by other means that no clients are in mid-logon when updating the data.


Return to Index

Profile Timestamps

At logoff, SyncProfile saves the profile data to the network, and for each root it stores the timestamp of when that root was saved. This timestamp information is also kept locally in the user's temp folder. This is checked at logon, to avoid syncing profile data where the dates match.

If a users logs off and back on again at the same PC, SyncProfile does not waste time syncing data unnecessarily. If the last thing we did was save to the network from this PC, there can't be anything to sync at logon.


Return to Index

Configuration

SyncProfile has three sources of configuration:

  • The SyncProfile.ini file.
  • The command line.
  • The roots configuration file, typically SyncRoots.cfg.

Broadly, the ini specifies global settings and defaults, the command line overrides the ini if needed and provides things that can only be done at runtime (e.g. the sync direction), and the roots config file tells it what to sync and how.

However, Syncprofile behaves differently at logoff compared to logon as far as configuration is concerned:

  • At logoff, the roots config file is used, and the resulting configuration for each root is saved with the data for each root.
  • At logon, each root uses the individual root configuration that was saved with it. The roots config file is not used.

This is because it is important for roots to be synced at logon with the same configuration that was used at logoff. E.g. changes to the filter configuration could have undesirable side effects if we picked up the new filter, and used it with profile data that was saved with a different filter. The downside of this is that changes to the config are only picked up at logoff.


Return to Index

SyncProfile.ini

Syncprofile will look for its ini file in the current directory, and if it cannot find one there it will look alongside SyncProfile.exe. If it still can't find one, it will give up and rely on internal defaults. It will only read one ini file.

The ini has four sections:

  1. Debug
  2. Config
  3. Defaults
  4. Advanced

While it is a reasonably normal INI file format, note that it requires spaces either side of the = sign. Lines starting with ";" are comments, and the sample ini file supplied is heavily commented.

Most things in the ini can be overridden from the command line. Nothing in the ini is case sensitive.


Return to Index

Debug settings

These settings control diagnostic logging.

SettingDefaultAllowed ValuesNotes
LogfileSyncProfile.logValid file pathThe name of the file to log to. Setting this does not in itself enable logging. If a plain filename is used, it goes in the user's %temp% folder. Or, specify a full path. The log file output is always UTF8.
Level00-2The logging verbosity. Level 0 is the most basic, 2 is the most verbose. 0 and 1 are fine for normal use. 2 will have performance implications.
ToFileFalseTrue/FalseSet this to true to enable logging to file.
AppendFalseTrue/FalseWhether to append to an existing log (true) or overwrite (false).

Sample ini section:

[Debug]
logfile = SyncProfile.log
level = 0
tofile = False
append = False


Return to Index

Config settings

These settings control the general SyncProfile config that is not specific to particular roots. These can all be overridden on the command line.

SettingDefaultAllowed ValuesNotes
RootsConfigSyncRoots.cfgValid file pathThe location of the roots config file. If this is a plain filename it is looked for in the current directory, and failing that alongside the exe. Or, specify a full path. SyncProfile will only read one roots config file at logoff. (At logon it gets root config from the saved profile data.)
NetProfile%homeshare%%homepath%Valid folder pathThe location on the network that we should use to store the user's profile data. SyncProfile will create folder structure beneath this for its own use (see NetFolder, below), and also use this location for SyncProfile.lock. This should be a user-specific location. Environment variables are fine here, so long as they are defined at the times SyncProfile will be run. So \\[server]\[share]\%username% may be valid, so long as all users using this config are on the same server and share. %homeshare%%homepath% may also be a viable approach for users across a variety of servers and shares. Or a custom variable if you can guarantee that the script that runs SyncProfile has set it (this is what we do at Liverpool). The folder specified must already exist, and the user must have write access. The path can end in a backslash or not, either is fine This path will contain data that is personal to the user so should only be accessible to the user and IT administrative staff, not somewhere that all users have rights to.
 
If using SyncProfile to provide Mandatory Profile functionality, a different approach is possible here - in this case you aren't syncing at logoff, only at logon, and the data is common to all users.. A single central location, readable by all clients, is typical for this situation.
NetFolderSyncWinValid folder nameThis specifies the sub-folder that SyncProfile will use within the folder defined by NetProfile, above. Two versions of this folder will be used - one named as specified here, and one with a suffix appended according to tokens specified in the settings. See the suffix setting and tag details below. As a quick example, you might end up with folders "SyncWin" and "SyncWin.14393L"
Suffix.[Build][Branch]See notesThe suffix is constructed from one or more tags in square brackets, plus other characters that are passed through unchanged. Tags are detailed below. The resulting suffix must start with a "." - Syncprofile will add this automatically if one isn't provided. The suffix cannot be empty.
CustomSuffixCustomStringTo be used in the suffix calculation if needed. Most likely you'll want to supply this on the command line, but you can give it a default value here.
MaxThreads162-32Syncprofile will process multiple roots and multiple actions within each root concurrently to get work done as quickly as possible. In practice disk or network contention will become the limiting factor - 16 threads seems to be the sweet spot in our tests, but you may want to do your own. The minimum is 2 because the main thread gets things done by spawning worker threads to do the work. Setting this to 2 can be useful when diagnosing problems, as the logging is then linear rather than having multiple actions interleaved.
ShowProgressNoneNone/Logon/Logoff/BothThis controls whether a progress bar is displayed during the sync process. Doing this at logon is not especially useful as it is typically behind the "Preparing your desktop" screen, but it can be useful at logoff. The window it not interactive (i.e. the user can't close it). Progress calculations are approximate.
AsciiOutTrueTrue/FalseWhether any text output to stdout is ASCII format (true) or UCS2 unicode (false). SyncProfile gives brief info to stdout when roots start and complete sync. This option allows you to match the output to any existing log file you might be appending to.
ErrorDetailFalseTrue/FalseSyncProfile returns errorlevels to indicate what happened. If errordetail is true, different errorlevels are used to indicate different kinds of success. i.e. One errorlevel might mean success because there was no work to do, another might mean work was done successfully. If errordetail is false all situations that count as success return errorlevel 0, and a non-zero errorlevel implies a serious error. Errorlevels are covered in more detail below..

The suffix is constructed from the following tags (not case sensitive):

TagMeaning
[WinSuffix]Returns the same profile suffix that Windows would have used for the roaming profile. "V5", "V6" etc. NB. This only knows about Windows versions up to and including Windows 10 Creators Update, so use this with caution for anything later than that.
[Branch]Returns "L" for LTSB/LTSC installs and "C" for Current Branch or Current Branch for Business (and Semi-Annual Channel). "X" is returned for Windows 10 builds where the branch is not recognised. Windows versions prior to 10 return "".
[Build]Returns the Windows build number. e.g. "15063"
[Major]Returns the major version number. e.g. "10"
[Minor]Returns the minor version number. e.g. "0" (from 10.0)
[AcadYear]Returns the academic year, which for our purposes is considered to start on the 1st Sept. e.g. "2017"
[Custom]Returns the custom suffix string, either from the ini or command line.
Other charactersAnything that does not form one of the above tags is passed through unchanged.

The tag system means that you can do more sophisticated things with this if needed, probably in combination with scripting to decide the custom suffix at runtime.

Sample ini section:

[Config]
RootsConfig = SyncRoots.cfg
NetProfile = %HOMESHARE%%HOMEPATH%
NetFolder = SyncWin
Suffix = .[build][branch]
CustomSuffix = Custom
MaxThreads = 16
ShowProgress = None
AsciiOut = True
ErrorDetail = False


Return to Index

Default settings

These are defaults that the roots (defined in the roots config file) will get unless they override with their own explicit settings.

SettingDefaultAllowed ValuesNotes
UseSuffixTrueTrue/FalseWhether roots go in the suffixed folder on the network by default. This defaults to true because it certainly shouldn't default to false - you will almost certainly have some roots that do need to be kept separate for some different windows versions.
PreserveNewerFalseTrue/FalseThis only applies to filesystem roots, and determines whether an older file is allowed to overwrite a newer one. It defaults to false because, for roaming profile purposes, when a user goes to a machine they have not used before, much of their profile is freshly created and may have timestamps from profile creation (i.e. a few seconds ago). In such cases you want the user's files to overwrite the newer default ones.
FolderMethodZipZip/As-IsLikewise, this only applies to filesystem roots. See the section above about sync methods. Registry roots always use a text-based format for exported registry data.

Sample ini section:

[Defaults]
UseSuffix = True
PreserveNewer = False
FolderMethod = Zip


Return to Index

Advanced settings

These settings control advanced or internal aspects of SyncProfile. You probably don't want to change these, but they are exposed in the ini in case you need to.

SettingDefaultAllowed ValuesNotes
LineWrap256IntegerWhen exporting registry data, strings over this character length will be linewrapped. This is a purely cosmetic issue - the original string is reconstructed when the file is read. This applies to registry strings (REG_SZ, REG_EXPAND_SZ and the strings within REG_MULTI_SZ), and to binary format (REG_BINARY, REG_NONE) which are stored in the text export as a Base64 encoded string.
MaxMCount1024IntegerThe maximum number of strings that are supported within a REG_MULTI_SZ. If a value is encountered that exceeds this, SyncProfile will consider it an error.
MaxRegName1024IntegerThe maximum length of a registry value or key name. Again, examples that exceed this are considered an error.
RetryCount201-100In cases where SyncProfile will retry on an error, how many times to retry. Currently this applies to things like reading status files, indexes, etc, not to the sync process itself. The overall SyncProfile locking (Syncprofile.Lock) mechanism uses this x3.
RetryDelay100010-10000As above, but how long to wait between retries (in milliseconds)

As far as other registry limits are concerned, SyncProfile has no particular limit on how deeply nested registry keys can be, or how large value contents can be - the internal Windows limits will be hit first.

Likewise, there is no particular limit on the length of filesystem paths or how deeply folders are nested.

Sample ini section:

[Advanced]
LineWrap = 256
MaxMCount = 1024
MaxRegName = 1024
RetryCount = 20
RetryDelay = 1000


Return to Index

Command line options

All command line options are of the form "-OptionName=OptionValue". If OptionValue contains spaces, it should be enclosed in "". Option names and parameters are not case sensitive.

Direction is the only required parameter - the others are all optional.

OptionRequiredAllowed ValuesNotes
-DirectionYesLogon/LogoffThis tells SyncProfile whether its syncing at logon, or logoff, and therefore whether it's syncing from or to the profile filestore. If not specified, SyncProfile will return an error and show the command line help screen.
-NetProfileNoValid folder pathSame as the corresponding setting in the ini.
-NetFolderValid folder name
-CustomSuffixString
-RootsConfigValid file path
-FolderMethodZip/As-Is
-MaxThreads2-32
-ShowProgressNone/Logon/Logoff/Both
-IncludeRootsComma separated list of root names, without spaces. e.g. -includeroots=root1,root2,root3

If no include/exclude root or group settings are supplied, SyncProfile will sync all the roots it knows about from the roots config file (at logoff) or saved profile data (at logon). If you want to restrict SyncProfile such that it only syncs a subset of the roots it could sync, you can use one or more of the include/exclude options. Roots can be specified either by name, or by the groups that they might be a member of as specified in the roots config.

Using an Include rule implicitly excludes all roots that are not listed. Likewise, using an Exclude rule implicitly includes all roots except those excluded. IncludeRoot and IncludeGroup can be combined, as can ExcludeRoot and ExcludeGroup, with no problems. Combining includes with excludes is not recommended and is usually a sign that you need different root groups. Roots can be in as many groups as you like.

-ExcludeRoots
-IncludeGroupsComma separated list of root group names, without spaces. e.g. -includegroups=group1,group2
-ExcludeGroups
-LogFileFilename or full path to fileUnlike the ini, specifying a log file on the command line implicitly enables logging to file as well as setting the file to log to. As with the ini, a plain filename goes in the user's temp folder, or give it a full path.
-LogLevel0-2Verbosity level, same as the ini.
-LogLockTrue/FalseWhether to keep the log file open during the sync. In some environments, opening and closing the log file each time it writes to it can be a noticeable overhead.
-NoSyncLockTrue/FalseDisables the SyncProfile locking mechanism, during logon sync only. Intended to make it easier to use SyncProfile to provide Mandatory Profile functionality.
-ForceSyncTrue/FalseForces SyncProfile to ignore profile timestamps and sync anyway (see above about Profile Timestamps). Useful when testing on a single machine, as otherwise there will be no work to do at logon.
-?, -helpN/AReturns the command line help screen.

Sample command lines:

SyncProfile.exe -direction=Logon -IncludeRoots=OfficeToolbar -IncludeGroups=Profile -LogLevel=1

SyncProfile.exe -direction=Logoff -IncludeRoots=OfficeToolbar -IncludeGroups=Profile -LogLevel=2 -MaxThreads=2


Return to Index

Roots Configuration

The roots configuration file is a custom file format:

  • Configuration information is indicated in the form of "Option: Value"
  • Lines starting with "#" are comments. Blank lines and lines that do not form a valid option are also ignored.
  • Nothing is case sensitive.
  • When defining a root, the root name must be first, followed by the type. Other values can then follow in any order and continue to apply to that root until a new name is reached.

An example config is included in the Liverpool Configuration section, below.

OptionRequiredDefaultAllowed ValuesNotes
Name:Yes, must be firstN/AAlphanumeric, plus - and _. No spaces or commas.All subsequent settings apply to the root just named, until the next name is reached.
Type:Yes, must be secondN/ARegistry/FolderThis must be second because it affects what other options are applicable.
Path:YesN/AValid registry key or folder pathFor registry roots, the key should include the hive, which can be specified in long (HKEY_CURRENT_USER) or short (HKCU) format. No trailing backslash is needed, so to sync the entire current user registry you'd use "HKCU". For folder paths, again no trailing backslash is needed. Wildcards are not supported; it must be a specific folder. Environment variables are fine, so long as they are defined in the context where SyncProfile will be running. Quotes are not needed even if the path contains spaces. Leading and trailing spaces will be removed. NB, in some cases it may be necessary to have more than one root with the same path. This is valid - see the later sections on Separating Settings.
Group:NoN/AComma separated list of group names, no spaces. Same rules for group names as for root names.You can supply a list of one or more groups to make the root a member of. This allows easier inclusion or exclusion of a particular set of roots at the command line.
UseSuffix:NoAs defined in the iniTrue/FalseWhether the root uses the suffixed folder on the network (True), or the plain one (False). I.e., whether this root contains things that need to be kept separately for, say, different versions of windows, or whether it contains things that are general.
Method:No; Folder roots only.As defined in the ini or supplied on command lineZip/As-IsPer-root override of folder sync method.
PreserveNewer:No; Folder roots only.As defined in the iniTrue/FalseWhether newer files will be overwritten by older ones during sync. Per-root override of the global default, which is usually False for roaming profile purposes.
Priority:No1IntegerUsed to determine which roots to start processing first. SyncProfile will allocate actions to available threads starting with the roots with the highest priority (i.e. higher number here). The number is meaningless other than as a way of sorting the roots into order of priority. This is for fine-tuning performance - if you have data that some roots take longer than others to sync (see section about logging for how to get timing information), there is a mild benefit in giving those roots higher priorities.
Weight:No1IntegerHigher values mean SyncProfile gives more weight to the root when calculating overall percentage completion. This only affects the progress bar that can be shown at logoff or logon.
ContainerDefaultNoIncludeInclude/ExcludeThis is the starting point of the filtering system, and the defaults are to include all containers (i.e. folders or keys), and leaves (i.e. files or values). Depending on what you're doing with the filtering, you might want to start from the opposite situation where everything is excluded by default and you define what you include. This can be set separately for containers and leaves. See filtering section below.
LeafDefault:NoIncludeInclude/Exclude
Include... / Exclude...NoN/AVariousFiltering rules - see filtering section below.
ProtectPath:NoN/AValid file path or key pathDefines things that SyncProfile should never attempt to delete. See section on Protected Paths.

As noted above, SyncProfile only reads the main roots config file at logoff, during which the resulting configuration of each root saved is included along with the profile data for that root. At logon, the saved root config for each root is used, to ensure that the configuration is the same as was used to save the data.

A simple example of a Registry root:

Name: OSReg_Core
Group: Profile
Type: Registry
Path: HKCU
UseSuffix: True
ContainerDefault: Include
LeafDefault: Include

ExcludeContainerPathContains: AppV\Client
ExcludeContainerPathExact: HKCU\AppEvents
ExcludeContainerPathExact: HKCU\Control Panel\PowerCfg
ExcludeContainerPathExact: HKCU\Printers\Connections
ExcludeContainerPathExact: HKCU\System
ExcludeContainerPathExact: HKCU\Volatile Environment

And one for a filesystem root:

Name: Firefox
Group: Browsers
Type: Folder
Path: %userprofile%\AppData\Roaming\Mozilla\Firefox
UseSuffix: False
ContainerDefault: Include
LeafDefault: Include

ExcludeLeafNameSuffix: .bak
ExcludeContainerNameExact: Crash Reports
ExcludeContainerNameExact: minidumps

# Block files over 100MB.
BlockLeafSizeGreater: 100000000


Return to Index

Filtering

Filtering works by setting an initial default for containers and leaves as to whether they are included or excluded (see ContainerDefault and LeafDefault in the root config, above). Then we define as many filter rules as we like in addition to that to include or exclude things overriding that default.

A Filter rule is constructed from five parts:

  • Operation: Include, Exclude or Block.
  • Object type: Container, Leaf or Any
  • Attribute of that object: Name, Path or Size (in bytes)
  • Match type to use: Exact, Prefix, Suffix, Contains, Greater or Less
  • The string to match with.

The first four of these form a compound word which acts like an option in the root config file, followed by the string as the value for that option. e.g. The config section for a filesystem root might have the line:

ExcludeLeafNameExact: Thumbs.db

Which would exclude any file called thumbs.db anywhere in that root.

The operation is difficult to talk about without going into examples which use the other parts of the rule, which we haven't talked about yet, so we'll come back to that below.

The object type is container (i.e. folder in the filesystem or key in the registry) or leaf (file or value), or any (i.e. the rule applies to both).

The attribute of that object can be either the name, not including any part of the path, the entire path, or the size (in bytes). Size is only a valid attribute for files, i.e. leaf objects within folder roots.

For filtering purposes, the path of a container or leaf includes the defining path of the root it belongs to, as originally defined (i.e. with variables intact rather than expanded). This allows rules to include parts of the root path. E.g. you can match against %UserProfile%\Appdata to ensure that you're not matching against any other folder that happens to be called Appdata. Container paths do not have trailing backslashes.

The match type is essentially how we decide whether the string we've come up with for comparison purposes (for the container or leaf under consideration) matches the string we've been given for the filter rule. All such matching is case insensitive, and ignores leading/trailing spaces on both strings.

  • Exact - Does the attribute of the object match the string we've been given exactly?
  • Prefix - does the attribute start with the string we've been given?
  • Suffix - does it end with it?
  • Contains - is it in there anywhere?
  • Greater/Less - for leaf sizes, is the size greater or less than the size we've been given? Sizes are always in bytes.

So, back to the operation - the first part of the rule, and some examples. All roots have a default, and then any filter rules would usually be the opposite of that default. e.g. Include by default followed by Exclude rules. You can get fancy with this though. The filtering system allows for a default (e.g. Include), an override of that default (Exclude), and an override of the override (Include again). So, you can do things like this (all examples constructed for the purpose of showing how the rules work):

ContainerDefault: Include
LeafDefault: Include
ExcludeLeafNameExact: Desktop.ini
IncludeLeafPathSuffix: Favorites\Desktop.ini

This will include all files and folders, but exclude desktop.ini files anywhere in the root, except for the one in the Favorites folder which is included because its path ends with "Favorites\Desktop.ini". i.e. The exclude rule overrides the default, and the explicit include rule overrides the exclude. The order here doesn't matter - the fact that it's an include by default root is what makes the include rule override the exclude rule. If the root excluded by default, exclude rules would override include rules.

In some cases this behaviour might not be desirable - you might want to include by default, and have a mix of include and exclude rules where some of the excludes are ones you don't want overridden. This is what the Block operation is for - block is an exclude that can't be overridden. So if you had something like this:

ContainerDefault: Include
LeafDefault: Include
ExcludeLeafSizeGreater: 100000000
IncludeAnyPathPrefix: %UserProfile%\Appdata\Roaming

The include at the end would include everything in Appdata\Roaming overriding any exclusions, and the exclusion by size would have no effect in that subfolder. But if we did this instead:

ContainerDefault: Include
LeafDefault: Include
BlockLeafSizeGreater: 100000000
IncludeAnyPathPrefix: %UserProfile%\Appdata\Roaming

The size restriction is now effective even in the Appdata\Roaming folder. This example also shows the use of path prefix matching where the defining path of the root is used (the root in this example would have %UserProfile% as its defining path).

Be careful when combining includes and excludes for containers and relying on the override behaviour. One effect of excluding a container is that SyncProfile will not recurse into it to examine the contents when scanning the registry or filesystem, so it is not possible to exclude a folder and then include a sub-folder of the excluded folder. If you need to do that, you'll need to define a new root for the sub-folder you want.

The size restriction in the above examples is for files over 100MB. This is useful for parts of the profile that might have large temp files or autosaved data that would slow down logon/logoff and fill up the profile filestore if you tried to sync it. Much of that is best excluded based on location, but excluding by size is a good belt-and-braces approach.

Some filtering tricks: Filtering by file extension is done by:

ExcludeLeafNameSuffix: .tmp

Which excludes all files of that type anywhere.

Filtering, such that you include a folder itself and the files in it, but exclude all subfolders regardless of name:

ExcludeContainerPathPrefix: %UserProfile%\example\path\with\backslash\

The trailing backslash means that the folder itself is not excluded, but all the sub-folders are.

Notes:

  • There is no wildcard support. Anything you want to do must be constructed out of include/exclude/block rules and the various types of string matching. Partly this is because things like "*" are valid characters in registry key and value names (I have an include rule for a registry key named "*"), which makes a simple * and ? based wildcard scheme impossible.
  • Filter rules are automatically added to keep roots from interfering with each other. What this means in practice is that all roots of the same type (folder or registry) will automatically get a set of BlockContainerPathExact rules for the defining paths of all other roots of that type. This is true even for roots that are not being synced - if the current run is only syncing a subset of roots, roots that are not part of that subset will still result in block rules on the roots that are part of it.
  • If something is excluded, that means that it will not be synced, but it also means that SyncProfile will ignore it completely, for all purposes. It won't recurse into excluded containers and scan their contents, so rules that would match against something inside an excluded container will never do anything in practice.
  • Every folder, file, key and value that you want to sync has to end up included one way or another. This means that exact matching against name or path has to be used with caution. Excluding a name or path exactly will exclude that, and for containers will exclude the contents as well, but excluding the contents is a side effect. The things in those containers are not excluded because the rule excluded them but because their parent container was excluded and that stopped SyncProfile from looking inside. This means that exclude rules have side effects that are generally what you want to happen anyway. For include rules, there is no such side effect doing work for you. If you want to include a container and everything in it, an exact match on the name or path is not enough. That would include the container but when we come to look at the things in it we would not include them (at least, not as a result of an exact name or path match against the parent). For including, matching against the path prefix is usually a better option, as the container and everything in it shares a prefix.
  • The defining path of the root does not need an include rule and cannot be excluded or blocked. Treating the defining path of a root as a thing to be scanned happens without any filter checking.
  • Excluding something means that it will not be synced, which is not the same as saying it will be removed or deleted locally. In the above examples, I talk about excluding autosave data for size reasons - that doesn't mean a user can't recover an autosaved version of a document, it just means that autosaved versions of files will not move with them from one PC to another. They will still be there locally if they go back to the machine they were using - aside from any separate mechanism that may mop up such profiles.
  • Because exclusion means that the excluded thing is not in SyncProfile's in-memory structures, SyncProfile will never decide to explicitly delete an excluded item directly. However, it is still possible for excluded things to be deleted as a consequence of deleting their parent folders or keys (so long as those parent folders are not themselves excluded). Filter rules will not protect against that - if there are things that absolutely must not be deleted (or cannot be deleted and you want to avoid spurious errors) you want ProtectPath, described below.


Return to Index

Protected Paths

Paths can be protected to ensure that SyncProfile will not delete them.

Protected paths are automatically defined internally to keep the roots from interfering with each other. Roots can also add further paths to the protected list. This is done within the config for a particular root, usually the root that contains the path to be protected, but the resulting list of paths is global and applies to all roots. Paths are protected even if they come from the config of roots you are not currently syncing - i.e. if you use the -includeroots command line option to sync settings for a single root, the protected paths from all the other roots defined in the config still apply.

Example of paths you might want to protect are:

  • Folders you have excluded because they contain a log file that cannot be synced because it is in use. If a user starts on a machine where the application is not present, and moves to one where it is, SyncProfile will find that folder as a discrepancy to be deleted, and will fail because it contains a file that's locked. This will put warning messages in the log, and raise the errorlevel. Protecting the folder avoids the warning being generated.
  • Registry keys that might or might not be present, but if present the user does not have rights to delete the contents. E.g. HKCU\Software\Google\Chrome\NativeMessagingHosts exists on Win10 build 15063 even if Chrome is not installed, but cannot be deleted by the user. As it's in a part of the registry that would normally be considered as independent of Windows version, it's possible for a user to move from an earlier build (where the key does not exist) to 15063 (where it does) and consider it something to be deleted, which will fail with an access denied. Protecting the key again avoids a warning being logged.

Remember that the defining paths of all roots, and the parents keys/folders of these paths are automatically protected to avoid conflicts between roots. You only need to manually deal with exceptions to that which need protecting.

As an example, this is what we do to protect the Chrome key mentioned above:

ProtectPath: HKCU\Software\Google
ProtectPath: HKCU\Software\Google\Chrome

Note that the protection only applies to the specific paths you provide. It does not automatically apply to the parent folder or key, and only protects against SyncProfile deleting that path explicitly, not against it deleting the parent folder or particular sub-folders. You need to define protected paths for the parent folder as well if they are not already protected. In the above example, we happen to have a root defined for HKCU\Software, so that is already protected.

Also, note that this protects the key or folder from deletion, but does not protect the things inside it. Normally, the things inside it are either fair game for deletion as needed to make the local profile look like the profile data the user has brought with them, or are subject to filtering in some way to exclude them. In this example, the NativeMessagingHosts key is excluded via filtering, and so that (and everything in it) is protected from direct deletion by that, and does not need to be a protected path as well. Siblings of NativeMessagingHosts are fair game. We just need to protect the parent keys.


Return to Index

Liverpool Configuration

This section goes into some detail on how we use SyncProfile at the University of Liverpool, as it's probably better to talk about real configurations than to construct hypothetical examples from scratch.

It's important to bear in mind that this is an example of how SyncProfile can be used, and a possible starting point for developing your own configuration, but several of the things we're doing are done for reasons specific to our environment and requirements.

In particular, our aim here was to consider application settings as primary, and sync those if at all possible. Windows settings are second-class citizens in our model - we'll sync them if and only if they are well known and well understood. The more opaque and windows-internals parts of the current user registry we consider safer left on each device, and likewise for the AppData\Roaming\Microsoft folder.


Return to Index

Separating Settings

Profile settings, whether file or registry, can be divided up into three broad categories:

  1. Stuff we want to sync, which is application-specific
  2. Stuff we want to sync, which is windows-specific
  3. Stuff we don't want to sync.

The challenge is then to design a system of root definitions where everything falls into the right category:

  1. Application specific - included by one root that does not use the suffix, and nowhere else.
  2. Windows specific - included by one root that does use the suffix, and nowhere else.
  3. Stuff we don't want - not included by any root (i.e., excluded by all roots).

Where this gets more complicated is where a folder contains a mixture of items in categories 1 and 2, or 1, 2 and 3. For this, the answer is two roots for the same path (yes, you can do that, although they must have different names), one using the suffix, one not. These then need careful filtering rules:

  • One or both should be exclude-by-default, so that only one at most operates as a catch-all.
  • The filtering rules should be such as to ensure that everything within the path is the responsibility of at most one root.

This kind of thing doesn't occur very much - in our configuration this issue arises twice - for %UserProfile% itself, and for %UserProfile%\AppData\Roaming\Microsoft. These are covered in more detail below in the filesystem root design. We have no instances of this (two roots with the same path) for the registry.

One thing we do to help with keeping track of this is to use "OS" as a prefix on the root name for all roots that use the suffix. That way, if you see a reference to a root called OSFiles_Base, you have a pretty good idea what it might be.


Return to Index

Registry Root Design

The following table gives an outline of how the registry roots are constructed for our config.

Colour Key:

BoldRoot definition
   KeyIncluded explicitly. For roots, this means roots that include by default.
   KeyExcluded explicitly. For roots, this means roots that exclude by default.
 Root is not concerned with this key.
Root_NameRoot is application-specific. i.e. does not use the suffix.
OSRoot_NameRoot is windows-specific. i.e. does use the suffix.

Path \ Root OSReg_Core Reg_Software Reg_ClassesEtc OSReg_MS Reg_MSIE Reg_Office OSReg_WinCV OSReg_Explorer OSReg_Active6432
HKCU Root 
   HKCU\AppEvents   
   HKCU\Control Panel\PowerCfg   
   HKCU\System   
   HKCU\Volatile Environment   
HKCU\Software  Root 
   HKCU\Software\Alerts001    
   HKCU\Software\AppDataLow    
   HKCU\Software\Clients    
   HKCU\Software\IMProviders    
   HKCU\Software\Policies    
   HKCU\Software\RegisteredApplications    
HKCU\Software\Classes  Root 
   HKCU\Software\Classes\[Key named "*"]    
   HKCU\Software\Classes\[Keys starting "."]    
   HKCU\Software\Classes\Applications    
HKCU\Software\Microsoft  Root 
   HKCU\Software\Microsoft\Active Setup    
   HKCU\Software\Microsoft\Assistance    
   HKCU\Software\Microsoft\Command Processor    
   HKCU\Software\Microsoft\IME    
   HKCU\Software\Microsoft\IMEMIP    
   HKCU\Software\Microsoft\Input    
   HKCU\Software\Microsoft\Powershell    
   HKCU\Software\Microsoft\Screen Magnifier    
HKCU\Software\Microsoft\Internet Explorer  Root 
   HKCU\Software\Microsoft\Internet Explorer\GPU    
   HKCU\Software\Microsoft\Internet Explorer\LowRegistry    
   HKCU\Software\Microsoft\Internet Explorer\User Preferences    
HKCU\Software\Microsoft\Office  Root 
HKCU\Software\Microsoft\Windows\CurrentVersion  Root 
   HKCU\Software\Microsoft\Windows\CurrentVersion\Run    
   HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce    
   HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings    
   HKCU\Software\Microsoft\Windows\CurrentVersion\IME    
   HKCU\Software\Microsoft\Windows\CurrentVersion\ScreenSavers    
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer  Root 
   HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced    
   HKCU\Software\Microsoft\Windows\CurrentVersion\Control Panel    
   HKCU\Software\Microsoft\Windows\CurrentVersion\RunMRU    
HKCU\Software\Wow6432Node\Microsoft\Active Setup  Root

The above is just an outline - it is not a comprehensive set of exclusions. Refer to the config file in the download for the full details.

Notes:

  • Reg_Active6432 is a separate root in its own right for dealing with active setup keys for 32bit apps on 64bit windows. The keys for 64bit active setup on 64bit windows are within HKCU\Software and end up included as part of Reg_Software.
  • Of the exclusions that aren't shown, the Active Setup related ones are the most important. Active Setup for windows components should be excluded, because when they run they will probably be making changes in parts of HKCU that we are not syncing.
  • This is only a suggested config. You may want to design your own for your own purposes and application set.
  • Most applications create their keys under HKCU\Software\[ApplicationName] or HKCU\Software\[DeveloperName], so for most non-Microsoft applications Reg_Software is doing most of the work.


Return to Index

Filesystem Root Design

As with the registry, the aim here was to ensure that application settings synced, and to sync windows settings as well if they are reasonably well understood, but not to try to sync some of the more complicated Windows profile internals.

The filesystem tends to be messier than the registry. Applications ported from other platforms tend not to do weird things in the registry because they aren't from a platform that has a registry (although there are exceptions). But ported apps are quite likely to do things off the root of %userprofile% or use Appdata incorrectly, or completely ignore the local/roaming distinction (because other platforms don't really have that), and this can result in application data being saved in unexpected locations. (E.g. creating a folder alongside Roaming, Local and LocalLow).

The filesystem is also where we have real instances of wanting two roots with the same path. For example, %UserProfile% itself contains some sub-folders which are windows-specific, and some that are not (e.g. applications ported from unix, creating .appname folders directly under %Userprofile%). We handle this with two roots - OSFiles_Base and Files_Base, which both have %UserProfile% as their defining path. OSFiles_Base uses the suffix; Files_Base does not. OSFiles_Base excludes by default, and has a list of specific inclusions for the sub-folders it's concerned with. Files_Base meanwhile does include by default and has a complementary set of exclusions to keep away from the folders OSFiles_Base is concerned with. Files_Base has a further set of exclusions for things we don't want to sync at all.

The other case is the AppData\Roaming\Microsoft folder, which has various windows-specific sub-folders, but also (assuming Office is installed) various Office-specific sub-folders as well. In this case we again have two roots, one include by default, one exclude by default, and a matching set of exclusions and inclusions to pull the Office files out into a separate, non-windows-specific, root.

As above, this is a table giving a reasonable level of detail on how the filesystem roots are constructed, but refer to the config file for the full details and exclusions.

Colour Key:

BoldRoot definition
PathIncluded explicitly. For roots, this means roots that include by default.
PathExcluded explicitly. For roots, this means roots that exclude by default.
PathExcluded implicitly. Shown in root columns where the root excludes by default.
PathIncluded by one root, excluded by another.
 Root is not concerned with this path.
Root_NameRoot is application-specific. i.e. does not use the suffix.
OSRoot_NameRoot is windows-specific. i.e. does use the suffix.

Path \ Root OSFiles_Base Files_Base Files_Favorites OSFiles_MS Files_Office Files_VS Firefox Chrome OfficeToolbar
%UserProfile% RootRoot 
   %UserProfile%\[Other Subfolders]    
   %UserProfile%\Contacts    
   %UserProfile%\Desktop    
   %UserProfile%\Documents    
   %UserProfile%\Downloads    
   %UserProfile%\Music    
   %UserProfile%\Pictures    
   %UserProfile%\Saved Games    
   %UserProfile%\Searches    
   %UserProfile%\Videos    
   %UserProfile%\AppData\Local    
   %UserProfile%\AppData\LocalLow    
%UserProfile%\Favorites  Root 
%UserProfile%\AppData\Roaming\Microsoft  RootRoot 
   %UserProfile%\AppData\Roaming\Microsoft\[Other Subfolders]     
   %UserProfile%\AppData\Roaming\Microsoft\Access     
   %UserProfile%\AppData\Roaming\Microsoft\Bibliography     
   %UserProfile%\AppData\Roaming\Microsoft\Document Building Blocks     
   %UserProfile%\AppData\Roaming\Microsoft\Excel     
   %UserProfile%\AppData\Roaming\Microsoft\Office     
   %UserProfile%\AppData\Roaming\Microsoft\Outlook     
   %UserProfile%\AppData\Roaming\Microsoft\Powerpoint     
   %UserProfile%\AppData\Roaming\Microsoft\Proof     
   %UserProfile%\AppData\Roaming\Microsoft\Publisher     
   %UserProfile%\AppData\Roaming\Microsoft\Publisher Building Blocks     
   %UserProfile%\AppData\Roaming\Microsoft\QuickStyles     
   %UserProfile%\AppData\Roaming\Microsoft\Spelling     
   %UserProfile%\AppData\Roaming\Microsoft\Stationery     
   %UserProfile%\AppData\Roaming\Microsoft\Templates     
   %UserProfile%\AppData\Roaming\Microsoft\UProof     
   %UserProfile%\AppData\Roaming\Microsoft\Word     
%UserProfile%\AppData\Roaming\Microsoft\VisualStudio  Root 
%UserProfile%\AppData\Roaming\Mozilla\Firefox  Root 
%UserProfile%\AppData\Local\Google\Chrome\UserData  Root 
%UserProfile%\AppData\Local\Microsoft\Office  Root

Notes:

  • The Chrome and OfficeToolbar roots have paths inside an excluded folder. Doing such things as separate roots is the recommended way of doing this - trying to come up with filtering rules that would allow those folders to be included in, say, Files_Base, would be very difficult.
  • The Firefox root is separate so that we can share Firefox settings between our desktop windows service and our Citrix service. This would not be possible if Firefox was included in the general Files_Base root.
  • OfficeToolbar is for the Quick Access Toolbar in various Office applications. It's also possible to use the registry to change where Office stores this, but we didn't know about that when this was written.
  • This config includes exclusions of a number of the default Shell Folder locations such as the user's Desktop and Documents folders. This is recommended - either because you're redirecting these to a network location, or because they're staying local to each PC. Syncing locations that the user might be saving their own files to isn't what SyncProfile is designed for.
  • This is only an outline of the config - there are many more exclusions and filtering rules involved. Refer to the example config file for what's really going on.
  • This is only a suggested config. You may want to design your own for your own purposes and application set.
  • Most applications put files in Appdata\Roaming, or directly under %UserProfile%. Either way, Files_Base is doing most of the work, although the Chrome root can also get large. In some cases, splitting Roaming into its own root might be desirable for concurrency reasons.


Return to Index

Example Config File

This is a bit large to include in-line... Example Config


Return to Index

Migration

Briefly, our migration path was determined by where we were starting from - namely student accounts with roaming profiles defined by the profilepath attribute on their AD object. For us, migration was a matter of changing our logon process to be able to do things the new way, but to stick with the old way if Windows considered the user to have a roaming profile. Then we could clear the profilepath attribute from test accounts to start using them with SyncProfile, while not affecting the rest of the user population. Also, we used separate test versions of our logon and logoff scripts for these test users.

Once we were happy with this, it was a question of making those changes live, such that we could start clearing the profilepath attribute from real users, which we did gradually over about a week using DSMOD. Finally, changes to our registration system to stop populating that attribute in the first place, and a final mop-up to ensure they were all cleared.

After that, it became more a question of maintaining and tweaking the config to take account of minor issues as they arose - the same as any production system.

In doing this, we made use of the GetProfileType utility (see Utilities) to decide whether a given user was still considered a roaming user by Windows.


Return to Index

Known Issues

General

SyncProfile does not attempt to sync ownership of files or folders, or permissions or auditting settings on files, folders or registry keys. It does not attempt to preserve file timestamps other than the last modified timestamp, and does not preserve folder timestamps at all. The last modified timestamp is only stored to 1-second accuracy. This is not normally an issue for roaming profile data.

It does preserve file and directory attributes when syncing (but not the archive bit), but attribute differences alone are not sufficient to trigger a sync. i.e. if a file was saved at logoff with particular size, date and attributes, and the file is found to exist at logon with the same size and date but different attributes, the file will not be synced. Again, this is not normally an issue for roaming profile data.

SyncProfile does not attempt to sync, or recurse into, filesystem links of any kind (symlinks, hard links, junctions etc). In most cases such junctions are to things elsewhere in the profile, such that "C:\Users\[Username]\Application Data" appears to exist, but is really a pointer to "C:\Users\[Username]\Appdata\Roaming" which is visible as a normal folder and synced accordingly. We're not aware of any need to recurse into junctions as if they were normal folders, or to attempt to copy them as junctions.

Registry data should be preserved accurately, including registry strings (REG_SZ, REG_EXPAND_SZ or the strings in a REG_MULTI_SZ) that contain carriage return, line feed, or other control characters. As far as SyncProfile is concerned, all such strings are UCS2 unicode, because it uses the unicode versions of the Win32 API calls, and is UCS2 internally. Some applications may expect to get ANSI strings back from the registry, but they should still do so, as they will be using the ANSI API calls, and Windows will do the conversion for them. REG_BINARY and REG_NONE are treated as binary blobs and are not converted in any way if they contain string data. However, it may be possible for applications to create invalid registry data that happens to work for that application (e.g. a REG_SZ with a sequence of bytes that isn't a valid UCS2 string). Such values may be altered by the sync process.

A specific instance of this is applications that create registry keys with line feed or carriage return as part of the key name. These are not valid key names as far as Microsoft specifications are concerned, but applications can get away with this. SyncProfile does not sync such keys and will log a warning when it encounters them.

SyncProfile does not have specific checks for running out of disk space, either locally for temp files or on the user's profile filestore. Some monitoring of the user's saved profiles is probably needed to track down cases of badly behaved applications using the profile to store significant amounts of data. i.e. you will need to periodically look for candidates to add to the filtering. Filtering can also be used to exclude files based on size. The same kind of issue applies to traditional roaming profiles, and to folder redirection to some extent. If anything, folder redirection is worse because it has no synchronisation step, and so no point at which filtering might be applied.

Because SyncProfile deals with the registry via the registry APIs (as opposed to traditional roaming profiles, for which the registry hive is just another file to copy), there are some things that cannot be synced because the user does not have rights to do so. i.e. there are parts of HKEY_CURRENT_USER that are not writable to the user (even if they are an admin). Most of these are things you wouldn't want to sync anyway - group policy related keys etc - so it's just a question of filtering these out.

SyncProfile has long (>260 characters) path support for both local files (drive letters) and network paths (UNCs), but does not currently support long paths as the defining path of a root, and I don't recommend it for the netprofile path, the path to the roots congfig file or the path to the log file. It also only supports long paths on UNCs if the server providing the storage supports them. UNC paths for SyncProfile are typically quite short unless as-is sync is being used.


Return to Index

Profile Creation

Although SyncProfile is intended to run pre-shell, this is still after Windows has created a profile for the user (or synced a roaming or mandatory profile if applicable). This is because that has to happen before the user's session really exists and can run processes as the user.

SyncProfile is therefore not a solution to the problem of users going through the profile creation process every time they move to a new PC. Instead, we allow profile creation to happen, and then sync changes into the freshly created profile. This is the main downside compared to traditional roaming profiles, where the user goes through profile creation once, and not thereafter. (That said, the fact that the user isn't going through profile creation is part of why various Windows features have problems for roaming users. Also, the sync mechanism for traditional profiles can involve copying large numbers of files individually, which can be slower than copying a zip and extracting locally even once the profile creation time is included.)

So, there is a great incentive to spend time on making the profile creation process as fast as possible - more so than with traditional roaming profiles. There are a variety of things you can do to achieve this, including making changes to the default user profile (we recommend doing this directly, rather than via the CopyProfile mechanism, as CopyProfile is regularly broken in newer Win10 builds), disabling startup items and generally cutting down on things you don't need. Specifically, any Modern apps you don't need are well worth removing from your Win10 image, and in our case we do the removal against the starting installation materials, such that the apps in question are never provisioned for any user (this is easier than unpicking them after the fact). But for our student PCs, the main thing we do to provide fast login despite profile creation happening every time is to use LTSB (since renamed to LTSC, but there are no LTSC releases yet). This may or may not be an option for you, depending on your environment, but having run Windows 10 (original release) on the student PCs in 2016/17 and Anniversary Update in 2017/18, it has definitely helped keep the service stable and responsive. We have also yet to have any requests for Modern apps on the student PCs (compared to close on 400 desktop applications of various kinds).


Return to Index

Hashed Settings

There is a category of settings in Windows 10 which are protected by hashes. This hashing is designed such that the values protected by the hash can only be changed via the Settings app, not by poking the registry directly. This means that although SyncProfile is capable of carrying these settings around with the user, the settings won't actually work as the hashes are no longer valid. This affects things like file associations for key file types, and the default browser setting. Our approach is simply to exclude those settings from synchronisation and live with that, although we do apply a set of default file associations (e.g. associate PDF with Adobe Reader). There are third-party utilities that purport to be able to set the default browser setting, using UI automation of the settings app, such that the hash comes out correct, but we have decided not to do this in our environment. (In practice, most users run the browser they want, and do things in that, rather than relying on the right browser being launched from a URL file or link in another application). (If you want to explore this further, the third-party utility is here: https://github.com/sampalmer/set-default-browser.)


Return to Index

Local Profile Accumulation

With traditional roaming profiles, Windows can be told to not cache the roaming profile data, meaning that when things are working normally, the local part of a user's profile is deleted from the PC after they have logged off cleanly, and they leave essentially no trace. PCs may see hundreds of users per week with no significant accumulation of profile data.

SyncProfile typically means migrating away from traditional roaming profiles, to local ones. This means that as far as Windows is concerned, the profiles are regular local profiles, and it isn't going to automatically delete them. PCs in high-traffic shared areas will therefore accumulate profile data on C: quite quickly, and some additional system is going to be needed to clear this up.

This isn't SyncProfile's problem to solve, in that there is nothing it could actually do, while running as the user, that would clear up profile data. We have a system at Liverpool for doing this, which uses the DelProf2 utility by Helge Klein to do the hard work - https://helgeklein.com/free-tools/delprof2-user-profile-deletion-tool/. I can provide more details on what we do at Liverpool if needed, but it's essentially a scheduled task and some extra scripting around DelProf2. We also put a marker file in the profile at logoff to indicate that it was synced successfully to the network, based on the errorlevel returned.

NB. There are problems in some of the later Win10 builds where deleting a user's profile (via any mechanism) isn't an entirely clean deletion and references to that user's SID persist in various places. A particular problem is the accumulation of per-user-per-app firewall rules for modern apps, which can rapidly cause problems for devices that see large numbers of users. Currently there is no easy automated way of clearing these things up as part of deleting the profile for a given username. Automated reimaging is one approach that works for this, but isn't suitable in all cases. This kind of thing is a problem for any approach (e.g. these firewall rules are also a problem for roaming profiles with cached profile deletion turned on).


Return to Index

Active Setup

Active Setup is a mechanism that allows stuff to be done for new or existing users, at logon, without depending on the user doing anything in particular. E.g. installing an application might add an active setup entry such that all subsequent users (whether they already have profiles or not) get a command run on their next login that populates current user settings that the application needs in order to run.

This is the same kind of thing that MSI self-healing can be used for, except that Active Setup happens at logon, not on running a particular kind of application shortcut, and doesn't necessarily involve MSI. For more info, this is a good explanation of it: https://helgeklein.com/blog/2010/04/active-setup-explained/.

The relevance to SyncProfile is this - SyncProfile can very easily sync the registry keys that indicate that a particular active setup item has been run for the user. But, depending on what else you're syncing, it's entirely possible that you've excluded some or all of what that active setup item actually did when it was run.

This is potentially bad, as it means the user carries around with them the fact that X was done, but does not carry around with them the results of X having been done. They may arrive at a new machine, active setup thinks there is no work for it to do, but the user is missing some key settings that active setup would have populated if it had run.

This is particularly true of the built-in active setup entries which tend to do things to parts of HKEY_CURRENT_USER that are somewhat opaque, or might be deliberately excluded from sync (e.g. the Shell Folder keys)

Active setup for particular applications is more likely to be safe, as applications are unlikely to require current user changes in the parts that are likely to be excluded from sync. The example config file contains the exclusions we use to ensure that windows-related active setup things run at every new PC, but application specific ones are kept and run only once when first needed.


Return to Index

Miscellaneous

Diagnostics

Logging

SyncProfile can generate a log, and that log contains certain info, depending on the diagnostic level. Roughly speaking:

  • Level 0 - just the "always logged" stuff, including all types of error, brief initialisation info, brief timings and sync info (count of files transferred etc).
  • Level 1 - above, plus more verbose initialisation including the root config details of all included roots. Protected paths are listed. Thread info as threads are assigned to actions. More detailed statistics at the end, including timings of each action in each root, and overall time spent on each root.
  • Level 2 - High diagnostics. Detailed info from all actions, including leaf-by-leaf and container-by-container info from the comparison stage for all roots. Initialisation includes config for roots that were not included.

High diagnostics will generate large logs, and have a significant performance impact. Levels 0 and 1 don't have any significant overhead.


Return to Index

Log File format

The log file is output line by line (that is, no single log message will span lines, which is useful when using grep).

During the early part of the sync process, lines will look something like this:

 1 :#:         32 : FinaliseOptions    : Folder structure does not exist within NetProfile. No work to do.

These are fields, separated by " : ". The fields here are:

  • The thread the message came from.
  • A marker for summary purposes (see below).
  • The elapsed time (in milliseconds) that SyncProfile has been running.
  • The function the message came from.
  • The message text.

Later on in the sync process, multiple threads will be spawned, each of which is doing some work for a particular root. At this point the format changes slightly:

 3 : :        674 : SyncAdditions      : Files_Base : Starting syncadditions

This has an extra field after the function name, which indicates the name of the root being processed. This allows all actions relevant to a particular root to be extracted with grep.

The start of the log will have a section something like this:

Thr:       Time : Procedure          : Text 
 1 :#:          2 : main               : App Details: SyncProfile 1.4.1 Build 370 2017.10.26 14:28:51
 1 : :          2 : main               : Developed by the University of Liverpool / Mike Sandells.
 1 :#:          3 : main               : Logging started: 2017.10.26 15:07:19
 1 : :          3 : main               :  To file:      True
 1 : :          3 : main               :  Filename:     C:\Users\#######\AppData\Local\Temp\SyncProfile.log
 1 : :          3 : main               :  Log level:    0
 1 : :          4 : main               :  Username:     #######\#######
 1 :#:          4 : main               :  Computername: #######
 1 :#:          5 : main               :  OSBuild:      14393

And will end with something like this, for a successful run:

 1 :#:       3920 : main               : Normal exit: 2017.10.26 15:07:23 errorlevel: 0

Some of these lines have ": :", while others have ":#:". The ones with the # in them are summary lines. These allow the log to be searched for ":#:" to output to a summarised log file.

In our scripting we use this such that each user has their most recent logon and logoff logs, complete, as well as logon and logoff summary logs, which are appended to each time.

This allows you to see plenty of detail from the most recent event, but also the basic history of SyncProfile activity, including if there were errors at some previous session.


Return to Index

Timing information

At loglevel 1 and above, the log file includes some detail on the timing of various operations. For example:

 1 :       2916 : FinishSync         : Files_Base       :  Tidy Local               :   0.34% : 7 msecs
 1 :       2917 : FinishSync         : Files_Base       :  Tidy Network             :   0.24% : 5 msecs
 1 :       2917 : FinishSync         : Files_Base       :  Clear Root Status        :   1.90% : 39 msecs
 1 :       2917 : FinishSync         : Files_Base       :  Scan Local               :  12.79% : 262 msecs
 1 :       2917 : FinishSync         : Files_Base       :  Create Data Zip          :   0.15% : 3 msecs
 1 :       2918 : FinishSync         : Files_Base       :  Sync Additions           :  71.58% : 1466 msecs
 1 :       2918 : FinishSync         : Files_Base       :  Sort and Fix (local)     :   0.15% : 3 msecs
 1 :       2918 : FinishSync         : Files_Base       :  Save Index File          :   0.10% : 2 msecs
 1 :       2919 : FinishSync         : Files_Base       :  Copy Index File          :   2.05% : 42 msecs
 1 :       2919 : FinishSync         : Files_Base       :  Copy Data Zip            :   6.74% : 138 msecs
 1 :       2919 : FinishSync         : Files_Base       :  Save Root Status         :   3.71% : 76 msecs
 1 :       2920 : FinishSync         : Files_Base       :  Tidy Local               :   0.24% : 5 msecs

This is a section giving the time spent on each action within a particular root (Files_Base) in this case. Each action has the time in milliseconds, plus the percentage of the total time spent on that root. Due to multi-threading both within and between roots, some of these actions may have happened concurrently. There will be sections for all of the roots in turn.

Later:

 1 :       2963 : FinishSync         : Files_Base       :  total thread time:  23.73% : 2128 msecs
 1 :       2964 : FinishSync         : Reg_Software     :  total thread time:  19.69% : 1766 msecs
 1 :       2964 : FinishSync         : Chrome           :  total thread time:   5.42% : 486 msecs
 1 :       2964 : FinishSync         : OSFiles_MS       :  total thread time:   6.32% : 567 msecs
 1 :       2965 : FinishSync         : OSFiles_Base     :  total thread time:   5.18% : 465 msecs
 1 :       2965 : FinishSync         : Files_Office     :  total thread time:   4.31% : 387 msecs
 1 :       2965 : FinishSync         : Reg_ClassesEtc   :  total thread time:   3.30% : 296 msecs
 1 :       2965 : FinishSync         : OSReg_Core       :  total thread time:   3.55% : 318 msecs
 1 :       2966 : FinishSync         : OSReg_MS         :  total thread time:   3.68% : 330 msecs
 1 :       2966 : FinishSync         : OSReg_Explorer   :  total thread time:   4.07% : 365 msecs
 1 :       2966 : FinishSync         : Reg_Office       :  total thread time:   3.43% : 308 msecs
 1 :       2967 : FinishSync         : OSReg_WinCV      :  total thread time:   4.60% : 413 msecs
 1 :       2967 : FinishSync         : OSReg_Active6432 :  total thread time:   2.79% : 250 msecs
 1 :       2967 : FinishSync         : Files_Favorites  :  total thread time:   6.25% : 561 msecs
 1 :       2968 : FinishSync         : Reg_MSIE         :  total thread time:   3.67% : 329 msecs

This lists all roots (that had any work to do), and gives the total time spent on each, plus the percentage of the total time spent on all roots. Again, multi-threading means that a large fraction of this probably happened concurrently.

Finally:

 1 :       3024 : FinishSync         : Timings          :   Init:            50
 1 :       3024 : FinishSync         : Timings          :   Pre-Thread:      990
 1 :       3024 : FinishSync         : Timings          :   Threaded:
 1 :       3025 : FinishSync         : Timings          :     Real:          1795
 1 :       3025 : FinishSync         : Timings          :     Cumulative:    8969
 1 :       3025 : FinishSync         : Timings          :     Saved:         7174
 1 :       3026 : FinishSync         : Timings          :   Post-Thread:     191
 1 :       3026 : FinishSync         : Timings          :   Total:           3026
 1 :       3026 : FinishSync         : 
 1 :       3026 : FinishSync         : TimingCSV        : 50,990,1795,8969,7174,191,3026

This gives a higher-level view of where SyncProfile spent its time. The threaded section breaks down into the real time spent, and the cumulative time spend in all the threads that were launched. The difference between these numbers is the time saved by threading.

The TimingCSV line gives the same information in a CSV format, which can be more convenient when extracting this from log files.


Return to Index

Types of Error

SyncProfile recognises several different kinds of error, which are tagged in the log output for easier discovery using grep or similar. The various error types are:

TypeLog detailsNotes
Warning"WARNING:"Occurs during sync of user data - i.e. actual writing of files/folders to the profile or keys/values to the registry. No retries attempted (currently). These are warnings, because the odd error is relatively normal and should not derail the process - i.e. SyncProfile will carry on with the remaining operations for that root. Warnings like this are how things that might need to be filtered or protected are discovered - log files that are in use; HKCU keys the user doesn't have rights to etc. In most cases the line in the log containing the "WARNING:" text will include the windows errorcode and error text (from FormatMessage()).
Error"ERROR:"These occur if there are failures at a more fundamental level - errors in copying the zip from the network or reading saved root configs or similar. These are subject to a retry mechanism. As above, details about the underlying error should be reported on the same line. These errors are reported when the failure occurs, and will be reported multiple times if the error occurs again on each retry attempt. The retries may eventually succeed, so the presence of "ERROR:" lines in the log do not mean there was an error overall. Errors of this type will either resolve as successful in the end or turn into FATAL errors if the retry limit is reached.
Retry"Success following earlier ERROR."Logged when an earlier error succeeds on retry. Includes the number of retries involved.
Fatal errorFATAL:Something more serious. This could be an ERROR that has simply run out of retry attempts. Or, it could be an error that isn't retriable. Fatal errors that occur early will abort SyncProfile entirely and no further processing will occur. Later on, once we're running multiple threads per root, a fatal error will abort the thread, and abort the root as far as launching new threads is concerned, but existing threads for that root will probably run to completion. Other roots will continue normally. Fatal errors will include the underlying error details, unless the reason it's fatal is that we hit the retry limit, in which case the details are with the preceding ERROR. Some FATAL errors will result in more than one line in the log with the FATAL marker.
InternalINTERNAL:This happens when an internal sanity check fails. This can simply mean a bug, although some some sanity checks can fail as a result of corruption in the saved registry or filesystem index files.
Unhandled errorNot loggedIf something really unexpected happens, SyncProfile will crash with an unhandled error. "Unhandled error, cannot continue" is sent to stdout (as UCS2, regardless of the AsciiOut setting), followed by the most recent error code and message. It will also report the source file and line. Nothing is logged for this, as the program is no longer in a state where it can safely write to files.


Return to Index

Errorlevels

SyncProfile returns different errorlevels depending on the ErrorDetail option. If ErrorDetail is false, all codes for success or non-serious errors collapse to zero.

SituationErrorDetail FalseErrorDetail True
No work to do at logon, because there is no profile data on the network (e.g. a user's first logon)00
No work to do at logon, because the local profile timestamps match the network ones (e.g. logon immediately after logoff)1
Work to do for at least one root, completed with no fatal errors or warnings. (Any ERRORs succeeded in the end).2
Work to do for at least one root, completed with warnings but no fatal errors.3
Failed to load functions from AdvApi32.dll100
Invalid command line parameters, including no direction specified101
Suffix resolved to an empty string102
Unable to locate roots configuation file103
Read roots configuration file but did not find any valid roots in it104
Read roots configuration file, but no roots included after processing root and group includes and excludes. (I.e. the command line is either excluding all roots, or is trying to include roots that are not in the config)105
Folder specified by NetProfile option does not exist106
Unable to read overall root status on the network107
Unable to save overall root status on the network108
Fatal error during sync. This is typically an error for a particular root - other roots may have completed successfully.109
Failed to get SyncProfile.lock, and ran out of retries.110
Any other unhandled error200

The highest applicable errorlevel is returned.


Return to Index

Large Zips

A recurring problem with trying to synchronise user settings between devices, is that users may end up with significant amounts of data inside their profile that gets caught up in the sync process, leading to slow logoff/logon. With SyncProfile we have the possibility of doing something about it with filtering, but it requires investigation to work out what to filter.

Doing so means finding cases where a user has large amounts of data being synced so that we can see what's ending up in the profile and decide what to do about it. There are several methods of doing this:

  1. Use the SyncProfile logs to track down users where the sync process is taking a significant amount of time, or reporting large amounts of data synced.
  2. If profile data is being stored on a dedicated profile filestore for each user, rather than on their home filestore, it may be possible to look at quota usage data for this filestore to see who is using the most space.
  3. Scan the location where profile data is being stored to look within the SyncProfile folder structure for unusually large zip files. (This assumes you're using Zip as the sync method).

These are all useful methods, although the last one is the one we've found most useful. Having found such zips, we can unpack them to a scratch area (using UnPackRoot, below) and use WinDirStat to scan it and analyse the space usage.


Return to Index

Helper Utilities

The SyncProfile download includes a couple of helper utilities:

  • UnPackRoot.exe. This can be used to extract profile data from a saved root that used the Zip sync method. It takes parameters of the folder containing the fsindex.txt and fsdata.zip files, and another folder to extract to. The folder to extract to will be created if needed. When extracting a zip in this way, unpackroot does not preserve the timestamp or attributes - this is primarily because it is intended to be used to track down cases where large amounts of data are ending up in the zip.
  • GetProfileType.exe. This returns an errorlevel to indicate what Windows thinks the current users profile type is. This is a combination of values: 0=Local, 1=Temporary, 2=Roaming, 4=Mandatory. So, e.g. a user with a roaming profile will have a profile type of 2 on typical machines, but 3 on machines where the setting to delete cached copies of roaming profiles has been enabled (as it is both roaming and temporary). This utility was useful to us during migration as a way of keeping SyncProfile from doing things with users who were still roaming as far as Windows was concerned. NB, this is more reliable than looking at the Active Directory attributes of the user, as the profile type is determined at logon, and applies to that session however long it lasts. If you had a profilepath defined when you logged on, then as far as Windows is concerned, you're a roaming user even if your AD object has been updated in the meantime.


Return to Index

Background

Why was it written?

Syncprofile was written in response to degradation of roaming profile support in Windows. From Windows 8 onwards, roaming profiles are still officially supported, but clearly an afterthought if that, and Windows has accumulated various features which were clearly designed without roaming profiles in mind and do not work well or at all for roaming users. This has included features as fundamental as the start menu. Microsoft's recommendations these days are essentially to stop having the kinds of problems that roaming profiles traditionally solved - i.e. users moving between devices as the normal case. That model is not something we can move away from for a wide variety of reasons, so we need to continue solving those problems even on newer Windows versions, and allow settings to move with the user as the user moves between devices, typically moving every time to a device they have never used before. There have also been semi-official indications (technet postings from Microsoft employees) to the effect that roaming profile support will be dropped entirely in a future version of Windows.

We also found roaming profiles to be less than ideal in some cases, and moving to our own solution offered more flexibility and control over what settings roam and in what cases. It's much easier to allow settings to roam or not for a user based on the type of machine in use, for example.

We had also found a number of issues with redirecting the Appdata\Roaming folder. Folder redirection is not a sync mechanism, so there is no possibility of filtering what gets redirected. An application which places large amounts of data in Appdata\Roaming cannot easily be prevented from filling up the user's filestore. We'd also found issues in Windows 10 with explorer hanging that were strongly suspected to be related to appdata redirection. If nothing else, performance is a good reason for keeping appdata local during the session.


Return to Index

Other Alternatives

Microsoft have two technologies you are directed to as alternatives to roaming profiles or the roaming-profile+folder-redirection combination. These are Enterprise State Roaming (ESR), and User Experience Virtualisation (UE-V)

ESR currently only syncs some windows settings, plus settings for Modern apps which have been written to make use of it. This doesn't overlap with our needs at all - we have no Modern apps.

UE-V syncs settings on a per-application basis, not the entire profile. This is more interesting, in that it does, at least, sync settings for the kind of applications we have in profusion, and keeps application and windows settings separate. But it also fell well short of our needs and was not a good fit for our design philosophy. UE-V is an on-demand mechanism that triggers based on the application launch event. In turn, this means it needs to be able to uniquely identify applications from the launched executable. It also needs to be told what to sync for each application, and (as we understand it) does not prevent applications from self-healing or triggering active setup (both of which happen prior to the application itself starting).

Our preferences, (or in some cases hard requirements) meanwhile were:

  • To sync settings for well-behaved applications (i.e. files in appdata\roaming and registry settings in HKEY_CURRENT_USER) by default without requiring per-application configuration.
  • To sync settings for applications even if they are running inside another process (java apps, python apps, various other interpreted languages), and so all look like the same executable (java.exe etc).
  • To sync settings for applications even if they are executables we don't know about in advance. (e.g. Comp sci students may need to have settings sync for their own applications, where we have no control over the exe name.)
  • To avoid self-healing and active setup from triggering unnecessarily.
  • To avoid getting in the way or causing a bottleneck at application launch time.

We couldn't see a way of using UE-V to achieve those ends.

There are third-party alternatives to roaming, but we had concerns about these relating to:

  • Expense. Anything priced per-user gets expensive very quickly for Universities.
  • Risk of being tied to a set of supported windows versions. It's useful for us to be able to slot in Insider Previews or new builds at release, for testing purposes, which means we'd prefer a solution that wasn't deeply hooked into windows or dependent on running on a version it knows.
  • Not necessarily better. See below about design philosophy.

So, on the basis of all this, and with past experience with custom sync mechanisms for Chrome (which puts data in Appdata\Local) and on our Mac service, we decided to explore rolling our own solution. SyncProfile is the result, and has been used in production at Liverpool since early September 2017. At time of writing (April 2018), we consider this to have been a success, and will be sticking with this for 2018/19 academic year.


Return to Index

Design Philosphy

For our desktop services we try to provide the functionality users need, while keeping things as simple as possible. If we can't keep things simple - if we have to introduce complexity at all - we prefer for that complexity to be as far away from the user run-time environment as possible. That means, roughly, we want to keep any complexity as far to the left as possible in the following sequence:

Image Creation | Image Deployment | App Deployment | Logon/Logoff | App Launch

And means, effectively, that we prefer a complex way of getting a simple result, over a simple way of getting a complex result.

Of relevance here, UE-V is complexity at application launch, which is what we most want to avoid. SyncProfile is one step removed from that - it happens at logon / logoff, and is relatively simple in itself in terms of what it depends on (just filestore, which you probably need anyway, and which was also true for traditional roaming profiles). If, for some reason, SyncProfile cannot run, the worst that happens is the user gets a default profile, or the profile they had when they last used that PC. SyncProfile also means we are no longer redirecting appdata, which reduces the network dependencies at application run time, and removes a bottleneck - a good fit with what we're trying to do.

Equally, our philosophy means we prefer to get things done at the earliest possible point, rather than the last.

UE-V is an on-demand technology, and that is essentially "do it at the last possible moment". Doing something on-demand means you've missed all your chances for getting it done earlier, when the user wasn't waiting for it. In general, we think of this as "pre-demand", and includes things like ensuring a required application is already installed locally in a room, ahead of the class that needs it. With an on-demand system, it's difficult to take advantage of that kind of knowledge.

We want the complexity to have been and gone by the time the user is actually trying to do things. Complexity here means not only things that are complicated in themselves, but also dependencies of any kind that are external to the PC - servers, VMs, etc. Any such external systems that are needed at application run time are going to be important systems, hence they need to be resilient, and therefore redundant, and support failover, and this is itself further complexity (and power-consumption, and embodied costs, etc).

Ideally, anything the user does (e.g. launch an application) should have everything it needs already local, installed on the machine ahead of time (overnight or earlier). That way, you get ideal parallelisation of user activity, and no bottleneck by design. Failing that, things should be as few hops away as possible.

This kind of design philosophy is something we've been doing for a long time, but have made more explicit in the past few years. It's getting off-topic from SyncProfile, but I highly recommend this kind of thinking about services; thinking about the best place for the complexity to go, and keeping the user environment as simple as possible, even at the cost of achieving that simplicity by complex means.


Return to Index

Terms and Conditions

SyncProfile is an internal tool developed and used at the University of Liverpool. It is made available on the basis that others in the UK Higher Education sector may find it useful.

However:

  • SyncProfile and its helper utilities are provided with no warranty.
  • Use of SyncProfile and its helper utilites are entirely at your own risk.
  • There is no commitment to provide support.

That said, on the support question, if you're in the UK Higher Education sector, and are having trouble getting SyncProfile to work, or are hitting issues you would like to raise, email mikejs@liverpool.ac.uk. There is no commitment to provide support, but at the same time we'd like to see people able to use it if they want to.


Return to Index

Future Development

SyncProfile was developed for our own needs, and is only being shared because the implementation seems reasonably generic and not tied to our own environment. Our own requirements are primarily what will drive any further development. If you have anything particular in mind, contact me on the email address above, and we'll look at it, but as with support we make no commitment to adding features on request.


Return to Index

Version History

  • 10.11.2017 : 1.4.3 (build 373) - First version made available outside the University of Liverpool.
  • 17.04:2018 : 1.4.4 (build 378) - Fixed bug in registry handling that could result in spaces appearing at the end of REG_SZ or REG_EXPAND_SZ strings, in rare cases. Minor documentation tweaks.
  • 18.05.2018 : (no changes) - Other minor documentation tweaks, and wider release of build 378.
  • 26.06.2019 : 1.4.5 (build 387) - Added -LogLock parameter. Application is now high-DPI aware (only affects the progress indicator) [Not released more widely]
  • 26.07.2021 : 1.4.6 (build 388) - Added -NoSyncLock parameter, and updated documentation with some notes on Mandatory Profile use.


Return to Index