A lot of changes have happened with MCSIO architecture since my colleague Rakesh Kumar published a three-part blog series on MCSIO in 2016 (see parts 1, 2, and 3). MCS provisioning has since extended its reach into public clouds, including Azure, AWS, and Google Cloud Platform

I thought it was time to look at some of the changes and provide implementation guidance. This post is the first in a series about the persistent write-back cache for the MCS pooled catalog in Azure. I’ll start by diving deep into the most hardcore way to enable this: PowerShell. Later, I’ll cover other methods and look at cost and how to improve performance.

My goal with this post is to help you to understand how to create an MCS machine catalog in Azure with persist write back cache enabled for any version of XenApp and XenDesktop or Citrix Virtual Apps and Desktops that supports this feature.

Unlike the on-prem configuration, the write cache disk in Azure by default will not be persistent. As you can see here, as of mid-April 2020, the PowerShell method is the only supported method to create an MCS machine catalog with persist write back cache enabled in Azure. In the documentation, you’ll see an example of how to use PowerShell to create a new ProvScheme.

But hold on, what is a “ProvScheme” and how is that tied to a machine catalog?

The challenge here is that you cannot simply bind a new ProvScheme to an existing catalog. If you must create a new ProvScheme via Powershell, you also have to create the catalog via PowerShell.

If you read the full PowerShell dump when you use Studio to create an MCS machine catalog, you will notice that there are at least 12 other steps required during the creation of an MCS catalog. This is considerably more complicated than it seems, so let’s take a look at the complete PowerShell command way.

Prerequisites:

  • Prepare a Windows image for MCS to clone in Azure. Note, a VDA (version higher than 7.9, suggest 7.15+) must be installed with MCSIO driver enabled.
  • Pre-create a Resource Group in Azure where you plan to hold your MCS catalog.
  • If you’re using Citrix Cloud, set up Citrix Remote PowerShell SDK on the machine you plan to run the PowerShell.

Step-by-Step Explanation in PowerShell:

You can use the PowerShell ISE to execute the steps below in your test environment (or the way you prefer).

Load the Citrix snap-ins.

ASNP Citrix*

Authenticate to your Citrix Cloud instance (only if you are using Citrix Cloud).

Get-XDAuthentication

Create a new Machine Catalog. You can run a Get-BrokerCatalog first to check the ZoneUid associated with other Catalogs.

New-BrokerCatalog -Name "MC-Persistwbc" -AllocationType "Random" -PersistUserChanges "Discard" -ProvisioningType "MCS" -SessionSupport "SingleSession" -ZoneUid "XXX"

Please note, the ZoneUid will be something that looks like like “4f8668ff-22cd-4445-8cef-46531eb538b6.” If you only have one Zone in your site, you can omit this parameter in the command.

Define the naming scheme and OU placement for the provisioned machines associated with the new catalog.

New-AcctIdentityPool -Domain "<yourdomain.com>" -IdentityPoolName "MC-Persistwbc"-NamingScheme "CTX-MCS-###" -NamingSchemeType "Numeric" -OU "CN=Computers,DC=yourdomain,DC=com"

Define a new provisioning scheme that includes the custom property “PersistWBC” value set to true to retain the write back cache disk. You can run a Get-ProvScheme from another catalog in your Azure environment first to determine what the hosting unit, master image VM, network, and service offering values should be.

New-ProvScheme
-AdminAddress "<FQDN of your DDC>:80" -CleanOnBoot '
-CustomProperties "<CustomProperties xmlns=”http://schemas.citrix.com/2014/xd/machinecreation” xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Property xsi:type="StringProperty" Name="UseManagedDisks" Value="true" /><Property xsi:type="StringProperty" Name="StorageAccountType" Value="Premium_LRS" /><Property xsi:type="StringProperty" Name="ResourceGroups" Value="XXX" /><Property xsi:type="StringProperty" Name="PersistWBC" Value="true" /></CustomProperties>" '
-HostingUnitName "XXX" '
-IdentityPoolName "MC-Persistwbc" '
-MasterImageVM "XDHyp:\HostingUnits\XXX.vhd" '
-NetworkMapping @{"0"="XDHyp:\HostingUnits\ XXX"} '
-ProvisioningSchemeName "MC-Persistwbc" '
-ServiceOffering "XDHyp:\HostingUnits\XXX" '
-UseWriteBackCache '
-WriteBackCacheDiskSize 40 '
-WriteBackCacheMemorySize 256

After the above command completes (this may take 10-20 minutes), run the following command to get the properties of the newly recreated provisioning scheme and set it to the BrokerCatalog we just created.

$PS = Get-ProvScheme -ProvisioningSchemeName "MC-Persistwbc"
Set-BrokerCatalog -Name "MC-Persistwbc" -ProvisioningSchemeId $PS.ProvisioningSchemeUid

There are a couple of things to keep in mind:

  • If you refresh your Studio before the last two lines are executed, even if you run everything properly, you’ll see an error on your machine catalog saying it doesn’t have a master image associated with it.
  • I purposely did not capture the output of those three new cmdlets so that you can see in the output whether the object has been properly created and can adjust or troubleshoot as needed.

At this point, you should be able to see the newly created “MC-Persistwbc” Catalog in Studio and you can Add Machines to it.

Here’s a real example that you may reference:

######################################################################
# Script to manually create a MCS catalog with Persist WBC in Azure
#
# Note: I will skip the error protection and all the existing object
#       check in this demo script.
#       Make sure you run it from the DDC and are not creating an existing MC

