Hyper-V Remote Management With PowerShell

You may have already read my previous two posts on Hyper-V remote management using the UI and configuring Constrained Delegation, for some people that will not be an option or is just undesirable...  Well with Windows 8 and the joy of PowerShell we have another option.  Many of the new Hyper-V PowerShell cmdlets (https://technet.microsoft.com/en-us/library/hh848559.aspx) take a computername parameter to allow for remote usage however if you are creating a virtual machine using SMB storage or if your are live migrating a VM you run into the same double hop constrained delegation problem as with the UI.  Luckily we have PowerShell remoting or WinRM remoting more specifically.

Overview_webGoing back to the example I’ve been using we have a two node Windows Server 8 Scale-Out file server cluster, two standalone Hyper-V Servers and a remote management workstation.  In this case we will be using PowerShell from the management workstation as opposed to the Hyper-V UI.  The other nice part about PowerShell remoting is that your management workstation could be of a different domain or no domain at all depending on how you choice to send the credentials.

Creating a New VM Remotely with SMB Storage – Failure

I’ll start with the error you will get if you try to create a VM remotely using SMB storage in Beta – the error message is wrong (it’s a bug and already fixed) but non the less you can see that using ComputerName parameter with the VM on an SMB share it fails.
PS C:\Windows\system32> New-VM -Name "VMOverSMB" -Path \\hv-w8-beta-smb\VirtualMachines -ComputerName 37-4611K2615L
New-VM : The Virtual Machine Management Service on host '37-4611K2615L' is not running.
At line:1 char:1
+ New-VM -Name "VMOverSMB" -Path \\hv-w8-beta-smb\VirtualMachines -ComputerName 37 ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [New-VM], VirtualizationOperationFailedException
+ FullyQualifiedErrorId : Microsoft.HyperV.PowerShell.Commands.NewVMCommand

Credential Delegation – CredSSP/Kerberos

In order to avoid the double hop and credential delegation issues we need to issue the command in the context of the Hyper-V server.  The easiest way to accomplish this is by using CredSSP and WsMan/WinRM.  By default CredSSP is disabled or more specifically the “AllowFreshCredentials” and “Allow CredSSP authentication” polcies are disabled you can either enable these via group policy or you can enabled them via the Enable-WSManCredSSP cmdlet.  I utilize group policy to enable CredSSP for my environment and have it pretty well locked down such that only systems on my domain and specific trusted domains can provide credentials and further more WinRM only listens on specific IP ranges.

Enable-WSManCredSSP -Role Client -DelegateComputer "*.hyper-v.selfhost.corp.microsoft.com"
Enable-WSManCredSSP -Role Server

It is worth stating the Kerberos delegation is also an option – it does carry with it some caveats as well.  When using Kerberos delegation you have to enable unconstrained delegation on the computer account and unconstrained delegation and constrained don’t seem to get along so it prevents Hyper-V remote UI management.

Using Credential Delegation

There are a few ways in PowerShell to use credential delegation – you can use Invoke-Command with a script block, computer name, credentials or you can create a PSSession and either pass that to InvokeCommand or enter the PSSession and execute the commands locally.  I’ll start with the PSSession example as it breaks down the concepts well.

The first step is getting the credentials that will be used on the remote machine – this is done via the Get-Credential cmdlet which will popup a standard Windows credential dialog, in my case I provide my username so I don’t have to type it in again.  The next step is to create a session via the New-PSSession cmdlet using CredSSP as my authentication and the credentials I got in step 1.  Next I enter the session with Enter-PSSession, after this command I am effectively typing on the remote computer and that’s evidenced by the computer name before my command prompt.  At this point I can create the New VM and away we go.
PS C:\> $remotingCreds = Get-Credential -Credential "hyper-v\taylorb"
PS C:\> $Session = New-PSSession -Authentication Credssp -Credential $remotingCreds -ComputerName "37-4611K2617L"
PS C:\> Enter-PSSession $Session
[37-4611K2617L]: PS C:\Users\taylorb\Documents> New-VM -Name "VMOverSMB" -Path \\hv-w8-beta-smb\VirtualMachines

Name State CPUUsage(%) MemoryAssigned(M) MemoryDemand(M) MemoryStatus Uptime Status ReplicationState
---- ----- ----------- ----------------- --------------- ------------ ------ ------ ----------------
VMOverSMB Off 0 0 0 00:00:00 Operating normally Disabled

In this example the first two steps are the same but as opposed to entering the PS Sessions I use Invoke-Command to execute a script block on the remote server.
PS C:\> $remotingCreds = Get-Credential -Credential "hyper-v\taylorb"
PS C:\> $Session = New-PSSession -Authentication Credssp -Credential $remotingCreds -ComputerName "37-4611K2615L"
PS C:\> Invoke-Command -Session $Session -ScriptBlock {New-VM -Name "VMOverSMB" -Path \\hv-w8-beta-smb\VirtualMachines}

We can also use Invoke-Command without a PSSession (though it will just create one for you and close it when it’s done).
PS C:\> Invoke-Command -Authentication Credssp -Credential (Get-Credential) -ComputerName "37-4611K2617L" -ScriptBlock {New-VM -Name "VMOverSMB" -Path \\hv-w8-beta-smb\VirtualMachines}

Or if you have unconstrained delegation enabled you can use Kerberos – also note that with Kerberos there is no need to provide credentials as the current users credentials will be delegated for you.
PS C:\> Invoke-Command -Authentication Kerberos -ComputerName "37-4611K2617L" -ScriptBlock {New-VM -Name "VMOverSMB" -Path \\hv-w8-beta-smb\VirtualMachines}

Live Storage Migration and Live Migration

These seem to be the biggest challenges for remote management – since they implicitly require a third hop I wanted to make sure there where some samples…

PS C:\> $remotingCreds = Get-Credential -Credential "hyper-v\taylorb"
PS C:\> $Session = New-PSSession -Authentication Credssp -Credential $remotingCreds -ComputerName "37-4611K2617L"

PS C:\> Invoke-Command -Session $Session -ScriptBlock {Move-VM -Name "VMOverSMB" -DestinationHost "37-4611K2615L"}

PS C:\> $remotingCreds = Get-Credential -Credential "hyper-v\taylorb"
PS C:\> $Session = New-PSSession -Authentication Credssp -Credential $remotingCreds -ComputerName "37-4611K2617L"
PS C:\> Invoke-Command -Session $Session -ScriptBlock {Move-VMStorage -VMName LocalVM -DestinationStoragePath \\hv-w8-beta-smb\VirtualMachines\LocalVM

Taylor Brown
Hyper-V Enterprise Deployment Team