Citrix XenDesktop 7.x VDI deployment with PowerShell using vSphere, local storage and PVS

At a customer a while back we had an Citrix XenDesktop 7.9 environment. VMware vSphere 6.0 was used as hypervisor, Citrix Provisioning Services 7.9 for deployment and Microsoft Windows 10 as OS for the virtual desktops. Since these desktops were non-persistent we were able to use the local solid state storage in the hypervisors. This did however present some challenges when it came to the deployment of the virtual desktops. We (my colleague Leon van Efferen and myself) ended up with a PowerShell script that did just about everything.

In this post I will explain what the script does and what you need to do to use it in your own XenDesktop/PVS/vSphere environment. You can find the actual script at the end of the post.
Keep in mind that the customer used VMware vSphere (XenServer or Hyper-V were a big no-no for unknown reasons) and therefore the script only contains the commands for vSphere (PowerCLI 6.x). If you would like to use it for other hypervisors, feel free to alter it in any way and present it as your own on your own blogsite.

How and why:
When deploying virtual desktops with Citrix Provisioning Services you first need to create the virtual machines on your hypervisor. This includes deploying them from a template, create devices (based on the MAC address) in Provisioning Service, add the correct vDisk to the devices, create computer accounts in Active Directory and add them to a XenDesktop Machine Catalog.
PVS presents you with two wizards to help you with these tasks. The Streamed VM Wizard and the XenDesktop Setup Wizard. The difference between the two is that de latter one will also add the machine to a Machine Catalog in your XenDesktop site.
While these wizards are very powerful and should be your first choice for deploying your virtual desktops, they unfortunately did not fit our needs. I will try to explain why.
The mentioned wizards require a template from which to create the virtual machines. Since we are using PVS this is just an empty template with the correct virtual hardware configuration, and (if you use Cache in memory with overflow to disk) a local (formatted) drive. This template should be available for all hypervisor hosts and therefore should be on shared storage. The wizards however deploy the resulting virtual machine on the same storage as the template. This would mean that all our virtual machines end up in shared storage which is something we didn’t want or need.

So our only options were to do everything manually or automate it with PowerShell. For obvious reasons we chose the latter and this was actually a fun thing to do. As I have said before in other posts: I am in no way a PowerShell expert and usually go by the rule ‘If it looks stupid but it works, it ain’t stupid’, so keep that in mind.

Because the wizards also added the Boot Device Manager partition to the VM’s we needed to create a template that already includes the BDM partition.
(Check this excellent blog by George Spiers for more information about the various boot methods of PVS.)

Basically the goals were as follows:
– Deploy the virtual desktops on local storage from a template on shared storage
– Add the virtual desktops to PVS with the correct vDisk
– Add the virtual desktops to a XenDesktop Machine Catalog
– Add computer accounts to Active Directory for the virtual desktops
– Choose the least used hypervisor and the least used network

Unfortunately we had multiple networks configured in vSphere with one being smaller than the rest (/23 subnet instead of /22). This meant that getting the least used network based on the amount of machines in each network wouldn’t work so we used percentages along with the maximum network size instead.

Script information:
Like I have said before, this script is not a one-size-fits-all (or one-script-automates-all) solution, so you would need to alter it to accommodate your environment. There are a lot of variables that need to be changed. I have commented these with REPLACE THIS! and REPLACE THIS IF NEEDED! notices. I have tried to make all the other comments and variables as easy to understand as possible so a experienced Citrix and vSphere administrator shouldn’t have any problem filling this out.

So save the script as ps1 file. Change all the variables and run it. It will ask you what kind of virtual machine you want to create (Acceptance or Production, if you have that kind of setup) and how many virtual machines you want. It will provide an overview of what it will do for you and, after confirmation, will start deploying. During deployment it will skip virtual machine names that already exist. So if there are some missing in your overall numbering, it will fill in the missing ones.
Keep in mind that it will use the local storage of your hypervisor hosts. If there are multiple local datastores, it will use the one with the most space available.

Known issues so far:
There was one known issue when using this script. When creating the virtual machine on vSphere, it will actually do this against the hypervisor host itself. It will take a while (20 to 60 seconds) for vCenter to notice there is a new VM on the host. Only after that can you add it to a XenDesktop Machine Catalog. To work around this it will try adding it three times with 30 seconds interval (continuing if it is successful of course).
The script also contains a password it plain text. I know this isn’t the smartest thing to do, but hey, I was just lazy. Feel free to add a credential prompt.

Wrapping things up:
That’s it again for now. Feel free to use this script, alter it, publish it. If you have any tips or improvements, I would be happy to hear them.
Next up is another script that I created for another customer to update virtual desktops through Machine Creation Services (without doing it from Citrix Studio).

The actual script:

 15,492 total views,  1 views today

