XenServer PowerShell Automation Series Index

Part 1 – Understanding the Requirements Part 2 – Creating a Custom ISO Part 3 – Unlimited VM Creation Part 4 – Roles, Features, and Other Components


After reviewing and staging the required files and folders in Part 1, it’s time to start the custom ISO creation process. The custom ISO is just one part to the whole, but it is probably the most important. Without the custom ISO, you would just have a bunch of bootless VMs.

To build a custom ISO, you need to start with a full Windows operating system ISO which can be downloaded from an MSDN or Visual Studio subscription. Your Microsoft licensing agreement would also include the necessary product keys for the different OS versions.

This base operating system ISO is part of what is used to create the customized, unattended, installation of an OS and will also be used to create the custom ISO. Each of the files and folders serve their own purpose, which will be discussed in further detail in the following sections along with the ISO creation form itself.

Where the Magic Happens

Upon first launch of AXL, you will get prompted with a choice, (see Figure 1) either to create custom ISO(s), or create VMs.

Figure 1 - First Launch Selection

After selecting to create custom ISO(s), the ISO creation GUI, as shown in Figure 2, will display and is used to define all the information needed to create a custom ISO.

Figure 2 - ISO Creation Form

Responding to each text box and drop down is important to the success of the ISO creation. Below is an explanation of all the fields in the form:

  • Input ISO Location: This specifies the path where the read-only, base ISO (Windows operating system) is located and will be used for the custom ISO creation.

  • Input Target Folder Location: This specifies the destination folder. Everything will be copied to the destination folder including the base ISO content, autounattend.xml, and XenServer Tools

  • Input Autounattended.xml File Location, Input Boot File Location, Input Path to ISO Creation Tool: These three inputs specify the full path to each file and are used in the ISO creation process

  • Input Path to XenServer Tools contents: This specifies the parent folder that contains the expanded XenServer Tools contents

  • Input: Product Key, Admin Name, Admin Password, and Time Zone: All of these fields specify information that is required for, and replaced in, the autounattend.xml file

  • New ISO File Name: This specifies the name of the ISO file you will be creating, NOTE: the file extension is not required in the name

  • Select Edition: This dropdown is used to specify which Windows edition gets installed and should be used in conjunction with the base ISO selected. One of the check boxes for either Windows 10 or Server 2016 must be checked before this field can be enabled.

After each field is populated, you’ll need to click the Validate button to ensure all the information is entered correctly.

If the validation is successful, the create button is then enabled. Each field has its own validation, most of which use regular expressions (regex) to determine validity. In the example above, clicking “Validate” results in an error as shown in Figure 3. It’s important that each field is populated with the appropriate information.

Figure 3 - Validation Error

For the error shown in Figure 3, the product key text box is evaluated with the following regex:


The ISO Construction form, when loaded, will pre-populate some fields depending on where the tool is launched from. If the oscdimg.exe and files are located in subdirectories of where the tool is launched, the paths for them will be automatically pre-populated on launch.

The same goes for the expanded XenServer Tools folder. After marking the check box to have XenServer Tools installed, all subdirectories will be searched, and if the agent is found, the folder path is automatically populated in the text box.

The Custom ISO

After understanding how to use the form and the purpose of the input fields, we can take a look behind the scenes at how the information is used.

The main file that allows for an unattended installation of a Windows operating system is a file called autounattend.xml. This file contains the instructions for how to install the operating system, including the acceptance of the EULA, the product key, the username and password for the administrator account. Different Windows operating systems require different autounattend.xml files since each Windows platform is unique.

I have created sample autounatend.xml files for both Windows Server 2016 and Windows 10 which are both posted on GitHub.

It’s important to note that the name of the file does matter because when loading the ISO, Windows will search specific locations for this file. Check out this Microsoft article for further information.

The next step is to get this information added to a custom ISO. ISOs are read only, so you cannot simply copy a file into it. You can however, copy the contents of an ISO out of it. But then that leads to another problem:

How do I recreate the ISO after I have the contents expanded into a folder? The answer is actually quite simple: oscdimg.exe. Oscdimg can be found in the Windows Assessment and Deployment Kit (ADK), which are available here, or simply download the files from the provided GitHub page earlier.

The only files from the ADK that are needed for this tool are oscdimg.exe and Oscdimg allows the creation of ISOs from the contents of a folder, which is exactly what is needed.

ISO Creation Process Explained

I’ve stepped you through what goes into the ISO and how to appropriately fill out the ISO creation form, but I haven’t really touched on the full process yet.

The ISO creation process is fairly straightforward and Figure 4 provides a visual representation.

Figure 4 - ISO Creation Flowchart

Starting at the top, you’ll need to fill out the ISO Construction form. After all the required fields are complete, the next step will be to click validate, which will then validate each populated field to ensure the ISO creation goes off without a hitch.

Should If a field is not filled in correctly, the tool will indicate which field is wrong and the probable cause. If everything checks out during the validation process, the create button will become enabled. Once you click on “Create”, the process cannot be stopped, so double check each field to ensure accuracy.

After the creation process has begun, the selected base Windows ISO is automatically mounted into the next available drive and the contents will be copied into the target folder location. A progress bar will track the progress of the file copies.

Once the copy of the Windows ISO contents is complete, the autounattend.xml file and XenServer Tools, if selected, will get copied to the target folder location as well. The code snippet for the copy process is shown below:

