I started out using VMWare Workstation before Hyper-V even existed. There were some simple things that I was really surprised were missing from Hyper-V V1 when it came out. Most importantly, copy and paste and smart sizing. Now we are on v3 and we still don’t have these abilities. One alternative is to just RDP into the target machine (or use PowerShell…I know, I know ;)). Well I stumbled onto the fact today that VMConnect is a managed assembly. For some reason I didn’t think this was the case. After cracking it open with Reflector, I realized that the connect functionality is just a hosted RDP OCX. The control just connects to an alternate RDP port. I’m not quite sure if it’s really RDPing to the VM or really just RDPing to an internal component of Hyper-V and they are virtualizing the display. The former seems more likely because the port is accessible on Linux machines and when a VM is booting up. RDP wouldn’t be available in either case. This may be why these particular functionalities haven’t made it into the product, even in the third version.

So, naturally, I ripped open VMConnect and made a PowerShell script that can add Smart Sizing. I’m still working on Clipboard support.

The first step is to load up the VMConnect assemblies and then create a helper class for calling the ConnectionHelper class. This was done to get around an ambigious overload failure.

$ClientAssemblyPath = Split-Path -Path $VMConnectPath -Parent
$ClientAssemblyPath = Join-Path $ClientAssemblyPath "Microsoft.Virtualization.Client.dll"
$ManagementAssemblyPath = Join-Path $ClientAssemblyPath "Microsoft.Virtualization.Client.Management.dll"
Add-Type -Path $ClientAssemblyPath
[Reflection.Assembly]::LoadFile($VMConnectPath) | Out-Null
Add-Type "
    using System;
    using Microsoft.Virtualization.Client;
    using Microsoft.Virtualization.Client.Management;
    public class ConnectHelperEx 
        public static IVMComputerSystem TryGetVirtualMachine(string server, string vmName, out Exception ex)
            IVMComputerSystem vm;
            ConnectionHelper.TryGetVirtualMachine(server, vmName, out vm, out ex);
            return vm;
" -ReferencedAssemblies $ClientAssemblyPath,$ManagementAssemblyPath

Next, I got a hold of the Server and Virtual Machine objects, the VMConnect form and the RDP controls hosted within it. Then I added the private fields using some reflection and Add-Member.

[Exception]$exception = $null
$VM = [ConnectHelperEx]::TryGetVirtualMachine($Server, [string]$VMName, [ref] $exception)
$TS = [Microsoft.Virtualization.Client.Management.ObjectLocator]::GetTerminalService($vm.Server)
$RdpConnectionInfo = New-Object Microsoft.Virtualization.Client.InteractiveSession.RdpConnectionInfo -ArgumentList $Server,$VM,$TS.ListenerPort
$InteractiveSessionForm = New-Object Microsoft.Virtualization.Client.InteractiveSession.InteractiveSessionForm -ArgumentList $RdpConnectionInfo
$InteractiveSessionForm = $InteractiveSessionForm | Add-PrivateField
$RDPViewer = $InteractiveSessionForm.m_RdpViewer | Add-PrivateField
$RdpControl = $RDPViewer.m_RdpClient  | Add-PrivateField

Finally, I setup a couple event handlers and some other settings to get around issues I encountered. The full screen hack doesn’t actually work. The VM won’t take up the full screen. The Resize hack does work. When you pull the handles of the VMConnect window you won’t get scroll bars anymore; the VM’s resolution will smart size. I had to enter my credentials to prevent a dialog from appearing when I connected to the machine.

#Doesn't work
    if ($RDPControl.FullScreen)
        $RDpControl.Size = New-Object System.Drawing.Size -ArgumentList ([System.Windows.Forms.SystemInformation]::VirtualScreen.Width),([System.Windows.Forms.SystemInformation]::VirtualScreen.Height)
    $RDpControl.Size = New-Object System.Drawing.Size -ArgumentList $RDPViewer.Width,$RDPViewer.Height
    $RDpControl.Location = New-Object System.Drawing.Point -ArgumentList 0,0
#So I don't get asked for creds
$RDPControl.UserName = "-" #<-- Actual creds here!
$RDPControl.Domain = "-"
$RDPControl.AdvancedSettings2.ClearTextPassword= "-"
$RDpControl.AdvancedSettings2.SmartSizing = $true
#Doesn't work :(
$RDpControl.AdvancedSettings2.RedirectDrives = $true
$RDpControl.AdvancedSettings5.RedirectClipboard = $true

It’s a pretty neat hack but I wish I could get the clipboard to work.






I’m hoping some one in the community could help get to the bottom of this or that someone from Microsoft will show me why this won’t work. One interesting thing I noticed is the RDP port that VMConnect is “connecting” to is 2179. Using MSTSC to try and connect to that port fails. There is some trickery going on here but I haven’t gotten to the bottom of it…

If anything I think it would be possible to start RDPClip and communicate over a virtual channel manually. I imagine that would be some serious work though.

FYI: I”ve tried starting and restarting RDPClip from within the VM and it doesn’t fix anything.

Download the script here.