19

Connecting to Hyper-V virtual machines with PowerShell

I’ve been using Windows 8 since its pre-release versions and one of the features I like most in it is – Hyper-V. Until Windows 8, Hyper-V was available only as a Server technology. Starting with Windows 8, it is now available out of the box!

In a nutshell, Hyper-V lets you run more than one 32-bit or 64-bit operating system at the same time on the same computer. In Windows 8, this technology is now built into the non-server version of Windows. Client Hyper-V provides the same virtualization capabilities as Hyper-V in Windows Server 2012.

For us, IT Pros, having a virtualized environment nowadays is almost a necessity as many of us need to run multiple operating systems, and maintain multiple test environments.  Hyper-V is an optional feature. You must first enable it.

Note: Client Hyper-V is supported only on 64-bit versions of Windows 8, Pro or Enterprise, having at least 4 GB of RAM,  and requires modern Intel and AMD microprocessors that include Second Level Address Translation (SLAT) technologies.

Enable Hyper-V using the UI

On the Control Panel, click Programs, and then click Programs and Features, click ‘Turn Windows features on or off’, tick the Hyper-V checkbox , click OK, and then click Close.

Enable Client Hyper-V using Windows PowerShell

Open Windows PowerShell and type the following command (which is a part of the Dism module):

Enable-WindowsOptionalFeature –FeatureName Microsoft-Hyper-V -All

To complete installation you need to restart your computer. After restarting the computer, you can use Hyper-V Manager or Windows PowerShell to create and manage virtual machines. You can also use Virtual Machine Connection (vmc) to connect to virtual machines locally or remotely.

Connecting to Virtual Machines

You can connect to your VMs by using the Virtual Machine Connection utility. Notice the warning at the bottom of the dialog. I launched it without administrative privileges and as a result I won’t be able to connect to VMs. Make sure you right click it and open it as an administrator.

That warning is also valid when you use the Hyper-V cmdlets, and the error you get back is misleading; it doesn’t mention required permissions whatsoever. For example, if you run the Get-VM from a non-elevated console:

PS> Get-VM -VMName DC12

Get-VM : The parameter is not valid. Hyper-V was unable to find a virtual machine with name DC12.
At line:1 char:1
+ Get-VM -VMName DC12
+ ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (DC12:String) [Get-VM], VirtualizationInvalidArgumentException
    + FullyQualifiedErrorId : InvalidParameter,Microsoft.HyperV.PowerShell.Commands.GetVMCommand

Alternatively, you can use the Hyper-V Manager. Just right click a VM and then ‘Connect’:

The Hyper-V module for Windows PowerShell

The Hyper-V module for Windows PowerShell includes more than 160 cmdlets to manage Hyper-V virtual machines. The cmdlets  provide an easy way to automate Hyper-V management tasks. Here’s a partial list of the module commands:

PS> Get-Command -Module Hyper-V
CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Cmdlet          Add-VMDvdDrive                                     hyper-v
Cmdlet          Add-VMFibreChannelHba                              hyper-v
Cmdlet          Add-VMHardDiskDrive                                hyper-v
Cmdlet          Add-VMMigrationNetwork                             hyper-v
Cmdlet          Add-VMNetworkAdapter                               hyper-v
Cmdlet          Add-VMNetworkAdapterAcl                            hyper-v
Cmdlet          Add-VMRemoteFx3dVideoAdapter                       hyper-v
Cmdlet          Add-VMScsiController                               hyper-v
Cmdlet          Add-VMStoragePath                                  hyper-v
Cmdlet          Add-VMSwitch                                       hyper-v
Cmdlet          Add-VMSwitchExtensionPortFeature                   hyper-v
Cmdlet          Add-VMSwitchExtensionSwitchFeature                 hyper-v
Cmdlet          Checkpoint-VM                                      hyper-v
Cmdlet          Compare-VM                                         hyper-v
Cmdlet          Complete-VMFailover                                hyper-v
Cmdlet          Connect-VMNetworkAdapter                           hyper-v
Cmdlet          Connect-VMSan                                      hyper-v
Cmdlet          Convert-VHD                                        hyper-v
Cmdlet          Disable-VMEventing                                 hyper-v
(...)

The online reference of the Hyper-V cmdlets in Windows PowerShell can be found here: http://technet.microsoft.com/library/hh848559.aspx

One of the first things I’ve tried when working with Hyper-V was to connect to a VM via PowerShell but I couldn’t find a Connect-VM cmdlet!

Under the hood, Hyper-V Manager is using the vmc utility (vmconnect.exe) to connect to a VM.

Based on the parameters of vmc, I created the Connect-VM advanced function. With Connect-VM, you can connect to a VM, locally or on a remote machine  and even start it, if it isn’t already running. You can pipe VMs you get with Get-VM to it or just specify the VM name(s) or GUIDs. And with a few modifications you can also extend it to launch Remote Desktop instead of Hyper-V.

