by Dennis Span, CTA
Learn how to configure Citrix StoreFront multi-site aggregation with PowerShell. This is a must for complex enterprise environments, since the StoreFront console cannot be used for advanced configurations.
The Citrix StoreFront version used in this article is 3.13 (released in Q4 2017), running on Windows Server 2016 version 1607. The words site and farm are used interchangeably in this article; they both have the same meaning.
In older versions of StoreFront, you had to manually modify the web.config file located in the directory C:\inetpub\%IISDirectory%\Citrix\%StoreName% to be able to configure advanced settings. In the latest StoreFront versions, this is no longer necessary, since all necessary PowerShell cmdlets are now available.
To better understand multi-site aggregation, please see the following articles by CTP Carl Stalhood and CTP George Spiers:
- StoreFront 3.5 through 3.13 – Configuration for NetScaler Gateway (in the section Configure Icon Aggregation and Home Sites).
- StoreFront High Availability, Icon Aggregation and Optimal Routing (in the section StoreFront icon aggregation).
Some other interesting articles I recommend you to read are:
- Citrix blog: StoreFront Multi-Site Settings: Some Examples
- Citrix blog: StoreFront Multi-Site Settings Part 2
- Citrix docs: Set up highly available multi-site stores
For detailed information on all StoreFront cmdlets, please see the Citrix StoreFront SDK.
Note: multi-site aggregation only works when the store contains at least two sites! |
When a user connects to a store configured with multiple sites, by default, all resources from all sites are enumerated and displayed to the user. This default behavior may be undesirable for a couple of reasons, for instance:
- The sites configured in the same store may be located differently geographically; one site may be located in Europe and the other in the US. In this case, you may want to define a preferred site (home site) for the user to connect to and only in case of a problem should the user receive resources (published applications) from the second site. So the user in Europe, by default, will always connect to the site in Europe. Only in the event of a problem will the user receive the published applications from the XenDesktop site in the US.
- The sites may contain duplicate resources and you do not want the user to see a published application such as “Microsoft Word” or “Adobe Acrobat Reader” twice. In this case, you would like to de-duplicate resources with the same published application name. De-duplication means that a published application that is available in multiple sites is only displayed to the user once.
- You may be running an environment in one data center, but based on a pod architecture. A pod architecture is where you create multiple independent XenDesktop sites (= pods) instead of one single XenDesktop site. If one XenDesktop site goes down, the others are still up and available. A user should only be connected to one site (“pod”) at a time based on a load-balancing (“round-robin”) approach.
As stated in the Citrix product documentation, the StoreFront console does not allow an administrator to configure all possible multi-site aggregation configurations. The following, more advanced configurations, can only be configured using PowerShell or by directly modifying the web.config file of the store:
- The ability to specify multiple groupings of deployments for aggregation.
- The management console allows only a single grouping of deployments, which is sufficient for most cases.
- For stores with many deployments with disjointed sets of resources, multiple groupings might give performance improvements.
- The ability to specify complex preference orders for aggregated deployments. The management console allows aggregated deployments to be load balanced or to be used as a single failover list.
- The ability to define disaster recovery deployments (deployments accessed only when all other deployments are unavailable). These are the backup farms.
The complete PowerShell script, with minimal logging and no error-handling, to configure multi-site aggregation and user mapping looks like this:
##########################################
# Create a multi-site aggregation set and map user groups
##########################################
# Variables [edit]
# - # The IIS site ID. If you only have one site ("Default Web Site"), the site ID is 1
[int]$IISSiteID = 1
# - # The virtual path to the StoreFront store in the specific IIS site (e.g. "/Citrix/MyStore")
[string]$StorePath = "/Citrix/MyStore"
# - # The unique name used to identify the new equivalent farm set (e.g. "FarmSet1")
[string]$EquivalentFarmsetName = "FarmSet1"
# - # The name of the aggregation group (e.g. "AggregationGroup1").
[string]$AggregationGroupName = "AggregationGroup1"
# - # The sites you want to aggregate (enter at least two farms/sites)
[string[]]$PrimaryFarms = "MySite1","MySite2"
# - # The backup site(s) in case the main sites fail. Leave this value blank ("") if you have no backup farm
[string[]]$BackupFarms = "MyBackupSite1","MyBackupSite2"
# - # Load balancing or fail-over. Possible values are 'Failover' or 'LoadBalanced'
$LoadBalanceMode = "LoadBalanced"
# - # The sites that are aggregated are 100% identical or not. Possible values are either '$true' or '$false'[bool]$FarmsAreIdentical = $True
# - # The AD group(s) you want to bind to the equivalent farm set
[string[]]$ADGroupNames = "usrsCTX","Domain Users"
# - # The unique name used to identify the UserFarmMapping
[string]$FarmMappingName = "FarmMapping$(Get-Random)"
Write-Host "Create a multi-site aggregation set and map user groups"
Write-Host ""
# Connect to the store
Write-Host "Connect to the store (IIS site ID $IISSiteID; store path '$StorePath')"
$store = Get-STFStoreService -siteID $IISSiteID -VirtualPath $StorePath
# Create the equivalent farm set
Write-Host "Create the equivalent farm set '$EquivalentFarmsetName'"
$FarmSet = New-STFEquivalentFarmset -Name $EquivalentFarmsetName -AggregationGroupName $AggregationGroupName -PrimaryFarms $PrimaryFarms -LoadBalanceMode $LoadBalanceMode -FarmsAreIdentical $FarmsAreIdentical
# 1) Retrieve the SID for each AD group defined in the variable $ADGroupNames
# 2) Add the group name and the group's SID to a hash table ('dictionary object')
Write-Host "Retrieve the SID for each AD group and add the SID to the hash table"
$UserMappingGroups = @{}
Foreach ( $ADGroup in $ADGroupNames ) {
[string]$SID = (New-Object System.Security.Principal.NTAccount($ADGroup)).Translate([System.Security.Principal.SecurityIdentifier]).value
Write-Host " -The SID for the AD group $ADGroup is $SID"
$UserMappingGroups.Add($ADGroup,$SID)
}
# Map the AD group(s) to the equivalent farm set
Write-Host "Map the AD groups (stored in the hash table) to the newly created equivalent farm set"
Add-STFUserFarmMapping -StoreService $store -Name $FarmMappingName -GroupMembers $UserMappingGroups -EquivalentFarmSet $FarmSet
Write-Host ""
Write-Host "End of script"
Copy the above script to a new PS1 file (e.g. C:\Temp\Create multi-site aggregation set and map users.ps1) and execute the script:
powershell.exe -executionpolicy bypass -file “C:\Temp\Create multi-site aggregation set and map users.ps1”
The PowerShell script consists of four parts:
1) Define the variables
The following variables are required:
- $IISSiteID: the IIS site ID. If you only have one site (“Default Web Site”), the site ID is 1. The data type of this variable is integer ([int]).
- $StorePath: the virtual path to the StoreFront store (e.g. “/Citrix/MyStore”). The data type of this variable is string ([string]).
- $EquivalentFarmsetName: the name of the new equivalent farm set (e.g. “FarmSet1”). This name must be unique. The data type of this variable is string ([string]).
- $AggregationGroupName: the name of the aggregation group (e.g. “AggregationGroup1”). This name can span multiple equivalent farm sets, so it does not have to be unique per farm set. The data type of this variable is string ([string]).
- $PrimaryFarms: the names of the sites that need to be aggregated (e.g. “MySite1″,”MySite2”). You cannot specify less than two sites (you can specify more than two). Also make sure that the site names are the same as configured on the store service. And one more thing, if you configure fail-over instead of load balancing (see below), the order of the sites depends on the order how the sites are set in the variable $PrimaryFarms. The data type of this variable is string array ([string[]]).
- $BackupFarms: the name of the backup site (e.g. “MyBackupSite1″,”MyBackupSite2”). Leave this value blank (“”) if you have no backup farm. The data type of this variable is string array ([string[]]).
- $LoadBalanceMode: possible values are Failover or LoadBalanced.
- $FarmsAreIdentical: whether the sites in the equivalent farm set are 100% identical or not. Possible values are either ‘$true’ or ‘$false’. The data type of this variable is boolean ($true or $false) ([bool]).
- $ADGroupNames: the AD group(s) that should be mapped/bound to the equivalent farm set. You can enter one ore more AD groups and with or without specifying the domain (e.g. “MyDomain\ADGroup1”, “ADGroup2”). The data type of this variable is string array ([string[]]).
- $FarmMappingName: the unique name used to identify the user farm mapping (e.g. “FarmMapping1987254035”). The Get-Random cmdlet generates a random 32-bit number to make sure that the farm mapping name is unique.