# Define the Machine Catalog Name here
$MachineCatalogName = "MCS-PersistWBC-Azure"
# Create a shortcut
$MC = $MachineCatalogName
# Load Citrix Plug-ins
asnp Citrix*

# Step 1::Create the BrokerCatalog(Machine Catalog) object
New-BrokerCatalog `
-Name $MC `
-AllocationType "Random" `
-PersistUserChanges "Discard" `
-ProvisioningType "MCS" `
-SessionSupport "MultiSession" `
#-ZoneUid "4f8668ff-22cd-4445-8cef-46531eb538b6"
# The ZoneUid parameter will only be needed if you have more than one zone.
# Get it by the following two lines:
# $t = Get-BrokerCatalog <Name of an existing catalog in the same zone>
# $ZoneUid = $t.ZoneUid
# Use the $ZoneUid as the input for -ZoneUid

# Step 2::Create the AcctIdentityPool for the computer accounts
New-AcctIdentityPool `
-Domain "HOMELAB.JEFFQIU.LOCAL" `
-IdentityPoolName $MC `
-NamingScheme "CTX-MCS-###" `
-NamingSchemeType "Numeric" `
-OU "OU=MCS01,DC=HOMELAB,DC=JEFFQIU,DC=LOCAL"

# Step 3::Create the ProvScheme object
New-ProvScheme `
-AdminAddress "JQ-DDC-01.HOMELAB.JEFFQIU.LOCAL:80" `
-CleanOnBoot `
-CustomProperties "<CustomProperties
xmlns=`"http://schemas.citrix.com/2014/xd/machinecreation`" `
xmlns:xsi=`"http://www.w3.org/2001/XMLSchema-instance`">`
<Property xsi:type=`"StringProperty`" `Name=`"UseManagedDisks`" Value=`"true`" />`
<Property xsi:type=`"StringProperty`" Name=`"StorageAccountType`" Value=`"Premium_LRS`" />`
<Property xsi:type=`"StringProperty`" Name=`"ResourceGroups`" Value=`"jeffqLabinAzure`" />`
<Property xsi:type=`"StringProperty`" Name=`"PersistWBC`" Value=`"true`" />`
</CustomProperties>" `
-HostingUnitName "Azure-East-US" `
-IdentityPoolName $MC `
-MasterImageVM "XDHyp:\HostingUnits\Azure-East-US\image.folder\jeffqLabinAzure.resourcegroup\JQ-MCS-GOLD_disk1_c4cbdce712d04e2a8327b619054f26e8.manageddisk" `
-NetworkMapping @{"0"="XDHyp:\HostingUnits\Azure-East-US\\virtualprivatecloud.folder\amgtestrg.resourcegroup\amgtestrg-vnet.virtualprivatecloud\default.network"} `
-ProvisioningSchemeName $MC `
-ServiceOffering "XDHyp:\HostingUnits\Azure-East-US\serviceoffering.folder\Standard_DS1.serviceoffering" `
-UseWriteBackCache `
-WriteBackCacheDiskSize 40 `
-WriteBackCacheMemorySize 256
#-RunAsynchronously
# I remarked this because we need to wait for the ProvScheme to continue

# Step 4::Assign this ProvScheme to the Catalog we just created
$PS = Get-ProvScheme -ProvisioningSchemeName $MC
Set-BrokerCatalog -Name $MC -ProvisioningSchemeId $PS.ProvisioningSchemeUid

Please note, it’s better if you first create an MCS catalog in Azure in the GUI with the exact image and network and VM type first so you can just copy those long complex strings directly from the PowerShell tab of Studio.

Stay tuned for my follow-up posts, where I’ll discuss alternative approaches. Please share your feedback and questions in the comments below.

And a special thanks to Sarah Steinhoff, who created the first version of this PowerShell script, and Yuhua Lu for their guidance and input on this post.

This software / sample code is provided to you “AS IS” with no representations, warranties or conditions of any kind. You may use, modify and distribute it at your own risk. CITRIX DISCLAIMS ALL WARRANTIES WHATSOEVER, EXPRESS, IMPLIED, WRITTEN, ORAL OR STATUTORY, INCLUDING WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NONINFRINGEMENT. Without limiting the generality of the foregoing, you acknowledge and agree that (a) the software / sample code may exhibit errors, design flaws or other problems, possibly resulting in loss of data or damage to property; (b) it may not be possible to make the software / sample code fully functional; and (c) Citrix may, without notice or liability to you, cease to make available the current version and/or any future versions of the software / sample code. In no event should the software / code be used to support of ultra-hazardous activities, including but not limited to life support or blasting activities. NEITHER CITRIX NOR ITS AFFILIATES OR AGENTS WILL BE LIABLE, UNDER BREACH OF CONTRACT OR ANY OTHER THEORY OF LIABILITY, FOR ANY DAMAGES WHATSOEVER ARISING FROM USE OF THE SOFTWARE / SAMPLE CODE, INCLUDING WITHOUT LIMITATION DIRECT, SPECIAL, INCIDENTAL, PUNITIVE, CONSEQUENTIAL OR OTHER DAMAGES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. Although the copyright in the software / code belongs to Citrix, any distribution of the code should include only your own standard copyright attribution, and not that of Citrix. You agree to indemnify and defend Citrix against any and all claims arising from your use, modification or distribution of the code.