12 thoughts on “Citrix XenDesktop 7.x VDI deployment with PowerShell using vSphere, local storage and PVS

  1. nava chou

    This is great.
    That’s what I understand.
    However, it seems that there are still some differences with XDSW, which is exactly what I am confused about.
    For example, to copy a virtual machine from a template, it is clear that PVS do not simply perform ‘new-vm’.
    PVS XDSW will not copy the disk whether or not the template has one, and ‘new-vm’ will.
    XDSW will copy the template first, then use the copied template as the template to create the virtual machine, and then delete the template.
    There are other differences from your script.
    Can you tell me more about what you know
    Thanks a lot

    1. Chris Jeucken Post author


      Yes, indeed there are differences. We didn’t really look into how XDSW handles the templates, but the results were that the created machines ended up in the shared storage where the template is stored. The goal was to put the machines on the local storage of the specific hypervisor host.
      We asked Citrix as well as Atlantis about how we should do this and both told us you would need to script it.
      So that is what we did.

      How did you found out that XDSW first copies the template? I didn’t notice it when playing around with this last year.


    1. chrisadm Post author

      Nee, helaas. Maar je weet dat je de PowerShell commando’s kunt inzien?
      Voeg bijv. nieuwe machines toe aan een catalog en kijk vervolgens in het bovenste menu van Citrix Studio onder het tabblad PowerShell.
      Dan zie je de commando’s die gebruikt zijn voor deze handeling en deze kun je vervolgens in je script opnemen.

      Heel concreet krijg je dan zoiets:
      $Log = Start-LogHighLevelOperation -AdminAddress xddc01.local.lan -StartTime "1/2/2019 10:13:06 AM" -Text "Adds 1 Machines to Machine Catalog 'Pool 01'"
      $Pool = Get-AcctIdentityPool -AdminAddress xddc01.local.lan -IdentityPoolName "Pool 01" -MaxRecordCount 2147483647
      Set-AcctIdentityPool -AdminAddress xddc01.local.lan -AllowUnicode -Domain "local.lan" -IdentityPoolName "Pool 01" -LoggingId $

      Get-AcctADAccount -AdminAddress xddc01.local.lan -IdentityPoolUid $Pool.IdentityPoolUid -Lock $False -MaxRecordCount 2147483647 -State "Available"
      New-AcctADAccount -AdminAddress xddc01.local.lan -Count 1 -IdentityPoolUid $Pool.IdentityPoolUid -LoggingId $
      Get-ProvScheme -AdminAddress xddc01.local.lan -MaxRecordCount 2147483647 -ProvisioningSchemeName "Pool 01"

      $VM = New-ProvVM -ADAccountName @("LOCAL\VDI0104$") -AdminAddress xddc01.local.lan -LoggingId $ -ProvisioningSchemeName "Pool 01" -RunAsynchronously
      Lock-ProvVM -AdminAddress xddc01.local.lan -LoggingId $ -ProvisioningSchemeName "Pool 01" -Tag "Brokered" -VMID @($VM.VMId)

      New-BrokerMachine -AdminAddress xddc01.local.lan -CatalogUid 4 -MachineName "VDI0104.local.lan"

      Stop-LogHighLevelOperation -AdminAddress xddc01.local.lan -EndTime "1/2/2019 10:13:25 AM" -HighLevelOperationId $ -IsSuccessful $True

      Laat maar even weten of je daar iets aan hebt, anders kan ik wel iets meer uitgebreid tikken.

      1. seref

        Bedankt voor je uitleg, als je tijd en zin hebt iets meer info zal voor mij heel handig zijn.


        1. chrisadm Post author

          Ja, dat is goed. Al is het wel handig om te weten wat je doel precies is. Wat wil je automatiseren?
          Dit omdat het bij MCS al heel erg geautomatiseerd is.


  2. navy

    This is very useful, I have written similar script, of course, there are some flaws like said above.And I always wanted to know how to create a partition for BDM with powershell and make it work.Do you have any advice for me?

    1. chrisadm Post author


      Sorry for the late reply:
      I actually used the XenDesktop Setup Wizard in the PVS Console to create a single machine with a BDM partition and used that to create a template in vSphere.
      That template is used by my script to deploy all the machines and in that way every machine will get the BDM partition.
      So I don’t have any script for you to create the partition.


  3. Mark

    Hello Chris,
    Thank you for sharing your script for creating a MCS Catalog for PVS. I am trying to automate my Citrix Home lab to automatically create the MCS catalog for MCS but due to not being very good with Powershell I am trying to find a script and came across your post.

    I have looked at some of the examples on Citrix’s own SDK site but I don’t know how to put everything together, I even looked into using the Powershell commands within Studio but haven’t been able to put together a script that will create a new Catalog and VMs without errors.

    Would you be able to share your immense Powershell knowledge and some day when you have time please post a script for some of us novices to learn how to automate things in Citrix.


    1. Chris Jeucken Post author


      Sadly I don’t have a script lying around to create a new MCS catalog. I would have to create that so I will add that to my todo list.
      I do have one that deploys a new snapshot to all the VMs in an existing MCS catalog (basically an automated version of ‘Update machine’).


  4. Mark

    Hello Chris,
    Thank you for your reply. I managed to find a basic script which I was able to change things around by trial and error and got it working for Desktops but it is not working for Servers/Virtual Apps.

    Yes, I am in search for a good script which can take a new snapshot to an existing pool of non-persistent desktops and servers. Ideally, what I would like to test is be able to run the script on a monthly schedule.



Leave a Reply

Your email address will not be published. Required fields are marked *