2) Connect to the store
Multi-site aggregation and user mapping is configured per store. So the first thing we need to do is to connect to the correct store. For this we need the IIS site ID and the virtual path to the store. Remember, a StoreFront server can have multiple deployments (= IIS sites) and each deployment can have multiple stores (see the article Citrix Storefront Unattended Installation with PowerShell for more information).
$store = Get-STFStoreService -siteID $IISSiteID -VirtualPath $StorePath |
Now that we have a connection to the store we can proceed with the next step and create the aggregation configuration.
The main StoreFront cmdlet used in this code snippet is Get-STFStoreService (see the StoreFront SDK for more information).
3) Create the equivalent farm set
A set of sites (farms) is called an equivalent farm set. To create an equivalent farm set, the following information is required:
- The equivalent farm set name ($EquivalentFarmsetName). You can choose any name you want. This is the unique name for the farm set.
- The aggregation group name ($AggregationGroupName). You can choose any name you want. The aggregation group name is used to connect multiple equivalent farm sets. For example, if you have two equivalent farm sets, but you still want to prevent the user from seeing the same application multiple times, make sure that each of the two equivalent farm sets contains the same aggregation group name.
- The sites ($PrimaryFarms) to be included in the equivalent farm set. The farm names should match those defined in the store service.
- The backup sites in case the sites specified in the equivalent farm set fail. ($BackupFarms).
- The load balance mode ($LoadBalanceMode), which can be set to load balancing or fail-over. Load balancing means that launches are distributed evenly among the available controllers. When fail-over is configured, launches are directed to the first controller specified in the user mapping dialog screen.
- Whether the sites in the equivalent farm set all publish identical resources ($FarmsAreIdentical). Set to true ($true) if all resources are identical on all primary farms. Set to false ($false) if the deployment has some unique resources per farm.
$FarmSet = New-STFEquivalentFarmset -Name $EquivalentFarmsetName -AggregationGroupName $AggregationGroupName -PrimaryFarms $PrimaryFarms -LoadBalanceMode $LoadBalanceMode -FarmsAreIdentical $FarmsAreIdentical |
The main StoreFront cmdlet used in this code snippet is New-STFEquivalentFarmset (see the StoreFront SDK for more information).
4) Create a hash table listing the SID of the AD group(s)
In order to bind one or more AD groups to the equivalent farm set, each AD group has to be added to a hash table. The hash table is then used to create the user mapping. A hash table is an array with a data structure that stores key/value pairs.
The variable $ADGroupNames contains one or more AD groups. The PowerShell snippet below loops through each group defined in $ADGroupNames and uses the NTAccount.Translate method to retrieve the SID. The key/pair value is then written to the hash table stored in the variable $UserMappingGroups. The key is the name of the AD group; the value is the SID.
$UserMappingGroups = @{}
Foreach ( $ADGroup in $ADGroupNames ) {
[string]$SID = (New-Object System.Security.Principal.NTAccount($ADGroup)).Translate([System.Security.Principal.SecurityIdentifier]).value
$UserMappingGroups.Add($ADGroup,$SID)
}
The contents of the hash table is mapped to the equivalent set and is not made visible. If it would be visible it would look something like this:

