Updated Hyper-V Clone from Disk Script

Back in 2015 I wrote a PowerShell script, which has a GUI, to create new Hyper-V VMs from existing VHD and VHDX files. The original blog post, “Poor man’s Hyper-V cloning from VHD/VHDX”, is available here.

Now that I’ve finally got a Windows 10 laptop with Hyper-V capability, I’ve made a few additions to the script since I’m using Hyper-V, and thus the script, pretty much daily now. For example, I have SysPrep’d Windows 10 and Server 2016 disks so I can quickly create new fresh VMs simply by right or double clicking on the relevant VHDX file in explorer. If you select the linked clone option, so the whole source disk does not have to be copied, the creation, and optional automatic starting, takes only a few seconds.

These enhancements include:

  1. Install (and uninstall) option to integrate into explorer’s right click menu without having to go near the registry yourself (apparently it scares some people!).
  2. Addition of a notes field which will go into the notes for the VM, if specified.
  3. Option to hide the parent PowerShell script window so it looks cleaner although may make any errors more difficult to track down.

I hope you find it as useful as I do.

The updated script is available here.

When even Process Monitor isn’t enough

I was recently tasked to investigate why an App-V 5.1 application was giving a license error at launch on XenApp 7.8 (on Server 2008R2) when the same application installed locally worked fine. I therefore ran up the trusty Process Monitor (procmon) tool to get traces on the working and non-working systems so I could look for differences. As I knew what the licence file was called, I honed in quickly on this in the traces. In the working trace, you could see it open the licence file, via a CreateFile operation, and then read from the file. However, in the App-V version it wasn’t reading from the file (a ReadFile operation) but no CreateFile operation was failing so I couldn’t understand why it wasn’t even attempting to read from the file when it didn’t appear to be unable to access it. The same happened when running as an administrator so it didn’t look like a file permission issue.

Now whilst procmon is a simply awesome tool, such that life without it would be an unimaginably difficult place, it does unfortunately only tell you about a few of the myriad of Microsoft API calls. In order to understand even more of what a process is doing under the hood, you need to use an API monitor program that has the ability to hook any API call available. To this end I used WinAPIOverride (available here). What I wanted was to find the calls to CreateFile for the licence file and then see what happened after that, again comparing good and bad procmon traces.

WinAPIOverride can launch a process but it needs to be inside the App-V bubble for the app in order for it to be able to function correctly. We therefore run the following PowerShell to get a PowerShell prompt inside the bubble for our application which is called “Medallion”:

$app = Get-AppvClientPackage | ?{ $_.Name -eq 'Medallion' };
Start-AppvVirtualProcess -AppvClientObject $app powershell.exe

We can then launch WinAPIOverride64.exe in this new PowerShell prompt, tell it what executable to run and then run it:

winapioverride-launch

Note that you may not be able to browse to the executable name so you may have to type it in manually.

Once we tell it to run, it will allow us to specify what APIs we want to get details on by clicking on the “Monitoring Files Library” button before we click “Resume”.

api-monitor-hook

You need to know the module (dll) which contains the API that you want to monitor. In this case it is kernel32.dll which we can glean from the MSDN manual page for the CreateFile API call (see here).

api-monitor-kernel32

Whilst you can use the search facility to find the specific APIs that you want to monitor and just tick those, I decided initially to monitor everything in kernel32.dll, knowing that it would generate a lot of data but we can search for what we want if necessary.

So I resumed the process, saw the usual error about the licence file being corrupt, stopped the API monitor trace and set about finding the CreateFile API call for the licence file to see what it revealed. What I actually found was that CreateFile was not being called for the licence file but when I searched for the licence file in the trace, it revealed that it was being opened by a legacy API called OpenFile instead. Looking at the details for this API (here), it says the following:

you cannot use the OpenFile function to open a file with a path length that exceeds 128 characters

Guess how long the full path for our licence file is? 130 characters! So we’re doomed it would seem with this API call which we could see was failing in API monitor anyway:

medallion-open-file

I suspect that we don’t see this in procmon as the OpenFile call fails before it gets converted to a CreateFile call and thence hits the procmon filter driver.

The workaround, as we found that the installation wouldn’t work in any other folder than c:\Medallion so we couldn’t install it to say C:\M, was to shorten the package installation root by running the following as an admin:

Set-AppvClientConfiguration -PackageInstallationRoot '%SystemDrive\A'

This changes the folder where App-V packages are cached from “C:\ProgramData\App-V” to “C:\A” which saves us 18 characters. The C:\A folder needed to be created and given the same permissions and owner (system) as the original folder. I then unloaded and reloaded the App-V package so it got cached to the \A folder whereupon it all worked properly.

Exporting validated shortcuts to CSV file

In a recent Citrix XenApp 7.x consulting engagement, the customer wanted to have a user’s start menu on their XenApp desktop populated entirely via shortcuts created dynamically at logon by Citrix Receiver. Receiver has a mechanism whereby a central store can be configured to be used for shortcuts such that when the user logs on, the shortcuts they are allowed are copied from this central share to their start menu. For more information on this see https://www.citrix.com/blogs/2015/01/06/shortcut-creation-for-locally-installed-apps-via-citrix-receiver/

Before not too long there were in excess of 100 shortcuts in this central store so to check these individually by examining their properties in explorer was rather tedious to say the least so I looked to automate it via good old PowerShell. As I already had logon scripts that were manipulating shortcuts, it was easy to adapt this code to enumerate the shortcuts in a given folder and then write the details to a csv file so it could easily be filtered in Excel to find shortcuts whose target didn’t exist although it will also output the details of these during the running of the script.

I then realised that the script could have more uses than just this, for instance to check start menus on desktop machines so decided to share it with the wider community.