Function CopyFiles { 
# Specify the Selected ISO and the mount location
$SelectedISO = $ISOPathTextBox.Text 
$MountedImage =  Mount-DiskImage $SelectedISO -PassThru 
$MountLocation = "$(($MountedImage | Get-Volume).DriveLetter):\" 
$MountedFiles = Get-ChildItem $MountLocation -Recurse 
# Specify variables in coordination with the text boxes
$TargetFolder = $TargetFolderTextBox.Text 
$AutounattendXML = $AutounattendPathTextBox.Text 
$AdminPW = $AdminPasswordTextBox.Text 
$AdminAcct = $AdminNameTextBox.Text 
$ProductKey = $ProductKeyTextBox.Text 
$XenToolsPath = $XenToolsPathTextBox.Text 
$Server2016CheckBox = $Server2016CheckBox.CheckState 
$Windows10Checkbox = $Windows10Checkbox.CheckState 
$DropDownEditionSelection = $DropDownEditionSelection.SelectedItem 
$DropDownTimeZone = $DropDownTimeZones.SelectedItem 
     if($MountLocation) {
        Foreach($MountedFile in $MountedFiles) {
            # Copy all contents from the mounted ISO to the target location keeping the same file/folder structure 
            if ($MountedFile.PSIsContainer) {
            Copy-Item $MountedFile.FullName -Destination (Join-Path $TargetFolder $MountedFile.Parent.FullName.Substring($MountLocation.length))
            else {
            Copy-Item $MountedFile.FullName -Destination (Join-Path $TargetFolder $MountedFile.FullName.Substring($MountLocation.length)) 
    # Copy Autounattend.xml file into the root of the ISO
    if($AutounattendXML -and $TargetFolder) {
    Copy-Item $AutounattendXML -Destination $TargetFolder"\Autounattend.xml"
    # Specify which Windows version is being installed
    if($Server2016CheckBox -eq 'Checked') {
    $WindowsEdition = "Windows Server 2016 $DropDownEditionSelection"
    elseif($Windows10Checkbox -eq 'Checked') {
    $WindowsEdition = "Windows 10 $DropDownEditionSelection"
    # Define the contents of the Autounattend.xml file for later modification
    $DefaultXML = Get-Content $TargetFolder"\Autounattend.xml"
        $DefaultXML | Foreach-Object {
            # Replace the contents of the Autounattend.xml file with the information provided
            $_ -replace '1AdminAccount', $AdminAcct `
            -replace '1AdminPassword', $AdminPW `
            -replace '1ProductKey', $ProductKey `
            -replace '1XenToolsPath', $XenToolsPath.Substring($XenToolsPath.LastIndexOf("\")+1) `
            -replace '1Edition', $WindowsEdition `
            -replace '1TimeZone', $DropDownTimeZones
        } | Set-Content $TargetFolder"\Autounattend.xml"
    # If it was specified to install XenServer Tools, copy the parent folder into the target
    if($XenToolsPath) {
    Copy-Item $XenToolsPath -Destination $TargetFolder -Recurse
    if($MountedImage) {
    Dismount-DiskImage $SelectedISO

When the copy is complete, the ISO will be automatically unmounted as it is no longer needed. After unmounting the ISO, the custom ISO creation process begins by integrating the contents of the target folder.

This process usually takes about 3-5 minutes to complete depending on how large the original ISO is. The code snippet for the ISO creation process is shown below:

Function BuildISO {
$SelectedISO = $ISOPathTextBox.Text
$TargetFolder = $TargetFolderTextBox.Text
$NewISOName = $NewISONameTextBox.Text
$BootFile = $BootFilePathTextBox.Text
$ISOTool = $ISOToolPathTextBox.Text
# List of arguments to pass to oscdimg.exe
$ArgumentList = "-b$BootFile -u2 -h -m $TargetFolder $($SelectedISO.Remove($SelectedISO.LastIndexOf("\")))\$NewISOName.iso"
# Display in the form what ISO is being created and where
$ISOCopyProgressLabel.Text = "Creating $NewISOName.iso at $($SelectedISO.Remove($SelectedISO.LastIndexOf("\")))\"
# Create Custom ISO file. This turns the folder that contains the ISO and unattend into a new ISO file
Start-Process -WindowStyle Hidden -FilePath $ISOTool -ArgumentList $ArgumentList -Wait

To read more about the command line switches used with Oscdimg.exe in the $ArgumentList variable, check out these resources online.

After the custom ISO creation process is complete, you have the option to delete the target folder if desired and you can repeat this process as many times as you like.

The custom ISO is created in the same place where the base Windows ISO was stored. If you have an ISO storage repository in XenServer, I would recommend choosing an ISO from there since the new ISO will automatically get created in that location.


With a full understanding of the ISO Construction form and custom ISO creation process, there shouldn’t be anything holding you back from creating your own ISOs; if you haven’t yet downloaded AXL and the associated files, get them from GitHub here.

This is a fairly seamless process and can be used to create ISOs in under 15 minutes. You should have no problems creating an endless number of ISOs to play around with and this automation allows you to repeatedly build lab environments much faster and easier.

As mentioned in the beginning of this series, check out Part 3 where I will be covering the VM creation process.

If you have any questions or want to see how CDA can help your organization, please send us a quick message!

XenServer PowerShell Automation Series Index

Part 1 – Understanding the Requirements Part 2 – Creating a Custom ISO Part 3 – Unlimited VM Creation Part 4 – Roles, Features, and Other Components

  • Facebook
  • Twitter
  • LinkedIn
  • YouTube