You can also use the PowerShell cmdlet Get-ADGroup to retrieve the SID of the AD group, but there are some disadvantages. One of them is that you either have to install or at least import the Active Directory PowerShell module. I decided to go with the .Net NTAccount.Translate method, because it does not require the additional installation of any PowerShell modules on any server type (domain controller or otherwise) and it works on all operating systems from Windows Server 2008 R2 and upwards.
5) Map the AD group(s) stored in the hash table to the equivalent farm set (UserFarmMapping)
Now we have arrived at the last step; binding the AD groups stored in the hash table (created in the previous step) to the equivalent farm set. The so-called user farm mapping.
Add-STFUserFarmMapping -StoreService $store -Name $FarmMappingName -GroupMembers $UserMappingGroups -EquivalentFarmSet $FarmSet |
Note: it is possible to bind the same user mapping group (the same hash table) to multiple equivalent farm sets. Simply add multiple farm sets to the parameter –EquivalentFarmSet, like this: -EquivalentFarmSet $FarmSet, $FarmSet2, $FarmSet3 |
The main StoreFront cmdlet used in this code snippet is Add-STFUserFarmMapping (see the StoreFront SDK for more information).
For the sake of completeness, there are two other ways how to map AD groups to the equivalent farm set.
- Use the cmdlet New-STFUserFarmMappingGroup (see the StoreFront SDK for more information). The main purpose of this cmdlet is to create a hash table (as described in step 4). The required input parameters are the name of the AD group and the SID. You have to manually retrieve the SID; this cmdlet does not do this for you. In line with the previous example above, the PowerShell code would be as follows:
Add-STFUserFarmMapping -StoreService $store -Name $FarmMappingName -GroupMembers (New-STFUserFarmMappingGroup -GroupName “Domain Users” -AccountSid “S-1-5-21-3344261976-1517029437-3302833933-513”) -EquivalentFarmSet $FarmSet
In case you would like to add all users you can use the special -AllUsers switch:
Add-STFUserFarmMapping -StoreService $store -Name $FarmMappingName -GroupMembers (New-STFUserFarmMappingGroup -AllUsers) -EquivalentFarmSet $FarmSet - You can add the AD group name and the SID directly in hash table format to the parameter -GroupMembers of the cmdlet Add-STFUserFarmMapping, like this:
Add-STFUserFarmMapping -StoreService $store -Name $FarmMappingName -GroupMembers @{“Domain Users” = “S-1-5-21-3344261976-1517029437-3302833933-513”} -EquivalentFarmSet $FarmSet
You can also add more than one group, like this:
Add-STFUserFarmMapping -StoreService $store -Name $FarmMappingName -GroupMembers @{“MyADGroup” = “S-1-5-21-3344261976-1517029437-3302833933-000″;”Domain Users” = “S-1-5-21-3344261976-1517029437-3302833933-513”} -EquivalentFarmSet $FarmSet
For more information on how to automate the installation and configuration of Citrix StoreFront see the article Citrix Storefront Unattended Installation with PowerShell.
I hope this article was of some help to you.