The get-help cmdlet can be used to see all the options but in its simplest form, just specify a -folder argument to tell it where the parent folder for the shortcuts is and a -csv with the name of the csv file you want it to write (it will overwrite any existing file of that name so be careful).

It can also check that the shortcut’s target exists on a remote machine. For instance, you can run the script on a Citrix Delivery Controller but have it check the targets on a XenApp server, via its administrative shares, by using the -computername option.

If you run it on a XenApp server with the “PreferTemplateDirectory” registry value set, use the -registry option instead of -folder and it will read this value from the registry and use that folder.

If you’re running it on a desktop to check that there are no bad shortcuts in the user’s own start menu, whether it is redirected or not, or in the all users start menu then specify the options -startmenu or -allusers respectively.

Finally, it can email the resultant csv file via an SMTP mail server using the -mailserver and -recipients options.

The script is available for download here.

Poor man’s Hyper-V cloning from VHD/VHDX

If you use Server 2012 Hyper-V but don’t have the luxury of System Center Virtual Machine Manager to do provisioning of new virtual machines for you then I offer here a PowerShell script, with GUI, that will do it for you from a master VHD/VHDX. I’ll also show you how to integrate it into explorer so you can just right click on a VHD/VHDX file and clone it from there.

I use Hyper-V at home and have SysPrep’d VHDs of all the Operating Systems I typically use but let’s not get into the debate, started by one Mark Russinovich, as to whether we actually need to SysPrep anymore – I’m old school so I do it out of habit more than anything.

So what we need to do to use an existing VHD to create a new VM is:

  1. Copy the VHD/VHDX to a new file or create a new differencing disk from it (aka a linked clone)
  2. Create a new VM with the new VHD/VHDX file as its disk
  3. Connect the VM to a network (optional)
  4. Start the VM (optional)

We start this process by right clicking the VHD that we want to copy in explorer:

Right click vhd

and selecting the “Create VM” option which is a registry key I’ve created, which  we’ll cover later, that runs the PowerShell script with the VHD/VHDX file as one of the arguments.

This then gives the user interface constructed on the fly by PowerShell:

hyper-v vhd cloner

All we have to do at this point if we are happy with the defaults is to enter the new virtual machine name and either click the “Create” button or hit Alt C or enter. Note that the VHD/VHDX destination folder is pre-populated with my personal default so I don’t have to type in or use the folder browser – this is done via the registry value we’ll see later and we can set other defaults in there too if we wish. The name of the new VHD/VHDX file will be the machine name that you have entered above or with a “- <number>” suffix if you create more than one VM at a time. If the destination VHD/VHDX file already exists then an error will be shown unless the “-force” option is specified which will cause the VHD/VHDX to be overwritten so use it wisely.

Depending on your storage, the file copy for a non-linked clone may take a while but you’ll find a PowerShell window behind the GUI with some rudiments of a progress indicator in there. You will also get a message box upon completion unless you specify the -quiet switch.

cloned ok

Also, if you run as an administrator but with UAC enabled (what I like to call the “sensible” option when running as an administrator (which I avoid as much as I can anyway)), the script will detect this and run itself again, but elevated, so you should expect to see a UAC elevation prompt. Without it elevated, it will probably fail due to lack of permission.

I’ve tested it just on Server 2012R2 English with PowerShell 4.0 and it certainly works reliably for me but I thought I’d share it lest it helps anyone else save time when creating new VMs from VHD/VHDX files. It won’t work on Server 2008/2008 R2 as they don’t have PowerShell support for Hyper-V (out of the box anyway).

It’s quick to use to as it has been designed to be used via the keyboard so you can tab through the fields and hit “enter” to start the creation process at any point. There are also keyboard accelerators – activated by hitting the “Alt” key. Hitting the escape key will quit immediately.

Note that it won’t work with AVHD/AVHDX files or snapshots as the disk cloning is done completely outside of Hyper-V – it just uses the Hyper-V PowerShell cmdlets to check if a VM of the name you entered exists already and if not to create a new VM, set the generation and number of processors and start it if requested.

The script can be downloaded here and is used entirely at your own risk. Any error messages will be displayed in a message box.

To integrate it into explorer, create a new key with the name you want in your right click explorer menu (mine is “Create VM” as shown above) in “HKEY_CLASSES_ROOT\Windows.VhdFile\shell”. In the key you create, create another key called “command” and set the default value in this “command” key to be something like this (obviously substituting your preferred default destination folder for my G: drive folder example or just leave out the -Folder option if you are happy to always enter or browse to a folder):

powershell.exe -command “& ‘c:\scripts\Clone VHD.ps1’ -Verbose -ShowUI -Folder \”G:\Hyper-V\Hyper-V Hard Drives\” -SourceVHD \”%1\”

So it looks like this in regedit – make sure you get all the single and double quote marks correct otherwise spaces in any argument will stop it working:

vhd association

A .reg file can be downloaded here – just change the path in it to wherever you save the PowerShell script and the argument to the -Folder switch to your default folder for Hyper-V hard drives to be stored.

The script can also be run without the GUI in a PowerShell session, e.g.:

& ‘c:\scripts\Clone VHD.ps1’ -SourceVHD “c:\folder\source.vhdx” -Name “My new VM” -Switch “External virtual switch” -Start -LinkedClone -Folder “d:\hyper-v\hyper-v hard drives”

where you need to change paths and virtual switches to match your system. Full help is available for it via Get-Help.

If the script won’t run due to the PowerShell execution policy then run “Set-ExecutionPolicy -ExecutionPolicy RemoteSigned” as an administrative user but please understand the implications of this before doing so. If it still won’t set the execution policy because of group policy then as an administrator change the “ExecutionPolicy” value in “HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell” to “RemoteSigned” although this is only a temporary workaround as it will eventually reapply the original value due to group policy refresh.