#requires -Version 3.0
function Connect-VM
{
  [CmdletBinding(DefaultParameterSetName='name')]

  param(
    [Parameter(ParameterSetName='name')]
    [Alias('cn')]
    [System.String[]]$ComputerName=$env:COMPUTERNAME,

    [Parameter(Position=0,
        Mandatory,ValueFromPipelineByPropertyName,
        ValueFromPipeline,ParameterSetName='name')]
    [Alias('VMName')]
    [System.String]$Name,

    [Parameter(Position=0,
        Mandatory,ValueFromPipelineByPropertyName,
        ValueFromPipeline,ParameterSetName='id')]
    [Alias('VMId','Guid')]
    [System.Guid]$Id,

    [Parameter(Position=0,Mandatory,
        ValueFromPipeline,ParameterSetName='inputObject')]
    [Microsoft.HyperV.PowerShell.VirtualMachine]$InputObject,

    [switch]$StartVM
  )

  begin
  {
    Write-Verbose "Initializing InstanceCount, InstanceCount = 0"
    $InstanceCount=0
  }

  process
  {
    try
    {
      foreach($computer in $ComputerName)
      {
        Write-Verbose "ParameterSetName is '$($PSCmdlet.ParameterSetName)'"

        if($PSCmdlet.ParameterSetName -eq 'name')
        {
              # Get the VM by Id if Name can convert to a guid
              if($Name -as [guid])
              {
			Write-Verbose "Incoming value can cast to guid"
			$vm = Get-VM -Id $Name -ErrorAction SilentlyContinue
              }
              else
              {
			$vm = Get-VM -Name $Name -ErrorAction SilentlyContinue
              }
        }
        elseif($PSCmdlet.ParameterSetName -eq 'id')
        {
              $vm = Get-VM -Id $Id -ErrorAction SilentlyContinue
        }
        else
        {
          $vm = $InputObject
        }

        if($vm)
        {
          Write-Verbose "Executing 'vmconnect.exe $computer $($vm.Name) -G $($vm.Id) -C $InstanceCount'"
          vmconnect.exe $computer $vm.Name -G $vm.Id -C $InstanceCount
        }
        else
        {
          Write-Verbose "Cannot find vm: '$Name'"
        }

        if($StartVM -and $vm)
        {
          if($vm.State -eq 'off')
          {
            Write-Verbose "StartVM was specified and VM state is 'off'. Starting VM '$($vm.Name)'"
            Start-VM -VM $vm
          }
          else
          {
            Write-Verbose "Starting VM '$($vm.Name)'. Skipping, VM is not not in 'off' state."
          }
        }

        $InstanceCount+=1
        Write-Verbose "InstanceCount = $InstanceCount"
      }
    }
    catch
    {
      Write-Error $_
    }
  }
}

Usage examples

# Connect to VM and start it

PS> Connect-VM -VMName DC12 -StartVM

2. Connecting to multiple VMs, when multiple connections are made the windows are cascaded. Without it they would sit on top of each other at the same position making it hard to switch from one to another.

PS> Get-VM | Connect-VM

3. Connect using a VM’s Guid

PS> Connect-VM -Id 34d22d46-15c7-4226-9fa2-04f6c90a5a9a -StartVM

You can download the function HERE

Filed in: Articles, Online Only Tags: , ,

19 Responses to "Connecting to Hyper-V virtual machines with PowerShell"

  1. dext3r@hotmail.com says:

    Doesn’t work

  2. SRed says:

    Wow, Connect-VM is fantastic! This should be integrated into the Hyper-V PSModule!

  3. jkavanagh58 says:

    A little frustrating that your PoSH session has to be run as administrator but loving these cmdlets in 2012/Win8. Coming from PowerCLI it is a pretty easy transition.

  4. Japsurd says:

    This won’t work on Server 2012 core. Use FreeRDP instead. https://vmconnect.codeplex.com/releases/view/108284

    • Shay Levy says:

      True, but in my opinion it would be better to invoke rdp from an admin workstation (or any other mmc) to manage core and not by installing a third party application.

  5. Mike Barnes says:

    The underlying vmconnect.exe works.

    Second the motion that Connect-VM ought to be a built-in cmdlet. Why is it not?

  6. Isaac says:

    Does this work with powerShell 4? When I run the script on a Windows 8 client, nothing happens.

  7. Shay Levy says:

    Works fine for me on Windows 8.1.
    Make sure you’re session is elevated (as admin).

    • Isaac says:

      Ran the Powershell as Admin. The script runs without error, but nothing happens. Machine is still off.

      Is there any logging? Are there any modification in the script that is required? I am running: .\Connect-VM -VmName TEST01 -StartVM

      • Isaac says:

        Ran the Powershell as Admin. The script runs without error, but nothing happens. Machine is still off.

        Is there any logging? Are there any modification in the script that is required? I am running: .\Connect-VM -VmName TEST01 -StartVM

        I am using PowerShell 4.0

  8. Dave says:

    I am using this example specifically for connecting to my VM and it works great. Thanks!

  9. Mohammad says:

    Hi,

    how is it possible to include credentials with ssl?

  10. Nemanja says:

    Good job dude, I’m looking for some powershell commands and you provide it…
    God bless

  11. SaschaH says:

    Is it possible to connect to a vmhost other than your local pc?
    I have hyper-v installed on my local environment but need to start up a instance on another vm host.

    I assume that’s where the “…$vm = $InputObject…” line comes in handy.

    Would you be able to please help me with specifying this $InputObject parameter?
    I’m not sure what to put in there…

    Thanks in advance.

    • SaschaH says:

      Sorry, I meant to write:
      “…start up a instance of a VM from another VM host…”

      • SaschaH says:

        I found the solution after some tinkering…:
        I added “… -ComputerName $computer …”to the below section which resolved the issue for me:

        Write-Verbose “Incoming value can cast to guid”
        $vm = Get-VM -ComputerName $computer -Id $Name -ErrorAction SilentlyContinue
        }
        else
        {
        $vm = Get-VM -ComputerName $computer -Name $Name -ErrorAction SilentlyContinue
        }

        so calling the function like this works:
        Connect-VM -cn VMHost -VMName Test_VM -StartVM -Verbose

  12. Vince says:

    Will this function work with Windows 10?

Leave a Reply

Submit Comment

© 2016 PowerShell Magazine. All rights reserved. XHTML / CSS Valid.
Proudly designed by Theme Junkie.
%d bloggers like this: